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
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
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
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")