Пример #1
0
 def captureFrame(settings: QSettings,
                  source: str,
                  frametime: str,
                  thumbsize: QSize = None,
                  external: bool = False) -> QPixmap:
     if thumbsize is None:
         thumbsize = VideoService.config.thumbnails['INDEX']
     capres = QPixmap()
     img = QTemporaryFile(os.path.join(QDir.tempPath(), 'XXXXXX.jpg'))
     if img.open():
         imagecap = img.fileName()
         cmd = VideoService.findBackends(settings).ffmpeg
         tsize = '{0:d}x{1:d}'.format(thumbsize.width(), thumbsize.height())
         args = '-hide_banner -ss {frametime} -i "{source}" -vframes 1 -s {tsize} -y "{imagecap}"'.format(
             **locals())
         proc = VideoService.initProc()
         if proc.state() == QProcess.NotRunning:
             proc.start(cmd, shlex.split(args))
             proc.waitForFinished(-1)
             if proc.exitStatus() == QProcess.NormalExit and proc.exitCode(
             ) == 0:
                 capres = QPixmap(imagecap, 'JPG')
             if external:
                 painter = QPainter(capres)
                 painter.drawPixmap(0, 0,
                                    QPixmap(':/images/external.png', 'PNG'))
                 painter.end()
     img.remove()
     return capres
Пример #2
0
 def capture(source: str,
             frametime: str,
             thumbsize: ThumbSize = ThumbSize.INDEX,
             external: bool = False) -> QPixmap:
     capres = QPixmap()
     img = QTemporaryFile(os.path.join(QDir.tempPath(), 'XXXXXX.jpg'))
     if img.open():
         imagecap = img.fileName()
         size = thumbsize.value
         backend, _ = VideoService.initBackends()
         args = '-hide_banner -ss %s -i "%s" -vframes 1 -s %ix%i -v 16 -y "%s"' % (
             frametime, source, size.width(), size.height(), imagecap)
         proc = VideoService.initProc()
         proc.setProcessChannelMode(QProcess.MergedChannels)
         if proc.state() == QProcess.NotRunning:
             if os.getenv('DEBUG', False):
                 logging.getLogger(__name__).info('"%s %s"' %
                                                  (backend, args))
             proc.start(backend, shlex.split(args))
             proc.waitForFinished(-1)
             if proc.exitStatus() == QProcess.NormalExit and proc.exitCode(
             ) == 0:
                 capres = QPixmap(imagecap, 'JPG')
             if external:
                 painter = QPainter(capres)
                 painter.drawPixmap(0, 0,
                                    QPixmap(':/images/external.png', 'PNG'))
                 painter.end()
     img.remove()
     return capres
