''' (C) 2019 Raryel C. Souza This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . ''' from PyQt5 import QtCore, QtWidgets from PyQt5.QtWidgets import QFileDialog, QMessageBox from PyQt5.QtCore import Qt from pathlib import Path from pytranscriber.model.param_autosub import Param_Autosub from pytranscriber.util.util import MyUtil from pytranscriber.control.thread_exec_autosub import Thread_Exec_Autosub from pytranscriber.control.thread_cancel_autosub import Thread_Cancel_Autosub from pytranscriber.gui.gui import Ui_window import os class Ctr_Main(): def __init__(self): import sys app = QtWidgets.QApplication(sys.argv) window = QtWidgets.QMainWindow() self.objGUI = Ui_window() self.objGUI.setupUi(window) self.__initGUI() window.setFixedSize(window.size()) window.show() sys.exit(app.exec_()) def __initGUI(self): #language selection list list_languages = [ "en-US - English (United States)", "en-AU - English (Australia)", "en-CA - English (Canada)", "en-GB - English (United Kingdom)", "en-HK - English (Hong Kong)", "en-IN - English (India)", "en-GB - English (Ireland)", "en-NZ - English (New Zealand)", "en-PH - English (Philippines)", "en-SG - English (Singapore)", "af - Afrikaans", "ar - Arabic", 'ar-DZ - Arabic (Algeria)', 'ar-EG - Arabic (Egypt)', 'ar-IQ - Arabic (Iraq)', 'ar-IS - Arabic (Israel)', 'ar-JO - Arabic (Jordan)', 'ar-KW - Arabic (Kuwait)', 'ar-LB - Arabic (Lebanon)', 'ar-MA - Arabic (Morocco)', 'ar-OM - Arabic (Oman)', 'ar-QA - Arabic (Qatar)', 'ar-SA - Arabic (Saudi Arabia)', 'ar-PS - Arabic (State of Palestine)', 'ar-TN - Arabic (Tunisia)', 'ar-AE - Arabic (United Arab Emirates)', 'ar-YE - Arabic (Yemen)', "az - Azerbaijani", "be - Belarusian", "bg - Bulgarian", "bn - Bengali", "bs - Bosnian", "ca - Catalan", "ceb -Cebuano", "cs - Czech", "cy - Welsh", "da - Danish", "de - German", 'de-AT - German (Austria)', 'de-CH - German (Switzerland)', "el - Greek", "eo - Esperanto", 'es-ES - Spanish (Spain)', 'es-AR - Spanish (Argentina)', 'es-BO - Spanish (Bolivia)', 'es-CL - Spanish (Chile)', 'es-CO - Spanish (Colombia)', 'es-CR - Spanish (Costa Rica)', 'es-DO - Spanish (Dominican Republic)', 'es-EC - Spanish (Ecuador)', 'es-GT - Spanish (Guatemala)', 'es-HN - Spanish (Honduras)', 'es-MX - Spanish (Mexico)', 'es-NI - Spanish (Nicaragua)', 'es-PA - Spanish (Panama)', 'es-PE - Spanish (Peru)', 'es-PR - Spanish (Puerto Rico)', 'es-PY - Spanish (Paraguay)', 'es-SV - Spanish (El Salvador)', 'es-UY - Spanish (Uruguay)', 'es-US - Spanish (United States)', 'es-VE - Spanish (Venezuela)', "et - Estonian", "eu - Basque", "fa - Persian", 'fil-PH - Filipino (Philippines)', "fi - Finnish", "fr - French", 'fr-BE - French (Belgium)', 'fr-CA - French (Canada)', 'fr-CH - French (Switzerland)', "ga - Irish", "gl - Galician", "gu -Gujarati", "ha - Hausa", "hi - Hindi", "hmn - Hmong", "hr - Croatian", "ht - Haitian Creole", "hu - Hungarian", "hy - Armenian", "id - Indonesian", "ig - Igbo", "is - Icelandic", "it - Italian", 'it-CH - Italian (Switzerland)', "iw - Hebrew", "ja - Japanese", "jw - Javanese", "ka - Georgian", "kk - Kazakh", "km - Khmer", "kn - Kannada", "ko - Korean", "la - Latin", "lo - Lao", "lt - Lithuanian", "lv - Latvian", "mg - Malagasy", "mi - Maori", "mk - Macedonian", "ml - Malayalam", "mn - Mongolian", "mr - Marathi", "ms - Malay", "mt - Maltese", "my - Myanmar (Burmese)", "ne - Nepali", "nl - Dutch", "no - Norwegian", "ny - Chichewa", "pa - Punjabi", "pl - Polish", "pt-BR - Portuguese (Brazil)", "pt-PT - Portuguese (Portugal)", "ro - Romanian", "ru - Russian", "si - Sinhala", "sk - Slovak", "sl - Slovenian", "so - Somali", "sq - Albanian", "sr - Serbian", "st - Sesotho", "su - Sudanese", "sv - Swedish", "sw - Swahili", "ta - Tamil", 'ta-IN - Tamil (India)', 'ta-MY - Tamil (Malaysia)', 'ta-SG - Tamil (Singapore)', 'ta-LK - Tamil (Sri Lanka)', "te - Telugu", "tg - Tajik", "th - Thai", "tl - Filipino", "tr - Turkish", "uk - Ukrainian", "ur - Urdu", "uz - Uzbek", "vi - Vietnamese", "yi - Yiddish", "yo - Yoruba", "yue-Hant-HK - Cantonese (Traditional, HK)", "zh - Chinese (Simplified, China)", "zh-HK - Chinese (Simplified, Hong Kong)", "zh-TW - Chinese (Traditional, Taiwan)", "zu - Zulu" ] self.objGUI.cbSelectLang.addItems(list_languages) self.__listenerProgress("", 0) #default output folder at user desktop userHome = Path.home() pathOutputFolder = userHome / 'Desktop' / 'pyTranscriber' self.objGUI.qleOutputFolder.setText(str(pathOutputFolder)) self.objGUI.bRemoveFile.setEnabled(False) self.objGUI.bCancel.hide() #button listeners self.objGUI.bConvert.clicked.connect(self.__listenerBExec) self.objGUI.bCancel.clicked.connect(self.__listenerBCancel) self.objGUI.bRemoveFile.clicked.connect(self.__listenerBRemove) self.objGUI.bSelectOutputFolder.clicked.connect(self.__listenerBSelectOuputFolder) self.objGUI.bOpenOutputFolder.clicked.connect(self.__listenerBOpenOutputFolder) self.objGUI.bSelectMedia.clicked.connect(self.__listenerBSelectMedia) self.objGUI.actionLicense.triggered.connect(self.__listenerBLicense) self.objGUI.actionDonation.triggered.connect(self.__listenerBDonation) self.objGUI.actionAbout_pyTranscriber.triggered.connect(self.__listenerBAboutpyTranscriber) def __resetGUIAfterSuccess(self): self.__resetGUIAfterCancel() self.objGUI.qlwListFilesSelected.clear() self.objGUI.bConvert.setEnabled(False) self.objGUI.bRemoveFile.setEnabled(False) def __resetGUIAfterCancel(self): self.__resetProgressBar() self.objGUI.bSelectMedia.setEnabled(True) self.objGUI.bSelectOutputFolder.setEnabled(True) self.objGUI.cbSelectLang.setEnabled(True) self.objGUI.chbxOpenOutputFilesAuto.setEnabled(True) self.objGUI.bCancel.hide() self.objGUI.bConvert.setEnabled(True) self.objGUI.bRemoveFile.setEnabled(True) def __lockButtonsDuringOperation(self): self.objGUI.bConvert.setEnabled(False) self.objGUI.bRemoveFile.setEnabled(False) self.objGUI.bSelectMedia.setEnabled(False) self.objGUI.bSelectOutputFolder.setEnabled(False) self.objGUI.cbSelectLang.setEnabled(False) self.objGUI.chbxOpenOutputFilesAuto.setEnabled(False) QtCore.QCoreApplication.processEvents() def __listenerProgress(self, str, percent): self.objGUI.labelCurrentOperation.setText(str) self.objGUI.progressBar.setProperty("value", percent) QtCore.QCoreApplication.processEvents() def __setProgressBarIndefinite(self): self.objGUI.progressBar.setMinimum(0) self.objGUI.progressBar.setMaximum(0) self.objGUI.progressBar.setValue(0) def __resetProgressBar(self): self.objGUI.progressBar.setMinimum(0) self.objGUI.progressBar.setMaximum(100) self.objGUI.progressBar.setValue(0) self.__listenerProgress("", 0) def __updateProgressFileYofN(self, str): self.objGUI.labelProgressFileIndex.setText(str) QtCore.QCoreApplication.processEvents() def __listenerBSelectOuputFolder(self): fSelectDir = QFileDialog.getExistingDirectory(self.objGUI.centralwidget) if fSelectDir: self.objGUI.qleOutputFolder.setText(fSelectDir) def __listenerBSelectMedia(self): #options = QFileDialog.Options() options = QFileDialog.DontUseNativeDialog files, _ = QFileDialog.getOpenFileNames(self.objGUI.centralwidget, "Select media", "","All Media Files (*.mp3 *.mp4 *.wav *.m4a *.wma)") if files: self.objGUI.qlwListFilesSelected.addItems(files) #enable the convert button only if list of files is not empty self.objGUI.bConvert.setEnabled(True) self.objGUI.bRemoveFile.setEnabled(True) def __listenerBExec(self): if not MyUtil.is_internet_connected(): self.__showErrorMessage("Error! Cannot reach Google Speech Servers. \n\n1) Please make sure you are connected to the internet. \n2) If you are in China or other place that blocks access to Google servers: please install and enable a desktop-wide VPN app like Windscribe before trying to use pyTranscriber!") else: #extracts the two letter lang_code from the string on language selection selectedLanguage = self.objGUI.cbSelectLang.currentText() indexSpace = selectedLanguage.index(" ") langCode = selectedLanguage[:indexSpace] listFiles = [] for i in range(self.objGUI.qlwListFilesSelected.count()): listFiles.append(str(self.objGUI.qlwListFilesSelected.item(i).text())) outputFolder = self.objGUI.qleOutputFolder.text() if self.objGUI.chbxOpenOutputFilesAuto.checkState() == Qt.Checked: boolOpenOutputFilesAuto = True else: boolOpenOutputFilesAuto = False objParamAutosub = Param_Autosub(listFiles, outputFolder, langCode, boolOpenOutputFilesAuto) #execute the main process in separate thread to avoid gui lock self.thread_exec = Thread_Exec_Autosub(objParamAutosub) #connect signals from work thread to gui controls self.thread_exec.signalLockGUI.connect(self.__lockButtonsDuringOperation) self.thread_exec.signalResetGUIAfterSuccess.connect(self.__resetGUIAfterSuccess) self.thread_exec.signalResetGUIAfterCancel.connect(self.__resetGUIAfterCancel) self.thread_exec.signalProgress.connect(self.__listenerProgress) self.thread_exec.signalProgressFileYofN.connect(self.__updateProgressFileYofN) self.thread_exec.signalErrorMsg.connect(self.__showErrorMessage) self.thread_exec.start() #Show the cancel button self.objGUI.bCancel.show() self.objGUI.bCancel.setEnabled(True) def __listenerBCancel(self): self.objGUI.bCancel.setEnabled(False) self.thread_cancel = Thread_Cancel_Autosub(self.thread_exec) #Only if worker thread is running if self.thread_exec and self.thread_exec.isRunning(): #reset progress indicator self.__listenerProgress("Cancelling", 0) self.__setProgressBarIndefinite() self.__updateProgressFileYofN("") #connect the terminate signal to resetGUI self.thread_cancel.signalTerminated.connect(self.__resetGUIAfterCancel) #run the cancel autosub operation in new thread #to avoid progressbar freezing self.thread_cancel.start() self.thread_exec = None def __listenerBRemove(self): indexSelected = self.objGUI.qlwListFilesSelected.currentRow() if indexSelected >= 0: self.objGUI.qlwListFilesSelected.takeItem(indexSelected) #if no items left disables the remove and convert button if self.objGUI.qlwListFilesSelected.count() == 0: self.objGUI.bRemoveFile.setEnabled(False) self.objGUI.bConvert.setEnabled(False) def __listenerBOpenOutputFolder(self): pathOutputFolder = Path(self.objGUI.qleOutputFolder.text()) #if folder exists and is valid directory if os.path.exists(pathOutputFolder) and os.path.isdir(pathOutputFolder): MyUtil.open_file(pathOutputFolder) else: self.__showErrorMessage("Error! Invalid output folder.") def __listenerBLicense(self): self.__showInfoMessage("GPL License

