Exemple #1
0
class MainWindowAction(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        super(MainWindowAction, self).__init__(parent)

        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()

        self.local_music_path = []

        self.setupUi(self)
        self.init()
        self.show()

    def init(self):
        # self.setWindowFlags(Qt.FramelessWindowHint)

        self.loadParams()

        self.playlist.setPlaybackMode(self.playlist.Loop)

        self.player.setPlaylist(self.playlist)
        self.player.play()

        exit_normal_icon_path = QUrl.fromLocalFile(EXIT_ICON_PATH)
        self.exit_normal_icon = QIcon(EXIT_ICON_PATH)

        self.exitButton.setStyleSheet(EXIT_BUTTON_STYLE)

        self.exitButton.clicked.connect(self.close)
        self.minButton.clicked.connect(self.showMinimized)
        # self.playButton.clicked.connect(self.playControl)

        self.nextButton.clicked.connect(self.playlist.next)
        self.prevButton.clicked.connect(self.playlist.previous)
        self.playButton.clicked.connect(self.controlPlay)

        self.player.currentMediaChanged.connect(self.initProgressBar)
        self.player.stateChanged.connect(self.changePlayState)
        self.player.positionChanged.connect(self.changeBar)

        self.playProgressBar.sliderReleased.connect(self.changePlayPosition)

    def loadParams(self):
        with open(CONFIG_PATH, 'r') as file:
            params = json.load(file)

            self.local_music_dirs = params['initParams']['LocalMusicDirs']
            last_playlist = params['lastPlayParams']['Playlist']

            self.initPlayList(last_playlist)

    def initPlayList(self, playlist_name):
        playlist_path = './PlayList/' + playlist_name + '.json'
        with open(playlist_path, 'r', encoding='UTF-8') as file:
            music_list = json.load(file)
            music_path_list = music_list['Songs']

        for music_path in music_path_list:
            path = QUrl.fromLocalFile(music_path)
            music = QMediaContent(path)
            self.playlist.addMedia(music)

    def controlPlay(self):
        if self.player.state() == self.player.PlayingState:
            self.player.pause()
            # self.playButton.setText("Play")
        elif self.player.state() == self.player.PausedState:
            self.player.play()
        elif self.player.state() == self.player.StoppedState:
            if self.player.mediaStatus() in [
                    self.player.LoadingMedia, self.player.LoadedMedia,
                    self.player.BufferedMedia, self.player.BufferingMedia
            ]:
                self.player.play()

    def changePlayState(self):
        if self.player.state() == self.player.PlayingState:
            self.playButton.setText("Pause")
        else:
            self.playButton.setText("Play")

    def initProgressBar(self):
        print(self.playlist.currentMedia().resources()[0].url().fileName())
        self.playProgressBar.setValue(0)

    def changeBar(self):

        if self.player.state() == self.player.PlayingState:
            duration = self.player.duration()
            if duration > 0:
                value = self.player.position() * 100 // duration
                self.playProgressBar.setValue(value)

    def changePlayPosition(self):
        self.player.pause()

        duration = self.player.duration()
        value = self.playProgressBar.value() * duration // 100

        self.player.setPosition(value)

        self.player.play()
Exemple #2
0
class Player(QWidget):
 
    fullScreenChanged = pyqtSignal(bool)
 
    def __init__(self, playlist, parent=None):
        super(Player, self).__init__(parent)
 
        self.colorDialog = None
        self.trackInfo = ""
        self.statusInfo = ""
        self.duration = 0
 
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.player.setPlaylist(self.playlist)
 
        self.player.durationChanged.connect(self.durationChanged)
        self.player.positionChanged.connect(self.positionChanged)
        self.player.metaDataChanged.connect(self.metaDataChanged)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.player.mediaStatusChanged.connect(self.statusChanged)
        self.player.bufferStatusChanged.connect(self.bufferingProgress)
        self.player.videoAvailableChanged.connect(self.videoAvailableChanged)
        self.player.error.connect(self.displayErrorMessage)
 
        self.videoWidget = VideoWidget()
        self.player.setVideoOutput(self.videoWidget)
 
        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.script_box = QPlainTextEdit()
        self.segmentList = QTreeWidget()
        self.segmentList.setSortingEnabled(True)
        #self.segmentList.setColumnCount(5)
        self.segmentList.setColumnCount(4)
        #self.segmentList.setHeaderLabels(['Product','Start','Label','Tool','Behavior'])
        self.segmentList.setHeaderLabels(['Start segment', 'End segment', 'Label', 'Event'])

        '''
        self.productTextInput = QLineEdit()
        self.startTextInput = QLineEdit()
        self.labelTextInput = QLineEdit()
        self.toolTextInput = QLineEdit()
        self.behaviorTextInput = QLineEdit()
        '''
        self.startTextInput = QLineEdit()
        self.endTextInput = QLineEdit()
        self.labelTextInput = QLineEdit()
        self.contentTextInput = QLineEdit()

        self.addBtn = QPushButton("Add")
        self.addBtn.clicked.connect(self.addSegment)

        self.saveBtn = QPushButton("Save")
        self.saveBtn.clicked.connect(self.saveSegments)

        self.slider = QSlider(Qt.Horizontal)
        self.slider.setRange(0, self.player.duration() / 1000)
 
        self.labelDuration = QLabel()
        self.slider.sliderMoved.connect(self.seek)
 
        self.labelHistogram = QLabel()
        self.labelHistogram.setText("Histogram:")
        self.histogram = HistogramWidget()
        histogramLayout = QHBoxLayout()
        histogramLayout.addWidget(self.labelHistogram)
        histogramLayout.addWidget(self.histogram, 1)
 
        self.probe = QVideoProbe()
        self.probe.videoFrameProbed.connect(self.histogram.processFrame)
        self.probe.setSource(self.player)
 
        openButton = QPushButton("Open", clicked=self.open)
        if os.path.isdir(VIDEO_DIR):
            self.open_folder(VIDEO_DIR)

        controls = PlayerControls()
        controls.setState(self.player.state())
        controls.setVolume(self.player.volume())
        controls.setMuted(controls.isMuted())
 
        controls.play.connect(self.player.play)
        controls.pause.connect(self.player.pause)
        controls.stop.connect(self.player.stop)
        controls.next.connect(self.playlist.next)
        controls.previous.connect(self.previousClicked)
        controls.changeVolume.connect(self.player.setVolume)
        controls.changeMuting.connect(self.player.setMuted)
        controls.changeRate.connect(self.player.setPlaybackRate)
        controls.stop.connect(self.videoWidget.update)
 
        self.player.stateChanged.connect(controls.setState)
        self.player.volumeChanged.connect(controls.setVolume)
        self.player.mutedChanged.connect(controls.setMuted)

        #self.segmentButton = QPushButton("Segment")
        #self.segmentButton.clicked.connect(self.createNewSegment)
        self.startSegmentButton = QPushButton("Start Segment")
        self.startSegmentButton.clicked.connect(self.createNewStartSegment)
        # self.segmentButton.setCheckable(True)

        self.endSegmentButton = QPushButton("End Segment")
        self.endSegmentButton.clicked.connect(self.createNewEndSegment)

        #self.fullScreenButton = QPushButton("FullScreen")
        #self.fullScreenButton.setCheckable(True)
 
        self.colorButton = QPushButton("Color Options...")
        self.colorButton.setEnabled(False)
        self.colorButton.clicked.connect(self.showColorDialog)
 
        displayLayout = QHBoxLayout()
        # videoLayout = QVBoxLayout()
        # videoLayout.addWidget(self.videoWidget)
        # videoLayout.addWidget(self.script_box)
        
        displayLayout.addWidget(self.videoWidget, 3)

        editLayout = QVBoxLayout()
        editLayout.addWidget(self.playlistView, 2)
        #editLayout.addWidget(self.script_box, 4)
        editLayout.addWidget(self.segmentList, 3)
        segmentInputLayout = QHBoxLayout()
        '''
        segmentInputLayout.addWidget(self.productTextInput)
        segmentInputLayout.addWidget(self.startTextInput)
        segmentInputLayout.addWidget(self.labelTextInput)
        segmentInputLayout.addWidget(self.toolTextInput)
        segmentInputLayout.addWidget(self.behaviorTextInput)
        '''
        segmentInputLayout.addWidget(self.startTextInput)
        segmentInputLayout.addWidget(self.endTextInput)
        segmentInputLayout.addWidget(self.labelTextInput)
        segmentInputLayout.addWidget(self.contentTextInput)

        editLayout.addLayout(segmentInputLayout,1)

        displayLayout.addLayout(editLayout, 2)
 
        controlLayout = QHBoxLayout()
        controlLayout.setContentsMargins(0, 0, 0, 0)
        controlLayout.addWidget(openButton)
        controlLayout.addStretch(1)
        controlLayout.addWidget(controls)
        controlLayout.addStretch(1)
        #controlLayout.addWidget(self.segmentButton)
        controlLayout.addWidget(self.startSegmentButton)
        controlLayout.addWidget(self.endSegmentButton)
        controlLayout.addWidget(self.addBtn)
        controlLayout.addWidget(self.saveBtn)
        #controlLayout.addWidget(self.fullScreenButton)
        # controlLayout.addWidget(self.colorButton)
 
        layout = QVBoxLayout()
        layout.addLayout(displayLayout, 2)
        hLayout = QHBoxLayout()
        hLayout.addWidget(self.slider)
        hLayout.addWidget(self.labelDuration)
        layout.addLayout(hLayout)
        layout.addLayout(controlLayout)
        # layout.addLayout(histogramLayout)
 
        self.setLayout(layout)
 
        if not self.player.isAvailable():
            QMessageBox.warning(self, "Service not available",
                    "The QMediaPlayer object does not have a valid service.\n"
                    "Please check the media service plugins are installed.")
 
            controls.setEnabled(False)
            self.playlistView.setEnabled(False)
            openButton.setEnabled(False)
            self.colorButton.setEnabled(False)
            #self.fullScreenButton.setEnabled(False)
 
        self.metaDataChanged()
 
        self.addToPlaylist(playlist)
    
    def open(self):
        fileNames, _ = QFileDialog.getOpenFileNames(self, "Open Files")
        self.addToPlaylist(fileNames)

    def open_folder(self, folder_path):
        fileNames = [folder_path+x for x in os.listdir(folder_path) if x.endswith('.mp4')]
        self.addToPlaylist(fileNames)
 
    def addToPlaylist(self, fileNames):
        for name in fileNames:
            fileInfo = QFileInfo(name)
            if fileInfo.exists():
                url = QUrl.fromLocalFile(fileInfo.absoluteFilePath())
                if fileInfo.suffix().lower() == 'm3u':
                    self.playlist.load(url)
                else:
                    self.playlist.addMedia(QMediaContent(url))
            else:
                url = QUrl(name)
                if url.isValid():
                    self.playlist.addMedia(QMediaContent(url))

    def addSegment(self):
        item = TreeWidgetItem(self.segmentList)
        '''
        item.setText(0, self.productTextInput.text())
        item.setText(1, self.startTextInput.text())
        item.setText(2, self.labelTextInput.text())
        item.setText(3, self.toolTextInput.text())
        item.setText(4, self.behaviorTextInput.text())
        '''

        item.setText(0, self.startTextInput.text())
        item.setText(1, self.endTextInput.text())
        item.setText(2, self.labelTextInput.text())
        item.setText(3, self.contentTextInput.text())

        item.setFlags(item.flags() | Qt.ItemIsEditable)
        self.segmentList.addTopLevelItem(item)
        self.segmentList.sortByColumn(0, Qt.AscendingOrder)

        self.clear_input_boxes()
        self.player.play()
    
    def saveSegments(self):
        itemCnt = self.segmentList.topLevelItemCount()
        colCnt = self.segmentList.columnCount()
        save_dict = {'segments':[]}

        for i in range(itemCnt):
            item = self.segmentList.topLevelItem(i)
            temp_data = []
            for j in range(colCnt):
                temp_data.append(item.text(j))
            #temp_dict = {'product': temp_data[0], 'start': temp_data[1], 'label': temp_data[2], 'tool': temp_data[3], 'behavior': temp_data[4]}

            if len(temp_data[0]) > 0 and len(temp_data[1]) > 0 and (':' in temp_data[0]) and (':' in temp_data[1]):

                start_interval_seconds = 0
                j = 0
                while j < len(temp_data[0].split(':')):
                    start_interval_seconds += (int(temp_data[0].split(':')[- 1 - j]) * (60 ** j))
                    j += 1

                end_interval_seconds = 0
                j = 0
                while j < len(temp_data[1].split(':')):
                    end_interval_seconds += (int(temp_data[1].split(':')[- 1 - j]) * (60 ** j))
                    j += 1

            else:
                start_interval_seconds = ''
                end_interval_seconds = ''

            temp_dict = {'start_segment': start_interval_seconds, 'end_segment': end_interval_seconds, 'label': temp_data[2], 'event': temp_data[3]}
            save_dict['segments'].append(temp_dict)
        
        import json
        file_name = self.playlist.currentMedia().canonicalUrl().fileName()
        with open(SEGMENT_DIR+file_name.replace('.mp4','.json'),'w') as file:
            json.dump(save_dict, file)

    def durationChanged(self, duration):
        duration /= 1000
 
        self.duration = duration
        self.slider.setMaximum(duration)
 
    def positionChanged(self, progress):
        progress /= 1000

        if not self.slider.isSliderDown():
            self.slider.setValue(progress)
 
        self.updateDurationInfo(progress)
 
    def metaDataChanged(self):
        if self.player.isMetaDataAvailable():
            self.setTrackInfo("%s - %s" % (
                    self.player.metaData(QMediaMetaData.AlbumArtist),
                    self.player.metaData(QMediaMetaData.Title)))
 
    def previousClicked(self):
        # Go to the previous track if we are within the first 5 seconds of
        # playback.  Otherwise, seek to the beginning.
        if self.player.position() <= 5000:
            self.playlist.previous()
        else:
            self.player.setPosition(0)
    
    def clear_input_boxes(self):
        '''
        self.productTextInput.clear()
        self.startTextInput.clear()
        self.labelTextInput.clear()
        self.toolTextInput.clear()
        self.behaviorTextInput.clear()
        '''
        self.startTextInput.clear()
        self.endTextInput.clear()
        self.labelTextInput.clear()
        self.contentTextInput.clear()


    def jump(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()
            file_name = self.playlist.currentMedia().canonicalUrl().fileName()
            '''
            script_file_name = file_name.replace('.mp4','.txt')
            if os.path.isfile(SCRIPT_DIR+script_file_name):
                text=open(SCRIPT_DIR+script_file_name).read()
                self.script_box.setPlainText(text)
            '''

            segment_file_path = SEGMENT_DIR + file_name.replace('.mp4','.json')
            json_dict = self.open_json(segment_file_path)
            self.clear_input_boxes()
            self.segmentList.clear()
            for segment in json_dict["segments"]:
                item = TreeWidgetItem(self.segmentList)
                '''
                item.setText(0, segment['product'])
                item.setText(1, str(segment['start']))
                item.setText(2, segment['label'])
                item.setText(3, segment['tool'])
                item.setText(4, segment['behavior'])
                '''
                item.setText(0, segment['start_segment'])
                item.setText(1, segment['end_segment'])
                item.setText(2, segment['label'])
                item.setText(3, segment['content'])

                item.setFlags(item.flags() | Qt.ItemIsEditable)
                self.segmentList.addTopLevelItem(item)
                
            
            
            # print([str(x.text()) for x in self.segmentList.currentItem()])

    def open_json(self, file_path):
        import json
        try:
            with open(file_path, 'r') as file:
                json_dict = json.loads(file.read())
        except:
            json_dict = {"segments":[]}
            # json_dict = {"segments":[{"product":"Sorry","start":"File not found.","label":"","tool":"","behavior":""}]}
        return json_dict
    
    def playlistPositionChanged(self, position):
        self.playlistView.setCurrentIndex(
                self.playlistModel.index(position, 0))
 
    def seek(self, seconds):
        self.player.setPosition(seconds * 1000)
 
    def statusChanged(self, status):
        self.handleCursor(status)
 
        if status == QMediaPlayer.LoadingMedia:
            self.setStatusInfo("Loading...")
        elif status == QMediaPlayer.StalledMedia:
            self.setStatusInfo("Media Stalled")
        elif status == QMediaPlayer.EndOfMedia:
            QApplication.alert(self)
        elif status == QMediaPlayer.InvalidMedia:
            self.displayErrorMessage()
        else:
            self.setStatusInfo("")
 
    def handleCursor(self, status):
        if status in (QMediaPlayer.LoadingMedia, QMediaPlayer.BufferingMedia, QMediaPlayer.StalledMedia):
            self.setCursor(Qt.BusyCursor)
        else:
            self.unsetCursor()
 
    def bufferingProgress(self, progress):
        self.setStatusInfo("Buffering %d%" % progress)
 
    def videoAvailableChanged(self, available):
        '''
        if available:
            self.fullScreenButton.clicked.connect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.connect(
                    self.fullScreenButton.setChecked)
 
            if self.fullScreenButton.isChecked():
                self.videoWidget.setFullScreen(True)
        else:
            self.fullScreenButton.clicked.disconnect(
                    self.videoWidget.setFullScreen)
            self.videoWidget.fullScreenChanged.disconnect(
                    self.fullScreenButton.setChecked)
 
            self.videoWidget.setFullScreen(False)

        '''
        self.colorButton.setEnabled(available)
 
    def setTrackInfo(self, info):
        self.trackInfo = info
 
        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)
 
    def setStatusInfo(self, info):
        self.statusInfo = info
 
        if self.statusInfo != "":
            self.setWindowTitle("%s | %s" % (self.trackInfo, self.statusInfo))
        else:
            self.setWindowTitle(self.trackInfo)
 
    def displayErrorMessage(self):
        self.setStatusInfo(self.player.errorString())
 
    def updateDurationInfo(self, currentInfo):
        duration = self.duration
        if currentInfo or duration:
            currentTime = QTime((currentInfo/3600)%60, (currentInfo/60)%60,
                    currentInfo%60, (currentInfo*1000)%1000)
            totalTime = QTime((duration/3600)%60, (duration/60)%60,
                    duration%60, (duration*1000)%1000);
 
            format = 'hh:mm:ss' if duration > 3600 else 'mm:ss'
            tStr = currentTime.toString(format) + " / " + totalTime.toString(format)
        else:
            tStr = ""
 
        self.labelDuration.setText(tStr)
    '''
    def createNewSegment(self):
        self.startTextInput.setText(str(int(self.player.position()/1000)))
    '''

    def createNewStartSegment(self):
        seconds = int(self.player.position()/1000)
        self.startTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format(
            math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60))

    def createNewEndSegment(self):
        seconds = int(self.player.position() / 1000)
        self.endTextInput.setText("{:02d}".format(math.floor(seconds / 3600)) + ':' + "{:02d}".format(
            math.floor((seconds / 60)) - math.floor(seconds / 3600) * 60) + ':' + "{:02d}".format(seconds % 60))
        self.player.pause()

    def showColorDialog(self):
        if self.colorDialog is None:
            brightnessSlider = QSlider(Qt.Horizontal)
            brightnessSlider.setRange(-100, 100)
            brightnessSlider.setValue(self.videoWidget.brightness())
            brightnessSlider.sliderMoved.connect(
                    self.videoWidget.setBrightness)
            self.videoWidget.brightnessChanged.connect(
                    brightnessSlider.setValue)
 
            contrastSlider = QSlider(Qt.Horizontal)
            contrastSlider.setRange(-100, 100)
            contrastSlider.setValue(self.videoWidget.contrast())
            contrastSlider.sliderMoved.connect(self.videoWidget.setContrast)
            self.videoWidget.contrastChanged.connect(contrastSlider.setValue)
 
            hueSlider = QSlider(Qt.Horizontal)
            hueSlider.setRange(-100, 100)
            hueSlider.setValue(self.videoWidget.hue())
            hueSlider.sliderMoved.connect(self.videoWidget.setHue)
            self.videoWidget.hueChanged.connect(hueSlider.setValue)
 
            saturationSlider = QSlider(Qt.Horizontal)
            saturationSlider.setRange(-100, 100)
            saturationSlider.setValue(self.videoWidget.saturation())
            saturationSlider.sliderMoved.connect(
                    self.videoWidget.setSaturation)
            self.videoWidget.saturationChanged.connect(
                    saturationSlider.setValue)
 
            layout = QFormLayout()
            layout.addRow("Brightness", brightnessSlider)
            layout.addRow("Contrast", contrastSlider)
            layout.addRow("Hue", hueSlider)
            layout.addRow("Saturation", saturationSlider)
 
            button = QPushButton("Close")
            layout.addRow(button)
 
            self.colorDialog = QDialog(self)
            self.colorDialog.setWindowTitle("Color Options")
            self.colorDialog.setLayout(layout)
 
            button.clicked.connect(self.colorDialog.close)
 
        self.colorDialog.show()