Пример #3
0
 def testJoin(self, file1: str, file2: str) -> bool:
     result = False
     self.logger.info('attempting to test joining of "%s" + "%s"' % (file1, file2))
     try:
         # 1. check audio + video codecs
         file1_codecs = self.codecs(file1)
         file2_codecs = self.codecs(file2)
         if file1_codecs != file2_codecs:
             self.logger.info('join test failed for %s and %s: codecs mismatched' % (file1, file2))
             self.lastError = '<p>The audio + video format of this media file is not the same as the files ' + \
                              'already in your clip index.</p>' + \
                              '<div align="center">Current files are <b>{0}</b> (video) and ' + \
                              '<b>{1}</b> (audio)<br/>' + \
                              'Failed media is <b>{2}</b> (video) and <b>{3}</b> (audio)</div>'
             self.lastError = self.lastError.format(file1_codecs[0], file1_codecs[1],
                                                    file2_codecs[0], file2_codecs[1])
             return result
         # 2. check frame sizes
         size1 = self.framesize(file1)
         size2 = self.framesize(file2)
         if size1 != size2:
             self.logger.info('join test failed for %s and %s: frame size mismatched' % (file1, file2))
             self.lastError = '<p>The frame size of this media file is not the same as the files already in ' + \
                              'your clip index.</p>' + \
                              '<div align="center">Current media clips are <b>{0}x{1}</b>' + \
                              '<br/>Failed media file is <b>{2}x{3}</b></div>'
             self.lastError = self.lastError.format(size1.width(), size1.height(), size2.width(), size2.height())
             return result
         # 2. generate temporary file handles
         _, ext = os.path.splitext(file1)
         file1_cut = QTemporaryFile(os.path.join(QDir.tempPath(), 'XXXXXX%s' % ext))
         file2_cut = QTemporaryFile(os.path.join(QDir.tempPath(), 'XXXXXX%s' % ext))
         final_join = QTemporaryFile(os.path.join(QDir.tempPath(), 'XXXXXX%s' % ext))
         # 3. produce 2 seconds long clips from input files for join test
         if file1_cut.open() and file2_cut.open() and final_join.open():
             result1 = self.cut(file1, file1_cut.fileName(), '00:00:00.000', '00:00:04.00', False)
             result2 = self.cut(file2, file2_cut.fileName(), '00:00:00.000', '00:00:04.00', False)
             if result1 and result2:
                 # 4. attempt join of temp 2 second clips
                 result = self.join([file1_cut.fileName(), file2_cut.fileName()], final_join.fileName(), False)
         file1_cut.remove()
         file2_cut.remove()
         final_join.remove()
     except:
         self.logger.exception('Exception in VideoService.testJoin', exc_info=True)
         result = False
     return result