" + "Copyright (C) 2019 Raryel C. Souza
" + "
This program is free software: you can redistribute it and/or modify
" + "it under the terms of the GNU General Public License as published by
" + "the Free Software Foundation, either version 3 of the License, or
" + " any later version
" + "
" + "This program is distributed in the hope that it will be useful,
" + "but WITHOUT ANY WARRANTY; without even the implied warranty of
" + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
" + "GNU General Public License for more details.
" + "
" + "You should have received a copy of the GNU General Public License
" + "along with this program. If not, see www.gnu.org/licenses." + "", "License") def __listenerBDonation(self): self.__showInfoMessage("" + "pyTranscriber is developed as a hobby, so donations of any value are welcomed and essential for further improvements and fixes." + "

If you feel that this software has been useful and would like to contribute for it to continue improve and have more features and fixes you can DONATE VIA PAYPAL or DONATE US$5 VIA BITCOIN." + "

Thanks in advance!" + "", "DONATIONS") def __listenerBAboutpyTranscriber(self): self.__showInfoMessage("" + "pyTranscriber is an application that can be used " + "to generate automatic transcription / automatic subtitles " + "for audio/video files through a friendly graphical user interface. " + "

" + "The hard work of speech recognition is made by the Google Speech Recognition API " + "using Autosub" + "

pyTranscriber is developed as a hobby, so donations of any value are welcomed and essential for further improvements and fixes." + "

If you feel that this software has been useful and would like to contribute for it to continue improve and have more features and fixes you can DONATE VIA PAYPAL or DONATE US$5 VIA BITCOIN." + "

Thanks in advance!" + "", "About pyTranscriber") def __showInfoMessage(self, info_msg, title): msg = QMessageBox() msg.setIcon(QMessageBox.Information) msg.setWindowTitle(title) msg.setText(info_msg) msg.exec() def __showErrorMessage(self, errorMsg): msg = QMessageBox() msg.setIcon(QMessageBox.Critical) msg.setWindowTitle("Error!") msg.setText(errorMsg) msg.exec()