Exemple #3
0
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 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())
Exemple #5
0
class MediaPlayerTab(GalacteekTab):
    statePlaying = QMediaPlayer.PlayingState
    statePaused = QMediaPlayer.PausedState
    stateStopped = QMediaPlayer.StoppedState

    def __init__(self, *args, **kw):
        super(MediaPlayerTab, self).__init__(*args, **kw)

        self.playlistIpfsPath = None
        self.playlist = QMediaPlaylist()
        self.model = ListModel(self.playlist)

        self.playlistsMenu = QMenu(self)
        self.playlistsMenu.triggered.connect(self.onPlaylistsMenu)

        self.pListWidget = QWidget(self)
        self.uipList = ui_mediaplaylist.Ui_MediaPlaylist()
        self.uipList.setupUi(self.pListWidget)
        self.uipList.savePlaylistButton.clicked.connect(self.onSavePlaylist)
        self.uipList.savePlaylistButton.setEnabled(False)
        self.uipList.loadPlaylistButton.setPopupMode(QToolButton.InstantPopup)
        self.uipList.loadPlaylistButton.setMenu(self.playlistsMenu)

        self.clipMenu = QMenu(self)
        self.copyPathAction = QAction(getIconIpfsIce(),
                                      iCopyPlaylistPath(),
                                      self,
                                      triggered=self.onCopyPlaylistPath)
        self.loadPathAction = QAction(getIconIpfsIce(),
                                      iLoadPlaylistFromPath(),
                                      self,
                                      triggered=self.onLoadPlaylistPath)

        self.copyPathAction.setEnabled(False)
        self.clipMenu.addAction(self.copyPathAction)
        self.clipMenu.addAction(self.loadPathAction)

        self.uipList.clipPlaylistButton.setPopupMode(QToolButton.InstantPopup)
        self.uipList.clipPlaylistButton.setMenu(self.clipMenu)
        self.uipList.clearButton.clicked.connect(self.onClearPlaylist)

        self.uipList.nextButton.clicked.connect(self.onPlaylistNext)
        self.uipList.previousButton.clicked.connect(self.onPlaylistPrevious)
        self.uipList.nextButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipForward))
        self.uipList.previousButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaSkipBackward))

        self.pListView = self.uipList.listView
        self.pListView.mousePressEvent = self.playlistMousePressEvent
        self.pListView.setModel(self.model)
        self.pListView.setResizeMode(QListView.Adjust)
        self.pListView.setMinimumWidth(self.width() / 2)

        self.duration = None
        self.playerState = None
        self.player = QMediaPlayer(self)
        self.player.setPlaylist(self.playlist)

        self.videoWidget = MPlayerVideoWidget(self.player, self)
        self.useUpdates(True)
        self.videoWidget.setSizePolicy(QSizePolicy.Expanding,
                                       QSizePolicy.Expanding)

        self.player.setVideoOutput(self.videoWidget)

        self.player.error.connect(self.onError)
        self.player.stateChanged.connect(self.onStateChanged)
        self.player.metaDataChanged.connect(self.onMetaData)
        self.player.durationChanged.connect(self.mediaDurationChanged)
        self.player.positionChanged.connect(self.mediaPositionChanged)
        self.player.videoAvailableChanged.connect(self.onVideoAvailable)

        self.pListView.activated.connect(self.onListActivated)
        self.playlist.currentIndexChanged.connect(self.playlistPositionChanged)
        self.playlist.currentMediaChanged.connect(self.playlistMediaChanged)
        self.playlist.mediaInserted.connect(self.playlistMediaInserted)
        self.playlist.mediaRemoved.connect(self.playlistMediaRemoved)

        self.togglePList = QToolButton(self)
        self.togglePList.setIcon(self.style().standardIcon(
            QStyle.SP_ArrowRight))
        self.togglePList.setFixedSize(32, 128)
        self.togglePList.clicked.connect(self.onTogglePlaylist)

        self.clipboardMediaItem = None
        self.clipboardButton = QToolButton(clicked=self.onClipboardClicked)
        self.clipboardButton.setIcon(getIconClipboard())
        self.clipboardButton.setEnabled(False)
        self.clipboardButton.setToolTip('Load media from clipboard')

        self.pinButton = QToolButton(clicked=self.onPinMediaClicked)
        self.pinButton.setIcon(getIcon('pin.png'))

        self.processClipboardItem(self.app.clipTracker.current, force=True)
        self.app.clipTracker.currentItemChanged.connect(self.onClipItemChange)

        self.playButton = QToolButton(clicked=self.onPlayClicked)
        self.playButton.setIcon(self.style().standardIcon(QStyle.SP_MediaPlay))

        self.pauseButton = QToolButton(clicked=self.onPauseClicked)
        self.pauseButton.setIcon(self.style().standardIcon(
            QStyle.SP_MediaPause))
        self.pauseButton.setEnabled(False)

        self.stopButton = QToolButton(clicked=self.onStopClicked)
        self.stopButton.setIcon(self.style().standardIcon(QStyle.SP_MediaStop))
        self.stopButton.setEnabled(False)

        self.fullscreenButton = QToolButton(clicked=self.onFullScreen)
        self.fullscreenButton.setIcon(getIcon('fullscreen.png'))
        self.fullscreenButton.setToolTip(iFullScreen())

        self.seekSlider = QSlider(Qt.Horizontal, sliderMoved=self.onSeek)
        self.seekSlider.sliderReleased.connect(self.onSliderReleased)
        self.seekSlider.setObjectName('mediaPlayerSlider')
        self.durationLabel = QLabel()

        vLayout = QVBoxLayout()
        hLayoutControls = QHBoxLayout()
        hLayoutControls.setContentsMargins(0, 0, 0, 0)
        hLayoutControls.addWidget(self.clipboardButton)
        hLayoutControls.addWidget(self.pinButton)
        hLayoutControls.addWidget(self.playButton)
        hLayoutControls.addWidget(self.pauseButton)
        hLayoutControls.addWidget(self.stopButton)
        hLayoutControls.addWidget(self.seekSlider)
        hLayoutControls.addWidget(self.durationLabel)
        hLayoutControls.addWidget(self.fullscreenButton)
        vLayout.addWidget(self.videoWidget)
        vLayout.addLayout(hLayoutControls)

        hLayout = QHBoxLayout()
        hLayout.addLayout(vLayout)
        hLayout.addWidget(self.pListWidget)
        hLayout.addWidget(self.togglePList)

        self.pListWidget.hide()

        self.vLayout.addLayout(hLayout)
        self.update()
        self.videoWidget.changeFocus()

    @property
    def isPlaying(self):
        return self.playerState == self.statePlaying

    @property
    def isPaused(self):
        return self.playerState == self.statePaused

    @property
    def isStopped(self):
        return self.playerState == self.stateStopped

    def useUpdates(self, updates=True):
        # Enable widget updates or not on the video widget
        self.videoWidget.setUpdatesEnabled(updates)

    def update(self):
        self.app.task(self.updatePlaylistsMenu)

    def onFullScreen(self):
        self.videoWidget.viewFullScreen(True)

    def onClearPlaylist(self):
        self.copyPathAction.setEnabled(False)
        self.player.stop()
        self.clearPlaylist()

    def onLoadPlaylistPath(self):
        current = self.app.clipTracker.getCurrent()
        if current:
            self.app.task(self.loadPlaylistFromPath, current.path)

    def onCopyPlaylistPath(self):
        if self.playlistIpfsPath:
            self.app.setClipboardText(self.playlistIpfsPath)

    def onPinMediaClicked(self):
        currentMedia = self.playlist.currentMedia()
        if currentMedia.isNull():
            return messageBox(iNoMediaInPlaylist())

        ensure(self.pinMedia(currentMedia))

    @ipfsOp
    async def pinMedia(self, ipfsop, media):
        mediaUrl = qurlPercentDecode(media.canonicalUrl())
        path = IPFSPath(mediaUrl, autoCidConv=True)

        if path.valid:
            await ipfsop.ctx.pin(str(path), qname='mediaplayer')

    @ipfsOp
    async def updatePlaylistsMenu(self, ipfsop):
        currentList = [
            action.text() for action in self.playlistsMenu.actions()
        ]
        listing = await ipfsop.filesList(self.profile.pathPlaylists)
        for entry in listing:
            if entry['Name'] in currentList:
                continue
            action = QAction(entry['Name'], self)
            action.setData(entry)
            self.playlistsMenu.addAction(action)

    def playlistShowContextMenu(self, event):
        selModel = self.pListView.selectionModel()
        idx = self.pListView.indexAt(event.pos())
        if not idx.isValid():
            return

        path = self.model.data(idx)
        if path:
            selModel.reset()
            selModel.select(idx, QItemSelectionModel.Select)

            menu = QMenu(self)
            menu.addAction(getIcon('clear-all.png'), iPlaylistRemoveMedia(),
                           functools.partial(self.onRemoveMediaFromIndex, idx))
            menu.exec_(event.globalPos())

    def onRemoveMediaFromIndex(self, idx):
        self.playlist.removeMedia(idx.row())

    def playlistMousePressEvent(self, event):
        if event.button() == Qt.RightButton:
            self.pListView.selectionModel().reset()
            self.playlistShowContextMenu(event)
        else:
            if not self.pListView.indexAt(event.pos()).isValid():
                self.deselectPlaylistItems()

            QListView.mousePressEvent(self.pListView, event)

    def onPlaylistsMenu(self, action):
        entry = action.data()
        self.app.task(self.loadPlaylistFromPath, joinIpfs(entry['Hash']))

    def onSavePlaylist(self):
        paths = self.playlistGetPaths()
        listName = inputText(title=iPlaylistName(), label=iPlaylistName())
        if not listName:
            return

        obj = JSONPlaylistV1(listName=listName, itemPaths=paths)
        self.app.task(self.savePlaylist, obj, listName)

    @ipfsOp
    async def savePlaylist(self, ipfsop, obj, name):
        objPath = os.path.join(self.profile.pathPlaylists, name)
        exists = await ipfsop.filesStat(objPath)

        if exists:
            await ipfsop.filesRm(objPath)

        ent = await ipfsop.client.core.add_json(obj.root)

        if ent:
            await ipfsop.filesLinkFp(ent, objPath)
            self.playlistIpfsPath = joinIpfs(ent['Hash'])
            self.copyPathAction.setEnabled(True)

        self.update()

    @ipfsOp
    async def loadPlaylistFromPath(self, ipfsop, path):
        try:
            obj = await ipfsop.jsonLoad(path)
        except Exception:
            return messageBox(iCannotLoadPlaylist())

        if obj is None:
            return messageBox(iCannotLoadPlaylist())

        try:
            # Assume v1 format for now, when the format evolves we'll just
            # use json validation
            pList = JSONPlaylistV1(data=obj)
            self.clearPlaylist()

            for item in pList.items():
                self.queueFromPath(item['path'])

            self.playlistIpfsPath = path
            self.copyPathAction.setEnabled(True)
        except Exception:
            return messageBox(iCannotLoadPlaylist())

    def playlistMediaInserted(self, start, end):
        self.uipList.savePlaylistButton.setEnabled(
            self.playlist.mediaCount() > 0)

    def playlistMediaRemoved(self, start, end):
        self.uipList.savePlaylistButton.setEnabled(
            self.playlist.mediaCount() > 0)

        self.model.modelReset.emit()

    def playlistGetPaths(self):
        return [u.path() for u in self.playlistGetUrls()]

    def playlistGetUrls(self):
        urls = []
        for idx in range(0, self.playlist.mediaCount()):
            media = self.playlist.media(idx)
            urls.append(media.canonicalUrl())
        return urls

    def onClipItemChange(self, item):
        self.processClipboardItem(item)

    def processClipboardItem(self, item, force=False):
        if not item:
            return

        def analyzeMimeType(cItem):
            if cItem.mimeCategory in ['audio', 'video', 'image']:
                self.clipboardMediaItem = cItem
                self.clipboardButton.setEnabled(True)
                self.clipboardButton.setToolTip(cItem.path)
            else:
                self.clipboardButton.setEnabled(False)
                self.clipboardButton.setToolTip(iClipboardEmpty())

        if force:
            analyzeMimeType(item)
        else:
            item.mimeTypeAvailable.connect(lambda mType: analyzeMimeType(item))

    def onClipboardClicked(self):
        if self.clipboardMediaItem:
            self.playFromPath(self.clipboardMediaItem.path)
        else:
            messageBox('Not a multimedia resource')

    def onSliderReleased(self):
        pass

    def onPlaylistNext(self):
        self.playlist.next()

    def onPlaylistPrevious(self):
        self.playlist.previous()

    def onPlayClicked(self):
        self.player.play()

    def onPauseClicked(self):
        if self.isPlaying:
            self.player.pause()
        elif self.isPaused:
            self.player.play()

    def onStopClicked(self):
        self.player.stop()
        self.player.setPosition(0)
        self.seekSlider.setValue(0)
        self.seekSlider.setRange(0, 0)

    def onSeek(self, seconds):
        if self.player.isSeekable():
            self.player.setPosition(seconds * 1000)

    def onTogglePlaylist(self):
        self.pListWidget.setVisible(self.pListWidget.isHidden())

    def onError(self, error):
        messageBox(iPlayerError(error))

    def onStateChanged(self, state):
        self.playerState = state
        self.updateControls(state)

    def updateControls(self, state):
        if self.isStopped:
            self.stopButton.setEnabled(False)
            self.pauseButton.setEnabled(False)
            self.playButton.setEnabled(True)
            self.seekSlider.setEnabled(False)
            self.duration = None
        elif self.isPlaying:
            self.seekSlider.setRange(0, self.player.duration() / 1000)
            self.seekSlider.setEnabled(True)
            self.pauseButton.setEnabled(True)
            self.playButton.setEnabled(False)
            self.stopButton.setEnabled(True)

    def onListActivated(self, index):
        if index.isValid():
            self.playlist.setCurrentIndex(index.row())
            self.player.play()

    def onMetaData(self):
        # Unfinished
        if self.player.isMetaDataAvailable():
            availableKeys = self.player.availableMetaData()

            for key in availableKeys:
                self.player.metaData(key)

    def playFromUrl(self, url, mediaName=None):
        if self.isPlaying:
            self.player.stop()

        cUrls = self.playlistGetUrls()
        for u in cUrls:
            if u.toString() == url.toString():
                return messageBox(iAlreadyInPlaylist())

        media = QMediaContent(url)
        if self.playlist.addMedia(media):
            count = self.model.rowCount()
            if count > 0:
                self.playlist.setCurrentIndex(count - 1)

        self.player.play()

    def playFromPath(self, path, mediaName=None):
        mediaUrl = self.app.subUrl(path)
        self.playFromUrl(mediaUrl)

    def queueFromPath(self, path, playLast=False, mediaName=None):
        mediaUrl = self.app.subUrl(path)
        self.playlist.addMedia(QMediaContent(mediaUrl))

        if playLast:
            count = self.playlist.mediaCount()

            if count > 0:
                self.player.stop()
                self.playlist.setCurrentIndex(count - 1)
                self.player.play()

    def clearPlaylist(self):
        self.playlist.clear()
        self.pListView.reset()

    def playlistPositionChanged(self, position):
        self.pListView.setCurrentIndex(self.model.index(position, 0))

    def deselectPlaylistItems(self):
        self.pListView.selectionModel().reset()

    def playlistMediaChanged(self, media):
        selModel = self.pListView.selectionModel()

        self.deselectPlaylistItems()

        self.model.modelReset.emit()
        idx = self.model.index(self.playlist.currentIndex(), 0)
        if idx.isValid():
            selModel.select(idx, QItemSelectionModel.Select)

    def onVideoAvailable(self, available):
        if available:
            if self.isPlaying:
                self.useUpdates(False)
            elif self.isStopped or self.isPaused:
                self.useUpdates(True)
        else:
            self.useUpdates(True)

    def mediaDurationChanged(self, duration):
        self.duration = duration / 1000
        self.seekSlider.setMaximum(self.duration)

    def mediaPositionChanged(self, progress):
        progress /= 1000

        if self.duration:
            cTime = durationConvert(progress)
            tTime = durationConvert(self.duration)
            self.durationLabel.setText('{0} ({1})'.format(
                cTime.toString(), tTime.toString()))

        if not self.seekSlider.isSliderDown():
            self.seekSlider.setValue(progress)

    async def onClose(self):
        self.player.stop()
        self.player.setMedia(QMediaContent(None))
        return True

    def playerAvailable(self):
        return mediaPlayerAvailable(player=self.player)