Пример #4
0
class TranslatorWidget(QWidget, Ui_TranslatorWidget):
    """
    Class implementing the translator widget.
    """
    def __init__(self, plugin, translator, parent=None):
        """
        Constructor
        
        @param plugin reference to the plugin object (TranslatorPlugin)
        @param translator reference to the translator object (Translator)
        @param parent reference to the parent widget (QWidget)
        """
        super(TranslatorWidget, self).__init__(parent)
        self.setupUi(self)

        self.__plugin = plugin
        self.__translator = translator

        self.__languages = TranslatorLanguagesDb(self)

        self.__translatorRequest = None
        self.__translationEngine = None

        self.__mediaPlayer = None
        self.__mediaFile = None

        audioAvailable = (MULTIMEDIA_AVAILABLE
                          and bool(QMediaPlayer.hasSupport("audio/mpeg")))
        self.pronounceOrigButton.setVisible(audioAvailable)
        self.pronounceTransButton.setVisible(audioAvailable)

        self.pronounceOrigButton.setIcon(
            self.__translator.getAppIcon("pronounce.png"))
        self.pronounceTransButton.setIcon(
            self.__translator.getAppIcon("pronounce.png"))
        self.swapButton.setIcon(self.__translator.getAppIcon("swap.png"))
        self.translateButton.setIcon(
            self.__translator.getAppIcon("translate.png"))
        self.clearButton.setIcon(UI.PixmapCache.getIcon("editDelete.png"))
        self.preferencesButton.setIcon(UI.PixmapCache.getIcon("configure.png"))

        self.translateButton.setEnabled(False)
        self.clearButton.setEnabled(False)
        self.pronounceOrigButton.setEnabled(False)
        self.pronounceTransButton.setEnabled(False)

        selectedEngine = self.__plugin.getPreferences("SelectedEngine")

        self.__updateEngines()
        engineIndex = self.engineComboBox.findData(selectedEngine)
        self.engineComboBox.setCurrentIndex(engineIndex)
        self.__engineComboBoxCurrentIndexChanged(engineIndex)

        self.engineComboBox.currentIndexChanged.connect(
            self.__engineComboBoxCurrentIndexChanged)
        self.__plugin.updateLanguages.connect(self.__updateLanguages)

    def __updateLanguages(self):
        """
        Private slot to update the language combo boxes.
        """
        self.__ensureTranslationEngineReady()
        if self.__translationEngine is not None:
            supportedCodes = self.__translationEngine.supportedLanguages()
            enabledCodes = self.__plugin.getPreferences("EnabledLanguages")

            # 1. save current selections
            origLanguage = self.origLanguageComboBox.itemData(
                self.origLanguageComboBox.currentIndex())

            # 2. reload the original language combo box
            self.origLanguageComboBox.blockSignals(True)
            self.origLanguageComboBox.clear()
            for code in enabledCodes:
                if code in supportedCodes:
                    language = self.__languages.getLanguage(code)
                    if language:
                        icon = self.__languages.getLanguageIcon(code)
                        self.origLanguageComboBox.addItem(icon, language, code)
            self.origLanguageComboBox.model().sort(0)
            origIndex = self.origLanguageComboBox.findData(origLanguage)
            if origIndex == -1:
                origIndex = 0
            self.origLanguageComboBox.blockSignals(False)
            self.origLanguageComboBox.setCurrentIndex(origIndex)

    def __updateEngines(self):
        """
        Private slot to update the engines combo box.
        """
        currentEngine = self.engineComboBox.itemData(
            self.engineComboBox.currentIndex())
        self.engineComboBox.clear()
        for engineName in TranslatorEngines.supportedEngineNames():
            icon = TranslatorEngines.getEngineIcon(engineName)
            self.engineComboBox.addItem(
                icon, TranslatorEngines.engineDisplayName(engineName),
                engineName)
        self.engineComboBox.model().sort(0)
        self.engineComboBox.setCurrentIndex(
            self.engineComboBox.findData(currentEngine))

    def __originalLanguage(self):
        """
        Private method to return the code of the selected original language.
        
        @return code of the original language (string)
        """
        return self.origLanguageComboBox.itemData(
            self.origLanguageComboBox.currentIndex())

    def __translationLanguage(self):
        """
        Private method to return the code of the selected translation language.
        
        @return code of the translation language (string)
        """
        return self.transLanguageComboBox.itemData(
            self.transLanguageComboBox.currentIndex())

    @pyqtSlot()
    def on_translateButton_clicked(self):
        """
        Private slot to translate the entered text.
        """
        self.transEdit.clear()
        result, ok = self.__translate(self.origEdit.toPlainText(),
                                      self.__originalLanguage(),
                                      self.__translationLanguage())
        if ok:
            self.transEdit.setHtml(result)
        else:
            E5MessageBox.critical(self, self.tr("Translation Error"), result)

    @pyqtSlot()
    def on_pronounceOrigButton_clicked(self):
        """
        Private slot to pronounce the original text.
        """
        self.__pronounce(self.origEdit.toPlainText(),
                         self.__originalLanguage())

    @pyqtSlot()
    def on_pronounceTransButton_clicked(self):
        """
        Private slot to pronounce the translated text.
        """
        self.__pronounce(self.transEdit.toPlainText(),
                         self.__translationLanguage())

    @pyqtSlot()
    def on_swapButton_clicked(self):
        """
        Private slot to swap the languages.
        """
        # save selected language codes
        oLanguage = self.origLanguageComboBox.itemData(
            self.origLanguageComboBox.currentIndex())

        tLanguage = self.transLanguageComboBox.itemData(
            self.transLanguageComboBox.currentIndex())

        oIdx = self.origLanguageComboBox.findData(tLanguage)
        if oIdx < 0:
            oIdx = 0
        self.origLanguageComboBox.setCurrentIndex(oIdx)

        tIdx = self.transLanguageComboBox.findData(oLanguage)
        if tIdx < 0:
            tIdx = 0
        self.transLanguageComboBox.setCurrentIndex(tIdx)

        origText = self.origEdit.toPlainText()
        self.origEdit.setPlainText(self.transEdit.toPlainText())
        self.transEdit.setPlainText(origText)

    @pyqtSlot()
    def on_clearButton_clicked(self):
        """
        Private slot to clear the text fields.
        """
        self.origEdit.clear()
        self.transEdit.clear()

    @pyqtSlot()
    def on_origEdit_textChanged(self):
        """
        Private slot to handle changes of the original text.
        """
        self.__updatePronounceButtons()
        self.__updateClearButton()
        self.__updateTranslateButton()

    @pyqtSlot()
    def on_transEdit_textChanged(self):
        """
        Private slot to handle changes of the translation text.
        """
        self.__updatePronounceButtons()
        self.__updateClearButton()

    @pyqtSlot(int)
    def on_origLanguageComboBox_currentIndexChanged(self, index):
        """
        Private slot to handle the selection of the original language.
        
        @param index current index (integer)
        """
        self.__plugin.setPreferences("OriginalLanguage",
                                     self.origLanguageComboBox.itemData(index))

        supportedTargetCodes = (
            self.__translationEngine.supportedTargetLanguages(
                self.origLanguageComboBox.itemData(index)))
        if supportedTargetCodes is not None:
            enabledCodes = self.__plugin.getPreferences("EnabledLanguages")
            transLanguage = self.transLanguageComboBox.itemData(
                self.transLanguageComboBox.currentIndex())
            self.transLanguageComboBox.clear()
            if len(supportedTargetCodes) > 0:
                for code in enabledCodes:
                    if code in supportedTargetCodes:
                        language = self.__languages.getLanguage(code)
                        if language:
                            icon = self.__languages.getLanguageIcon(code)
                            self.transLanguageComboBox.addItem(
                                icon, language, code)
                self.transLanguageComboBox.model().sort(0)
                index = self.transLanguageComboBox.findData(transLanguage)
                if index == -1:
                    index = 0
                self.transLanguageComboBox.setCurrentIndex(index)

        self.__updateTranslateButton()

    @pyqtSlot(int)
    def on_transLanguageComboBox_currentIndexChanged(self, index):
        """
        Private slot to handle the selection of the translation language.
        
        @param index current index (integer)
        """
        self.__plugin.setPreferences(
            "TranslationLanguage", self.transLanguageComboBox.itemData(index))

    @pyqtSlot()
    def __availableTranslationsLoaded(self):
        """
        Private slot to handle the availability of translations.
        """
        origLanguage = self.__plugin.getPreferences("OriginalLanguage")
        transLanguage = self.__plugin.getPreferences("TranslationLanguage")

        self.__updateLanguages()

        origIndex = self.origLanguageComboBox.findData(origLanguage)
        self.origLanguageComboBox.setCurrentIndex(origIndex)
        self.on_origLanguageComboBox_currentIndexChanged(origIndex)
        self.transLanguageComboBox.setCurrentIndex(
            self.transLanguageComboBox.findData(transLanguage))

    def __ensureTranslationEngineReady(self):
        """
        Private slot to ensure, that the currently selected translation engine
        is ready.
        """
        engineName = self.engineComboBox.itemData(
            self.engineComboBox.currentIndex())
        if (self.__translationEngine is not None
                and self.__translationEngine.engineName() != engineName):
            self.__translationEngine.availableTranslationsLoaded.disconnect(
                self.__availableTranslationsLoaded)
            self.__translationEngine.deleteLater()
            self.__translationEngine = None

        if self.__translationEngine is None:
            self.__translationEngine = TranslatorEngines.getTranslationEngine(
                engineName, self.__plugin, self)
            if self.__translationEngine is not None:
                self.__translationEngine.availableTranslationsLoaded.connect(
                    self.__availableTranslationsLoaded)

    @pyqtSlot(int)
    def __engineComboBoxCurrentIndexChanged(self, index):
        """
        Private slot to handle the selection of a translation service.
        
        @param index current index
        @type int
        """
        self.__ensureTranslationEngineReady()
        if self.__translationEngine is not None:
            self.__updateTranslateButton()
            self.__updatePronounceButtons()

            self.__plugin.setPreferences("SelectedEngine",
                                         self.engineComboBox.itemData(index))

    def __updatePronounceButtons(self):
        """
        Private slot to set the state of the pronounce buttons.
        """
        if self.__translationEngine is not None:
            hasTTS = self.__translationEngine.hasTTS()
        else:
            hasTTS = False
        self.pronounceOrigButton.setEnabled(
            hasTTS and bool(self.origEdit.toPlainText()))
        self.pronounceTransButton.setEnabled(
            hasTTS and bool(self.transEdit.toPlainText()))

    def __updateClearButton(self):
        """
        Private slot to set the state of the clear button.
        """
        enable = (bool(self.origEdit.toPlainText())
                  or bool(self.transEdit.toPlainText()))
        self.clearButton.setEnabled(enable)

    def __updateTranslateButton(self):
        """
        Private slot to set the state of the translate button.
        """
        enable = bool(self.origEdit.toPlainText())
        enable &= bool(self.__translationLanguage())
        enable &= bool(self.__originalLanguage())
        self.translateButton.setEnabled(enable)

    def __translate(self, text, originalLanguage, translationLanguage):
        """
        Private method to translate the given text.
        
        @param text text to be translated (string)
        @param originalLanguage language code of the original (string)
        @param translationLanguage language code of the translation (string)
        @return tuple of translated text (string) and flag indicating
            success (boolean)
        """
        if self.__translatorRequest is None:
            from .TranslatorRequest import TranslatorRequest
            self.__translatorRequest = TranslatorRequest(self)

        self.__ensureTranslationEngineReady()
        if self.__translationEngine is None:
            return "", False
        else:
            result, ok = self.__translationEngine.getTranslation(
                self.__translatorRequest, text, originalLanguage,
                translationLanguage)

            return result, ok

    def __pronounce(self, text, language):
        """
        Private method to pronounce the given text.
        
        @param text text to be pronounced (string)
        @param language language code of the text (string)
        """
        if not text or not language:
            return

        if self.__translatorRequest is None:
            from .TranslatorRequest import TranslatorRequest
            self.__translatorRequest = TranslatorRequest(self)

        if self.__mediaPlayer is None:
            self.__mediaPlayer = QMediaPlayer(self)
            self.__mediaPlayer.stateChanged.connect(
                self.__mediaPlayerStateChanged)

        if self.__mediaPlayer.state() == QMediaPlayer.PlayingState:
            return

        self.__ensureTranslationEngineReady()
        if self.__translationEngine is not None:
            if not self.__translationEngine.hasTTS():
                E5MessageBox.critical(
                    self, self.tr("Translation Error"),
                    self.tr("The selected translation service does not"
                            " support the Text-to-Speech function."))
                return

            data, ok = self.__translationEngine.getTextToSpeechData(
                self.__translatorRequest, text, language)
            if ok:
                self.__mediaFile = QTemporaryFile(self)
                self.__mediaFile.open()
                self.__mediaFile.setAutoRemove(False)
                self.__mediaFile.write(data)

                self.__mediaPlayer.setMedia(QMediaContent(), self.__mediaFile)
                self.__mediaPlayer.play()
            else:
                E5MessageBox.critical(self, self.tr("Translation Error"), data)

    def __mediaPlayerStateChanged(self, state):
        """
        Private slot handling changes of the media player state.
        
        @param state media player state (QAudio.State)
        """
        if state == QMediaPlayer.StoppedState:
            self.__mediaFile.close()
            self.__mediaFile.remove()
            self.__mediaFile = None

    @pyqtSlot()
    def on_preferencesButton_clicked(self):
        """
        Private slot to open the Translator configuration page.
        """
        e5App().getObject("UserInterface").showPreferences("translatorPage")