class DirectoryPlaylist(Playlist):

    def __init__(self, parent=None):
        super(DirectoryPlaylist, self).__init__(parent)

        self._directories_urls = set()
        self._added_song_urls = set()
        self._tracks = []

        self._qPlaylist = QMediaPlaylist(parent)
        self._qPlaylist.mediaAboutToBeInserted.connect(
            lambda s, e: self.mediaAboutToBeInserted.emit(s, e))
        self._qPlaylist.mediaInserted.connect(
            lambda s, e: self.mediaInserted.emit(s, e))
        self._qPlaylist.mediaAboutToBeRemoved.connect(
            lambda s, e: self.mediaAboutToBeRemoved.emit(s, e))
        self._qPlaylist.mediaRemoved.connect(
            lambda s, e: self.mediaRemoved.emit(s, e))
        self._qPlaylist.mediaChanged.connect(
            lambda s, e: self.mediaChanged.emit(s, e))

    def songs(self):
        return self._tracks

    def albums_data(self):
        return self._albumsData

    def artists_data(self):
        return self._artistsData

    def __traverse_directory(self, url, func):
        songs = []
        for root, dirs, files in os.walk(url):
                for file in files:
                    abs_path = os.path.join(root, file)
                    song = func(abs_path)
                    if song:
                        songs.append(song)
        return songs

    def is_empty(self):
        return not self._tracks

    def add_song(self, abs_path):
        if abs_path not in self._added_song_urls:
            url = QtCore.QUrl.fromLocalFile(abs_path)
            song = MediaFactory.create_media(abs_path)
            if not song:
                return None
            added = self._qPlaylist.addMedia(QMediaContent(url))
            if not added:
                return None

            self._tracks.append(song)
            self._added_song_urls.add(abs_path)
            return song

    def remove_song(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        if self._qPlaylist.currentIndex() == row:
            if row < self.song_count():
                self._qPlaylist.setCurrentIndex(row + 1)
            else:
                self._qPlaylist.setCurrentIndex(row - 1)

        removed = self._qPlaylist.removeMedia(row)
        if not removed:
            return

        del self._tracks[row]
        url = self.get_song_abs_path(row)
        self._added_song_urls.discard(url)

    def add_directory(self, directory):
        if directory not in self._directories_urls:
            self._directories_urls.add(directory)
            songs = self.__traverse_directory(directory, self.add_song)
            return songs
        return None

    def add_directories(self, directories):
        songs = []
        for directory in directories:
            if directory not in self._directories_urls:
                current_songs = self.add_directory(directory)
                if current_songs:
                    songs.extend(current_songs)
        return songs

    def remove_directory(self, directory):
        if directory not in self._directories_urls:
            return False  # raise Error

        self.__traverse_directory(directory, self.remove_song)

    def setCurrentIndex(self, index):
        self._qPlaylist.setCurrentIndex(index)

    def getCurrentIndex(self):
        return self._qPlaylist.currentIndex()

    def getCurrentSong(self):
        return self._qPlaylist.currentMedia()

    def clear(self):
        self._tracks = []
        self._directories_urls = set()
        self._added_song_urls = set()
        self._qPlaylist.clear()

    @property
    def internalPlaylist(self):
        return self._qPlaylist

    def song_count(self):
        return len(self._tracks)

    def get_song_metadata(self, row, tags):
        if row < 0 or row > self.song_count() - 1:
            return None
        if not isinstance(tags, list):
            tags = [tags]
        return self._tracks[row].get_values(tags)

    def get_song(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        return self._tracks[row]

    def get_song_title(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None
        k, v = self.get_song_metadata(row, 'title').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_album(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None
        k, v = self.get_song_metadata(row, 'album').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_artist(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        k, v = self.get_song_metadata(row, 'artist').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_genre(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        k, v = self.get_song_metadata(row, 'genre').popitem()
        try:
            return v[0]
        except IndexError:
            return None

    def get_song_abs_path(self, row):
        if row < 0 or row > self.song_count() - 1:
            return None

        return self._tracks[row].get_abs_path()

    def getDirectories(self):
        return self._directories_urls

    def getAddedSongUrls(self):
        return self._added_song_urls

    def __str__(self):
        return str(self._tracks)

    def __eq__(self, other):
        return (isinstance(other, self.__class__) and
                self._directories_urls == other._directories_urls and
                self._added_song_urls == other._added_song_urls)
Exemple #7
0
class App(QMainWindow):
    def __init__(self):
        super().__init__()
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.playlist.setPlaybackMode(QMediaPlaylist.Sequential)
        self.title = 'JPR Reader GUI version2'
        self.left = 50
        self.top = 100
        self.width = 1200
        self.height = 800
        self.fileReady = False
        self.tableRow = 5
        self.tableCol = 15
        self.row = 2
        self.audiolist = []
        self.configFile = ".//configurationFile.xlsx"
        self.dict = {
            'num': None,
            'partner': None,
            'parcel': None,
            'exception': None,
            'box': None
        }
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        # menu
        menubar = self.menuBar()
        filemenu = menubar.addMenu('File')
        fileAct = QAction('Open File', self)
        fileAct.setShortcut('Ctrl+O')
        filemenu.addAction(fileAct)
        fileAct.triggered.connect(self.openFileNameDialog)

        # status_bar
        self.statusbar = self.statusBar()

        # tabs
        self.tabs = QTabWidget()
        self.tab1 = QWidget(self)
        self.tab2 = QWidget(self)
        self.tabs.addTab(self.tab1, "조작")
        self.tabs.addTab(self.tab2, "설정")
        self.setCentralWidget(self.tabs)

        # tab1 gui
        self.ButtonGroupBox = self.createButtonGroupBox()
        self.createLogTable()
        self.tab1.layout = QVBoxLayout()
        self.tab1.layout.addWidget(self.ButtonGroupBox)
        self.tab1.layout.addWidget(self.logTable)
        self.tab1.setLayout(self.tab1.layout)

        # tab2 gui
        self.explanation = QLabel()
        self.explanation.setText("""<<< JPR reader 설정 테이블 >>>    
            이곳에서 JPR reader가 읽어주는 항목과 아이템을 설정할 수 있습니다.
            항목과 아이템의 설정 방법은 셀을 더블 클릭한 후 이름을 입력하는 방식으로진행됩니다.
            그 후 떠오른 파일 탐색기에서 지정할 mp3파일을 선택해 주세요.
            설정의 확인은 셀의 색으로 확인 가능합니다. 지정이 완료된 항목은 노란색, 아이템은 하늘색으로 표시됩니다.
            지정이 되지 않은 셀은 빨간색으로 표시됩니다. 행과 열 버튼으로 테이블의 크기를 조절할 수 있으며
            초기화시 모든 설정은 사라지며 테이블은 5by5로 초기화 됩니다.

            <<<주의사항>>>
            1. 첫번째 열은 반드시 항목을 입력해 주세요.
            2. 입력되는 이름은 엑셀파일에서 표현된 명칭과 완벽히 일치해야 합니다.(엔터나 스페이스, 오타 주의!)
            3. 초기화를 누르면 처음부터 모든 항목과 아이템을 지정해야 합니다.
            4. 엑셀 파일의 ()나 /을 통해 구분한 아이템은 따로 입력해 주세요.
            5. 사용하는 엑셀파일의 구조를 유지해 주세요. 변경시 프로그램의 수정이 필요할 수 있습니다.(예: '박스'항목은 항상 있을 것으로 간주됩니다.)

            제작자 정보: 김현우([email protected])""")
        self.explanation.setAlignment(Qt.AlignCenter)
        self.createConfigTable()
        self.createHorizontalButtons2()
        self.tab2.layout = QVBoxLayout()
        self.tab2.layout.addWidget(self.explanation)
        self.tab2.layout.addWidget(self.configTable)
        self.tab2.layout.addWidget(self.horizontalButtons2)
        self.tab2.setLayout(self.tab2.layout)

        # Show widget
        self.show()

    def openFileNameDialog(self):
        fileName, _ = QFileDialog.getOpenFileName(self, "Open file", "",
                                                  "All Files (*)")
        if not fileName:
            self.statusbar.showMessage('Fail to load file...')

        else:
            self.wb = load_workbook(fileName.strip())
            self.ws = self.wb.active
            self.fileReady = True
            self.row = 2
            self.statusbar.showMessage('succeed to load file...')
            self.logTable.clear()

            # set logTable's horizontal header
            self.logTable.setHorizontalHeaderItem(0, QTableWidgetItem("포장순번"))
            self.logTable.setHorizontalHeaderItem(1, QTableWidgetItem("거래처명"))
            self.logTable.setHorizontalHeaderItem(2, QTableWidgetItem("배송센터"))
            self.logTable.setHorizontalHeaderItem(3, QTableWidgetItem("특이사항"))
            self.logTable.setHorizontalHeaderItem(4, QTableWidgetItem("박스"))

            # initialize dictionary
            self.dict = {
                'num': None,
                'partner': None,
                'parcel': None,
                'exception': None,
                'box': None
            }
            col = 6
            num = 0
            header = str(self.ws.cell(row=1, column=col + 1).value).strip()
            while header != 'None':
                self.dict[header] = None
                col = col + 1
                num = num + 1
                header = str(self.ws.cell(row=1, column=col + 1).value).strip()

            self.tableCol = 5 + num
            self.logTable.setColumnCount(self.tableCol)

            for c in range(5, self.tableCol):
                self.logTable.setHorizontalHeaderItem(
                    c, QTableWidgetItem(list(self.dict.keys())[c]))

    def createButtonGroupBox(self):
        buttonGroupBox = QGroupBox("Controller")
        vLayout = QVBoxLayout()

        pre_button = QPushButton('w', self)
        pre_button.clicked.connect(self.pre_click)
        pre_button.setIcon(QIcon('.\\img\\up-arrow.png'))
        pre_button.setIconSize(QSize(600, 100))
        pre_button.setShortcut('w')
        vLayout.addWidget(pre_button)

        hBottensWidget = self.createHButtons()
        vLayout.addWidget(hBottensWidget)

        next_button = QPushButton('x', self)
        next_button.clicked.connect(self.next_click)
        next_button.setIcon(QIcon('.\\img\\down-arrow.png'))
        next_button.setIconSize(QSize(600, 100))
        next_button.setShortcut('x')
        vLayout.addWidget(next_button)

        buttonGroupBox.setLayout(vLayout)

        return buttonGroupBox

    def createHButtons(self):
        hBottensWidget = QWidget()
        hLayout = QHBoxLayout()

        back_button = QPushButton('a', self)
        back_button.clicked.connect(self.back_click)
        back_button.setIcon(QIcon('.\\img\\left-arrow.png'))
        back_button.setIconSize(QSize(200, 150))
        back_button.setShortcut('a')
        hLayout.addWidget(back_button)

        cur_button = QPushButton('s', self)
        cur_button.clicked.connect(self.cur_click)
        cur_button.setIcon(QIcon('.\\img\\reload.png'))
        cur_button.setIconSize(QSize(200, 150))
        cur_button.setShortcut('s')
        hLayout.addWidget(cur_button)

        forward_button = QPushButton('d', self)
        forward_button.clicked.connect(self.forward_click)
        forward_button.setIcon(QIcon('.\\img\\right-arrow.png'))
        forward_button.setIconSize(QSize(200, 150))
        forward_button.setShortcut('d')
        hLayout.addWidget(forward_button)

        hBottensWidget.setLayout(hLayout)

        return hBottensWidget

    def createHorizontalButtons2(self):
        self.horizontalButtons2 = QGroupBox("설정 변경")
        layout = QHBoxLayout()

        plusRowButton = QPushButton('행+', self)
        plusRowButton.clicked.connect(self.plus_row)
        layout.addWidget(plusRowButton)

        plusColButton = QPushButton('열+', self)
        plusColButton.clicked.connect(self.plus_col)
        layout.addWidget(plusColButton)

        init_button = QPushButton('초기화', self)
        init_button.clicked.connect(self.initialize)
        layout.addWidget(init_button)

        self.horizontalButtons2.setLayout(layout)

    def createLogTable(self):
        # Create table
        self.logTable = QTableWidget()
        self.logTable.setRowCount(self.tableRow)
        self.logTable.setColumnCount(self.tableCol)
        self.logTable.move(0, 0)

    def createConfigTable(self):
        self.configTable = QTableWidget()

        try:
            # load configurationFile
            cwb = load_workbook(self.configFile.strip())
        except:
            # message box
            string = "설정파일을 불러올 수 없습니다."
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)

        else:
            # Get matadata
            cws = cwb.active
            self.crow = cws.cell(row=1, column=1).value
            self.ccol = cws.cell(row=1, column=2).value

            # Configure table
            self.configTable.setRowCount(self.crow)
            self.configTable.setColumnCount(self.ccol)
            self.configTable.move(0, 0)

            # Load data from configFile
            for i in range(self.crow):
                for j in range(self.ccol):
                    item = str(cws.cell(row=i + 2, column=j + 1).value).strip()
                    if item == 'None':
                        item = ''
                    self.configTable.setItem(i, j, QTableWidgetItem(item))

            # check if files exist
            arr = listdir('./audio_clips')
            for row in range(self.crow):
                for col in range(self.ccol):
                    # if 박스(0,0)
                    if row == 0 and col == 0:
                        continue

                    # reset backgound color
                    self.configTable.item(row,
                                          col).setBackground(QColor(255, 0, 0))

                    # if file exist, change background color
                    fname = str(row) + '_' + str(col) + '.mp3'
                    if fname in arr:
                        if row == 0:
                            self.configTable.item(row, col).setBackground(
                                QColor(255, 255, 0))
                        else:
                            self.configTable.item(row, col).setBackground(
                                QColor(0, 255, 255))

            # 박스(0,0)
            self.configTable.setItem(0, 0, QTableWidgetItem('박스'))
            self.configTable.item(0, 0).setBackground(QColor(255, 255, 255))

            # link the callback function
            self.configTable.itemDoubleClicked.connect(self.item_doubleClicked)
            self.configTable.itemChanged.connect(self.item_changed)

    def setLogTable(self):
        # shifting other rows
        for r in range(1, self.tableRow):
            for c in range(self.tableCol):
                try:
                    self.logTable.item(r,
                                       c).setBackground(QColor(255, 255, 255))
                    self.logTable.setItem(r - 1, c,
                                          self.logTable.item(r, c).clone())
                except:
                    pass

        # set current row
        for idx, key in enumerate(list(self.dict.keys())):
            if type(self.dict[key]) is list:
                self.logTable.setItem(
                    self.tableRow - 1, idx,
                    QTableWidgetItem(' '.join(self.dict[key])))
                self.logTable.item(self.tableRow - 1,
                                   idx).setBackground(QColor(255, 255, 0))
            else:
                self.logTable.setItem(self.tableRow - 1, idx,
                                      QTableWidgetItem(self.dict[key]))
                self.logTable.item(self.tableRow - 1,
                                   idx).setBackground(QColor(255, 255, 0))

    def read(self):

        # 포장 순번
        self.dict['num'] = str(self.ws.cell(row=self.row,
                                            column=3).value[2:]).strip()

        # 거래처명
        self.dict['partner'] = str(self.ws.cell(row=self.row,
                                                column=5).value).strip()

        # 배송센터
        self.dict['parcel'] = str(self.ws.cell(row=self.row,
                                               column=4).value).strip()

        # 특이사항
        self.dict['exception'] = str(
            self.ws.cell(row=self.row, column=6).value).strip()

        # 박스
        self.dict['box'] = str(self.ws.cell(row=self.row,
                                            column=2).value).strip()

        # left things
        print(len(self.dict))
        for i in range(5, len(self.dict)):
            header = str(self.ws.cell(row=1, column=i + 2).value).strip()
            self.dict[header] = str(
                self.ws.cell(row=self.row, column=i + 2).value).strip()
            self.parsing(header, self.dict[header])

        print(self.dict)
        self.setLogTable()

    def parsing(self, key, val):
        if val == 'None' or val == '':
            self.dict[key] = None

        else:
            if '(' in val or '/' in val:
                arr = re.split('[(/]', val)
                for i in range(len(arr)):
                    if ')' in arr[i]:
                        arr[i] = arr[i][:arr[i].index(')')]
                    arr[i] = arr[i].strip()
                self.dict[key] = arr

            else:
                self.dict[key] = val

    def itemFromKeyVal(self, key, val):
        items = self.configTable.findItems(val, Qt.MatchExactly)
        if len(items) <= 0:
            # Error
            string = '(' + key + ', ' + val + ') ' + '아이템을 찾을 수 없습니다.'
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
        else:
            for item in items:
                if self.configTable.item(0, item.column()).data(0) == key:
                    return item

    def load_audiolist(self):
        for key, val in self.dict.items():

            # 포장순번
            if key == 'num':
                for i in range(len(self.dict['num'])):
                    self.audiolist.append('_' + val[i])

                # beep
                self.audiolist.append('_beep')

            # 택배발송
            elif key == 'parcel':
                if val == '택배발송':
                    self.audiolist.append('_택배발송')

                    # beep
                    self.audiolist.append('_beep')

            # 박스
            elif key == 'box':
                item = self.itemFromKeyVal('박스', val)
                if item:
                    self.audiolist.append(
                        str(item.row()) + '_' + str(item.column()))

                    # beep
                    self.audiolist.append('_beep')

            elif key in ['partner', 'exception']:
                pass

            # general case
            else:
                # The case(val == None) will be ignored
                if val == None:
                    pass

                # when val is list
                elif type(val) == list:
                    for idx, eachVal in enumerate(val):
                        item = self.itemFromKeyVal(key, eachVal)
                        if item:
                            if idx == 0:
                                self.audiolist.append(
                                    '0_' + str(item.column()))  # key
                            self.audiolist.append(
                                str(item.row()) + '_' +
                                str(item.column()))  # val

                    # beep
                    self.audiolist.append('_beep')

                # when val is not list
                else:
                    item = self.itemFromKeyVal(key, val)
                    if item:
                        if val == '1' or key == val:
                            self.audiolist.append('0_' +
                                                  str(item.column()))  # key
                        else:
                            self.audiolist.append('0_' +
                                                  str(item.column()))  # key
                            self.audiolist.append(
                                str(item.row()) + '_' +
                                str(item.column()))  # val

                        # beep
                        self.audiolist.append('_beep')

        print(self.audiolist)

    def speak(self):
        self.playlist.clear()
        for clip in self.audiolist:
            url = QUrl.fromLocalFile('./audio_clips/' + clip + '.mp3')
            #print(url)
            self.playlist.addMedia(QMediaContent(url))
        self.player.setPlaylist(self.playlist)
        self.player.play()

#----------------------- Control button callback -----------------------#

    @pyqtSlot()
    def pre_click(self):
        if not self.fileReady:
            self.cur_click()

        else:
            if self.row == 2:
                self.statusbar.showMessage("Can't be previous.")
            else:
                self.row -= 1

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def cur_click(self):
        if not self.fileReady:
            string = '파일이 준비되어 있지 않습니다.'
            QMessageBox.question(self, '경고', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
            self.openFileNameDialog()
        else:

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def next_click(self):
        if not self.fileReady:
            self.cur_click()

        else:
            if self.row == self.ws.max_row:
                self.statusbar.showMessage("It's over.")
            else:
                self.row += 1

            self.dict = self.dict.fromkeys(self.dict, None)
            del self.audiolist[:]
            self.read()
            self.load_audiolist()
            self.speak()

    @pyqtSlot()
    def back_click(self):
        if self.playlist.mediaCount() == 0:
            self.cur_click()
        elif self.playlist.mediaCount() != 0:
            p = re.compile('.+_beep.+')
            cnt = 0
            for i in range(self.playlist.mediaCount()):
                # if it's start point, start at here
                if self.playlist.currentIndex() == 0:
                    break
                # go backward
                self.playlist.setCurrentIndex(self.playlist.previousIndex(1))

                # start at previous beep point
                if p.match(str(self.playlist.currentMedia().canonicalUrl())):
                    cnt = cnt + 1
                    if cnt == 2:
                        print(self.playlist.currentIndex())
                        if self.player.state() == QMediaPlayer.StoppedState:
                            self.player.play()
                        break

    @pyqtSlot()
    def forward_click(self):
        if self.playlist.mediaCount() == 0:
            self.cur_click()
        elif self.playlist.mediaCount() != 0:
            p = re.compile('.+_beep.+')
            for i in range(self.playlist.mediaCount()):
                # don't go further from end point
                if self.playlist.currentIndex() < 0:
                    break

                # go forward
                self.playlist.setCurrentIndex(self.playlist.nextIndex(1))

                # start at next beep point
                if p.match(str(self.playlist.currentMedia().canonicalUrl())):
                    print(self.playlist.currentIndex())
                    break

#----------------------- Configuration button callback -----------------------#

    @pyqtSlot()
    def plus_row(self):
        # change configTable
        self.crow = self.crow + 1
        self.configTable.setRowCount(self.crow)

        # fill the generated cell
        self.configTable.itemChanged.disconnect(self.item_changed)
        for col in range(self.ccol):
            self.configTable.setItem(self.crow - 1, col, QTableWidgetItem(''))
            self.configTable.item(self.crow - 1,
                                  col).setBackground(QColor(255, 0, 0))
        self.configTable.itemChanged.connect(self.item_changed)

    @pyqtSlot()
    def plus_col(self):
        # change configTable
        self.ccol = self.ccol + 1
        self.configTable.setColumnCount(self.ccol)

        # fill the generated cell
        self.configTable.itemChanged.disconnect(self.item_changed)
        for row in range(self.crow):
            self.configTable.setItem(row, self.ccol - 1, QTableWidgetItem(''))
            self.configTable.item(row, self.ccol - 1).setBackground(
                QColor(255, 0, 0))
        self.configTable.itemChanged.connect(self.item_changed)

    @pyqtSlot()
    def initialize(self):
        # remove configurable audio files
        arr = listdir('./audio_clips')
        p = re.compile('_.+')
        for file in arr:
            if p.match(file):
                continue
            remove('./audio_clips/' + file)

        # init configTable
        self.configTable.itemChanged.disconnect(self.item_changed)  # lock

        self.configTable.clear()
        self.crow = 5
        self.ccol = 5
        self.configTable.setRowCount(self.crow)
        self.configTable.setColumnCount(self.ccol)

        # reset configTable item
        for row in range(self.crow):
            for col in range(self.ccol):
                self.configTable.setItem(row, col, QTableWidgetItem(''))
                self.configTable.item(row,
                                      col).setBackground(QColor(255, 0, 0))
        self.configTable.setItem(0, 0, QTableWidgetItem('박스'))
        self.configTable.item(0, 0).setBackground(QColor(255, 255, 255))

        self.configTable.itemChanged.connect(self.item_changed)  # unlock

        # init configFile
        self.update_configFile()


#---------------------- ConfigTable signal callback ------------------------#

    def item_doubleClicked(self, item):
        self.previousItem = item.data(0)
        print(self.previousItem)

    def update_configFile(self):
        cwb_w = Workbook(write_only=True)
        cws_w = cwb_w.create_sheet()

        cws_w.append([self.crow, self.ccol])

        for row in range(self.crow):
            itemList = []
            for col in range(self.ccol):
                itemList.append(self.configTable.item(row, col).data(0))
            cws_w.append(itemList)
        try:
            cwb_w.save(self.configFile)
        except:
            string = """설정파일이 열려있을 수 있습니다.
                            설정파일을 닫은 후에 다시 시도하세요."""
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)

    def item_changed(self, item):
        self.configTable.itemChanged.disconnect(self.item_changed)  # lock

        if item.row() == 0 and item.column() == 0:
            string = "이 항목은 바꿀 수 없습니다."
            QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                 QMessageBox.Ok)
            self.configTable.setItem(item.row(), item.column(),
                                     QTableWidgetItem(self.previousItem))

        else:
            # get file name
            fileName, _ = QFileDialog.getOpenFileName(self, "Open file", "",
                                                      "All Files (*)")

            # count the number of key that has same name
            keys = self.configTable.findItems(item.data(0), Qt.MatchExactly)
            kcnt = 0
            for key in keys:
                if key.row() == 0:
                    kcnt = kcnt + 1

            # count the number of atribute that has same name
            atributes = self.configTable.findItems(item.data(0),
                                                   Qt.MatchExactly)
            acnt = 0
            for atribute in atributes:
                if atribute.row() == 0:
                    pass
                elif atribute.column() == item.column():
                    acnt = acnt + 1

            # change is accepted only in case of uniqueness and existence and it is not 박스(0,0)
            if kcnt >= 2:
                string = "항목명이 같을 수 없습니다."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

            elif acnt >= 2:
                string = "같은 항목에 같은 이름의 아이템을 둘 수 없습니다."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

            elif fileName:
                # copy file to local dir
                dst = "./audio_clips./" + str(item.row()) + '_' + str(
                    item.column()) + '.mp3'
                copyfile(fileName, dst)

                # change cell color
                if item.row() == 0:
                    self.configTable.item(item.row(),
                                          item.column()).setBackground(
                                              QColor(255, 255, 0))
                else:
                    self.configTable.item(item.row(),
                                          item.column()).setBackground(
                                              QColor(0, 255, 255))

                # update configFile
                self.update_configFile()

            else:
                string = "선택이 취소됨."
                QMessageBox.question(self, 'Error', string, QMessageBox.Ok,
                                     QMessageBox.Ok)
                self.configTable.setItem(item.row(), item.column(),
                                         QTableWidgetItem(self.previousItem))

        self.configTable.itemChanged.connect(self.item_changed)  # unlock
Exemple #8
0
class MusicApp(QMainWindow):
    def __init__(self):
        super().__init__()
        self.player = QMediaPlayer()
        self.playlist = QMediaPlaylist()
        self.title = 'GestureTunes - player'
        self.left = 300
        self.top = 300
        self.width = 600
        self.height = 340
        self.volume_initial_value = 60
        self.model = QStandardItemModel(0, 1)
        self.song_list = QtWidgets.QTableView()
        self.play_btn = QPushButton('播放')
        self.media_controls = QHBoxLayout()
        # 共享变量
        self.image_to_show = None
        self.rec_res = {
            "set": False,
            "used": True,
            "direction": None,
            "fingers": 0
        }
        # 摄像头窗口
        self.widget = QWidget()
        self.widget.move(1000, 200)
        self.widget.resize(300, 200)
        self.widget.setWindowTitle("GestureTunes - gesture panel")  # 窗口标题
        self.videoFrame = QLabel('正在打开摄像头,请稍等...')
        video_area = QVBoxLayout()
        self.widget.setLayout(video_area)
        video_area.addWidget(self.videoFrame)
        self.widget.show()
        # self.widget.setWindowFlags(QtCore.Qt.WindowStaysOnTopHint)
        # 定时器
        self.timer = QTimer()
        self.timer.setInterval(20)
        self.timer.start()
        self.timer.timeout.connect(self.show_image)
        self.have_song = False
        self.volume_slider = QSlider(Qt.Horizontal, self)
        self.volume_slider.setTracking(True)
        # 播放模式
        self.play_style = '列表循环'
        self.single_img = QIcon('pics/single.png')
        self.loop_img = QIcon('pics/loop.png')
        self.play_style_btn = QPushButton()
        self.play_style_btn.setIcon(self.loop_img)
        self.play_tip = ''

        self.playlist.setPlaybackMode(QMediaPlaylist.Loop)

        # 初始化界面
        self.init_ui()

    def init_ui(self):
        # Add file menu
        menubar = self.menuBar()
        file_menu = menubar.addMenu('文件')

        fileAct = QAction('打开文件', self)
        folderAct = QAction('打开文件夹', self)

        file_menu.addAction(fileAct)
        file_menu.addAction(folderAct)

        fileAct.triggered.connect(self.open_file)
        folderAct.triggered.connect(self.add_files)

        self.add_listener()

        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)
        self.show()

    def add_listener(self):
        wid = QWidget(self)
        self.setCentralWidget(wid)

        # 播放控件
        self.volume_slider = QSlider(Qt.Horizontal, self)
        self.volume_slider.setFocusPolicy(Qt.NoFocus)
        self.volume_slider.valueChanged[int].connect(self.change_volume)
        self.volume_slider.setValue(self.volume_initial_value)
        open_btn = QPushButton('打开...')
        prev_btn = QPushButton('上一首')
        next_btn = QPushButton('下一首')
        # 显示播放列表
        self.set_play_list()
        self.song_list.setSelectionBehavior(
            QtWidgets.QAbstractItemView.SelectRows)
        self.song_list.setShowGrid(False)
        self.song_list.setTextElideMode(QtCore.Qt.ElideLeft)

        # 按钮的layout
        control_area = QVBoxLayout()  # centralWidget
        self.media_controls = QHBoxLayout()

        # 将播放控件添加到layout
        self.media_controls.addWidget(open_btn)
        self.media_controls.addWidget(prev_btn)
        self.media_controls.addWidget(self.play_btn)
        self.media_controls.addWidget(next_btn)
        self.media_controls.addWidget(self.play_style_btn)
        self.media_controls.addWidget(self.volume_slider)

        # 将layout添加到界面中
        control_area.addWidget(self.song_list)
        control_area.addLayout(self.media_controls)
        wid.setLayout(control_area)

        # 设置监听
        self.play_btn.clicked.connect(self.start_or_stop)
        open_btn.clicked.connect(self.add_files)
        prev_btn.clicked.connect(self.prev)
        next_btn.clicked.connect(self.next)
        self.song_list.doubleClicked.connect(self.change_song)
        self.play_style_btn.clicked.connect(self.change_play_style)

        self.statusBar()
        self.playlist.currentMediaChanged.connect(self.song_changed)

    def set_play_list(self):
        self.model.clear()
        self.song_list.horizontalHeader().hide()
        # self.song_list.verticalHeader().hide()
        # QHeaderView()
        self.song_list.setModel(self.model)  # 把数据添加至QtableView中
        self.song_list.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)
        self.song_list.setEditTriggers(
            QAbstractItemView.NoEditTriggers)  # 设置不可编辑单元格
        if self.playlist.mediaCount():  # 添加数据
            for index in range(self.playlist.mediaCount()):
                self.model.appendRow([  # 添加一行数据
                    QStandardItem(
                        self.playlist.media(index).canonicalUrl().fileName())
                ])
            self.song_list.selectRow(0)

    def open_file(self):
        song = QFileDialog.getOpenFileName(self, "打开文件", "~",
                                           "音频文件 (*.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()
            else:
                self.playlist.addMedia(QMediaContent(url))
        self.set_play_list()
        self.have_song = True

    def add_files(self):
        if self.playlist.mediaCount() != 0:
            self.playlist.clear()
        self.folder_iterator()
        self.player.setPlaylist(self.playlist)
        self.player.playlist().setCurrentIndex(0)
        self.song_list.selectRow(0)
        self.set_play_list()
        self.player.pause()
        self.play_tip = "暂停:" + self.playlist.currentMedia().canonicalUrl(
        ).fileName()
        self.statusBar().showMessage(self.play_tip + " - " + self.play_style)
        self.have_song = True

    def folder_iterator(self):
        folder_chosen = QFileDialog.getExistingDirectory(self, '打开文件夹', '~')
        if folder_chosen is not None:
            it = QDirIterator(folder_chosen)
            it.next()
            while it.hasNext():
                if (not it.fileInfo().isDir()) and it.filePath() != '.':
                    f_info = it.fileInfo()
                    if f_info.suffix() in ('mp3', 'ogg', 'wav', 'm4a'):
                        self.playlist.addMedia(
                            QMediaContent(QUrl.fromLocalFile(it.filePath())))
                it.next()
            if (not it.fileInfo().isDir()) and it.filePath() != '.':
                f_info = it.fileInfo()
                if f_info.suffix() in ('mp3', 'ogg', 'wav', 'm4a'):
                    self.playlist.addMedia(
                        QMediaContent(QUrl.fromLocalFile(it.filePath())))

    def start_or_stop(self):
        print(self.player.state())
        if self.playlist.mediaCount() == 0:
            self.open_file()
        else:
            if self.player.state() == QMediaPlayer.PlayingState or \
                    (self.player.state() == QMediaPlayer.PlayingState and self.play_btn.text() == '暂停'):
                self.player.pause()
                self.play_btn.setText('播放')
                self.play_tip = "暂停:" + self.playlist.currentMedia(
                ).canonicalUrl().fileName()
            elif self.player.state() == QMediaPlayer.PausedState or \
                    (self.player.state() == QMediaPlayer.PlayingState and self.play_btn.text() == '播放'):
                self.player.play()
                self.play_btn.setText('暂停')
                self.play_tip = "正在播放:" + self.playlist.currentMedia(
                ).canonicalUrl().fileName()
            self.statusBar().showMessage(self.play_tip + " - " +
                                         self.play_style)

    def change_volume(self, value):
        self.player.setVolume(value)

    def volume_up(self):
        volume = self.player.volume(
        ) + 10 if self.player.volume() + 10 <= 100 else 100
        self.player.setVolume(volume)
        self.volume_slider.setTracking(True)
        self.volume_slider.setValue(volume)

    def volume_down(self):
        volume = self.player.volume(
        ) - 10 if self.player.volume() - 10 >= 0 else 0
        self.player.setVolume(volume)
        self.volume_slider.setTracking(True)
        self.volume_slider.setValue(volume)

    def prev(self):
        if self.playlist.mediaCount() == 0:
            self.open_file()
        elif self.playlist.mediaCount() != 0:
            self.player.playlist().previous()

    def shuffle(self):
        self.playlist.shuffle()

    def next(self):
        if self.playlist.mediaCount() == 0:
            self.open_file()
        elif self.playlist.mediaCount() != 0:
            self.player.playlist().next()

    def song_changed(self, media):
        if not media.isNull():
            url = media.canonicalUrl()
            self.play_tip = "正在播放:" + url.fileName()
            self.statusBar().showMessage(self.play_tip + " - " +
                                         self.play_style)
            self.song_list.selectRow(self.playlist.currentIndex())

    def change_song(self):
        index = self.song_list.currentIndex().row()  # 获取双击所在行
        self.playlist.setCurrentIndex(index)

    def change_play_style(self):
        if self.playlist.playbackMode() == QMediaPlaylist.Loop:
            self.playlist.setPlaybackMode(QMediaPlaylist.CurrentItemInLoop)
            self.play_style = "单曲循环"
            self.play_style_btn.setIcon(self.single_img)
        elif self.playlist.playbackMode() == QMediaPlaylist.CurrentItemInLoop:
            self.playlist.setPlaybackMode(QMediaPlaylist.Loop)
            self.play_style = "列表循环"
            self.play_style_btn.setIcon(self.loop_img)
        self.statusBar().showMessage(self.play_tip + " - " + self.play_style)

    def convert_image(self, frame):
        if len(frame.shape) == 2:  # 若是灰度图则转为三通道
            frame = cv2.cvtColor(frame, cv2.COLOR_GRAY2BGR)

        rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # 将BGR转为RGB
        rgb_image = np.asanyarray(rgb_image)
        label_image = QImage(rgb_image.data, rgb_image.shape[1],
                             rgb_image.shape[0],
                             QImage.Format_RGB888)  # 转化为QImage
        self.image_to_show = QPixmap(label_image)

    def show_image(self):
        if self.image_to_show is not None:
            self.videoFrame.setPixmap(self.image_to_show)
        if self.rec_res['set'] and not self.rec_res['used']:
            final_direction = self.rec_res['direction']
            final_fingers = self.rec_res['fingers']
            if final_fingers == 3:
                self.start_or_stop()
                self.rec_res['used'] = True
                return
            if final_fingers == 5:
                self.change_play_style()
                self.rec_res['used'] = True
                return
            if final_direction is not None and final_direction != 'NOT_FOUND':
                if final_direction == "RIGHT":
                    self.next()
                    self.rec_res['used'] = True
                if final_direction == "LEFT":
                    self.prev()
                    self.rec_res['used'] = True
                if final_direction == "UP":
                    self.volume_up()
                    self.rec_res['used'] = True
                if final_direction == "DOWN":
                    self.volume_down()
                    self.rec_res['used'] = True

    def set_rec_res(self, res):
        self.rec_res = res