From 5d670d62b1c8148312d6c3bf7f9b5614411cf492 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaros=C5=82aw=20Wieczorek?= Date: Mon, 18 Jan 2021 16:35:37 +0100 Subject: [PATCH] Add progress bar. Add docstrings. Add generation done info. Pylama fixes. Fixes. --- src/gui/ui/mainwindow.ui | 8 ++++ src/python/classes/mainwindow.py | 69 ++++++++++++++++++++++++---- src/python/classes/preview_dialog.py | 23 +++++++++- src/python/classes/range_slider.py | 19 +++++--- src/python/classes/translate.py | 2 +- src/python/ui/mainwindow_ui.py | 5 ++ 6 files changed, 108 insertions(+), 18 deletions(-) diff --git a/src/gui/ui/mainwindow.ui b/src/gui/ui/mainwindow.ui index 02eef28..e57f55f 100644 --- a/src/gui/ui/mainwindow.ui +++ b/src/gui/ui/mainwindow.ui @@ -614,6 +614,13 @@ + + + + 24 + + + h_line h_line_2 @@ -621,6 +628,7 @@ h_line_3 v_spacer_1 check_box_connected_channels + progress_bar diff --git a/src/python/classes/mainwindow.py b/src/python/classes/mainwindow.py index e64d711..243ec3f 100644 --- a/src/python/classes/mainwindow.py +++ b/src/python/classes/mainwindow.py @@ -2,11 +2,12 @@ import os import shutil import subprocess import tempfile + from pathlib import Path from pydub.utils import mediainfo # import resources_rc -from PyQt5.QtCore import Qt +from PyQt5.QtCore import Qt, pyqtSignal, pyqtSlot from PyQt5.QtGui import QPixmap from PyQt5.QtWidgets import QMainWindow, QLabel, QFileDialog, QDialog, QDialogButtonBox, QVBoxLayout, QApplication @@ -23,9 +24,13 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): """ MainWindow Class """ + signal = pyqtSignal() + slot = pyqtSlot() def __init__(self, parent=None): + super(MainWindow, self).__init__(parent=parent) + self.connected_channels_status = False self.translator = Translator() self.installTranslator(self.translator) self.lang = 'pl' @@ -35,10 +40,11 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): self.setup_detail() self.retranslateUi(self.window()) self.aresample = "8000" - self.test_data() - + # self.test_data() + self.dialog = self.create_custom_dialog(title='Process generowania podcastu', msg='Sprawdzanie poprawności danych') self.image_extensions = ['.jpg', '.png'] self.audio_extensions = ['.mp3', '.wav'] + self.progress_bar.setValue(0) def setup_logic(self): """Connect ui elements with methods.""" @@ -52,8 +58,13 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): self.button_select_avatar_3.clicked.connect(lambda: self.open_image_import(image_number=3)) self.button_select_avatar_4.clicked.connect(lambda: self.open_image_import(image_number=4)) self.check_box_connected_channels.setChecked(True) + self.connected_channels_status = self.check_box_connected_channels.checkState() self.check_box_connected_channels.stateChanged.connect(self.channels_connected) + def on_progress_change(self, value): + """Update progress bar value""" + self.progress_bar.setValue(value) + def change_language(self): """Retranslate user interface.""" self.translator.load_lang(self.lang) @@ -191,7 +202,8 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): if audio_number == 1: self.line_edit_audio_1.setText(file) self.line_edit_audio_1.setProperty('duration', mediainfo(file)['duration']) - print(f"[*] Audio 1: {file} duration: {mediainfo(file)['duration']}") + + print(f"[*] Audio 1: {file} duration: {self.line_edit_audio_1.property('duration')}") elif audio_number == 2: self.line_edit_audio_2.setText(file) self.line_edit_audio_2.setProperty('duration', mediainfo(file)['duration']) @@ -213,7 +225,9 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): def channels_connected(self, checked): """Change information id channels connected.""" print(checked) + self.connected_channels_status = checked if checked: + self.button_audio_2.setDisabled(True) self.line_edit_audio_2.setDisabled(True) self.line_edit_audio_1.setPlaceholderText("Plik audio rozmówców") @@ -225,11 +239,35 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): def preview_video_podcast(self): """Preview Video Podcast""" - preview_dialog = PreviewDialog(parent=self) + + if not self.check_box_connected_channels.isChecked(): + audio_files = [self.line_edit_audio_1.text(), self.line_edit_audio_2.text()] + + if not all(self.check_file(x, self.audio_extensions) for x in audio_files): + return -1 + audio_1 = float(self.line_edit_audio_1.property('duration')) + print(audio_1) + audio_2 = float(self.line_edit_audio_2.property('duration')) + + print(f"[*] File duration audio_1: {audio_1}") + print(f"[*] File duration audio_2: {audio_2}") + + end_time = audio_1 if audio_1 >= audio_2 else audio_2 + preview_dialog = PreviewDialog(parent=self, start_time=0, end_time=end_time) + else: + audio_files = [self.line_edit_audio_1.text()] + if not all(self.check_file(x, self.audio_extensions) for x in audio_files): + return -1 + + end_time = float(self.line_edit_audio_1.property('duration')) + print(f"[*] File duration audio_2: {end_time}") + preview_dialog = PreviewDialog(parent=self, start_time=0, end_time=end_time) + preview_dialog.exec_() def generate_video_podcast(self, start=None, end=None): """Generate podcast based on values from UI.""" + self.progress_bar.setValue(0) threshold_value = int(self.threshold_lcd.value()) generate_demuxer.set_up_threshold(threshold_value) connected_channels = self.check_box_connected_channels.isChecked() @@ -242,12 +280,12 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): 'right': self.preview_label_avatar_4.property('path') } - audio_files = [] for image_path in image_files.values(): if not self.check_file(image_path, self.image_extensions): - self.create_custom_dialog(title='Błąd!', msg=f"Tworzenie podcastu zostało przerwane.") - return -1 + self.create_custom_dialog(title='Błąd!', msg="Tworzenie podcastu zostało przerwane.") + return -1 + audio_files = [] if not connected_channels: audio_files.append({'file': self.line_edit_audio_1.text()}) audio_files.append({'file': self.line_edit_audio_2.text()}) @@ -258,14 +296,16 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): for audio_path in audio_files: if not Path(audio_path['file']).is_file(): if not self.check_file(audio_path['file'], self.audio_extensions): - self.create_custom_dialog(title='Błąd!', msg=f"Tworzenie podcastu zostało przerwane.") + self.create_custom_dialog(title='Błąd!', msg="Tworzenie podcastu zostało przerwane.") return -1 # Split name and extension of the file for dictionary in audio_files: dictionary['ext'] = dictionary['file'].rsplit('.')[-1] + self.progress_bar.setValue(10) with tempfile.TemporaryDirectory() as tmp_dir_name: + print(tmp_dir_name) print(f'[*] Create temporary directory: {tmp_dir_name}') tmp_out_dir = tmp_dir_name + "/out" @@ -273,6 +313,7 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): audio_dir = tmp_dir_name + "/audio" video_dir = tmp_dir_name + "/video" + self.progress_bar.setValue(15) print(F"[!] Create tmp out dir: {tmp_out_dir}") os.mkdir(tmp_out_dir) @@ -291,6 +332,7 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): shutil.copy(image_files['left'], pics_dir + "/left.png") shutil.copy(image_files['right'], pics_dir + "/right.png") + self.progress_bar.setValue(20) print(f'[*] Copy audio to {audio_dir}\n') if not self.check_box_connected_channels.isChecked(): audio_files[0]['tmp'] = audio_dir + "/left_channel" + "." + audio_files[0]['ext'] @@ -306,6 +348,7 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): print(f'[*] Images in {pics_dir}: {os.listdir(pics_dir)}') print(f'[*] Audo files in {audio_dir}: {os.listdir(audio_dir)}') + self.progress_bar.setValue(25) subprocess.check_output(["echo", tmp_dir_name]).decode('utf-8') if connected_channels: @@ -317,12 +360,14 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): audio_files[0]['tmp']]) print("[+] Split channels - done") + self.progress_bar.setValue(30) print("[-] Create raw files - start:") subprocess.check_output(['bash', 'bash_commands/create_raw_files.sh', audio_dir, self.aresample]) print("[+] Create raw files - done") + self.progress_bar.setValue(60) print("[-] Create demuxer - start:") generate_demuxer.run(tmp_dir=tmp_dir_name) print("[+] Create demuxer - done") @@ -332,8 +377,14 @@ class MainWindow(QMainWindow, QApplication, Ui_MainWindow): ['bash', 'bash_commands/generate_video_by_demuxer.sh', tmp_dir_name, video_dir]) print('[+] Create video - done') + self.progress_bar.setValue(75) # while True: pass print('[-] Create final podcast - start:') subprocess.check_output( ['bash', 'bash_commands/connect_sound.sh', tmp_dir_name, audio_files[0]['file']]) print('[+] Create final podcast - done') + self.progress_bar.setValue(100) + + dialog_done = self.create_custom_dialog(title="Informacja", msg="Zakończono generowanie podcastu.") + dialog_done.exec_() + self.progress_bar.setValue(0) diff --git a/src/python/classes/preview_dialog.py b/src/python/classes/preview_dialog.py index 24f0136..56b6c42 100644 --- a/src/python/classes/preview_dialog.py +++ b/src/python/classes/preview_dialog.py @@ -1,10 +1,12 @@ +from pathlib import Path + from PyQt5.QtMultimedia import QMediaPlayer from PyQt5.QtMultimediaWidgets import QVideoWidget from src.python.classes.range_slider import QRangeSlider from src.python.ui.preview_dialog_ui import Ui_PreviewDialog -from PyQt5.QtWidgets import QDialog, QLabel, QStyle +from PyQt5.QtWidgets import QDialog, QStyle class PreviewDialog(QDialog, Ui_PreviewDialog): @@ -14,6 +16,7 @@ class PreviewDialog(QDialog, Ui_PreviewDialog): def __init__(self, parent=None, start_time=0, end_time=15): super(PreviewDialog, self).__init__(parent=parent) self.setupUi(self) + self.mediaPlayer = QMediaPlayer(parent=self, flags=QMediaPlayer.VideoSurface) self.video_widget = QVideoWidget() @@ -23,6 +26,24 @@ class PreviewDialog(QDialog, Ui_PreviewDialog): self.range_slider.setRange(start=int(start_time), end=int(end_time)) + def get_audio_files(self): + """Load time of audio files""" + audio_files = [] + if not self.connected_channels_status: + audio_files.append({'file': self.line_edit_audio_1.text()}) + audio_files.append({'file': self.line_edit_audio_2.text()}) + + else: + audio_files.append({'file': self.line_edit_audio_1.text()}) + + for audio_path in audio_files: + if not Path(audio_path['file']).is_file(): + if not self.check_file(audio_path['file'], self.audio_extensions): + self.create_custom_dialog(title='Błąd!', msg="Tworzenie podcastu zostało przerwane.") + return -1 + + return audio_files + def setup_video_logic(self): """ Setup connections to events diff --git a/src/python/classes/range_slider.py b/src/python/classes/range_slider.py index 2463e5e..ce9d66d 100644 --- a/src/python/classes/range_slider.py +++ b/src/python/classes/range_slider.py @@ -1,6 +1,6 @@ -from PyQt5.QtWidgets import * -from PyQt5.QtCore import * -from PyQt5.QtGui import * +from PyQt5.QtCore import Qt, QRect, QSize +from PyQt5.QtGui import QPaintEvent, QPainter, QPalette, QBrush, QMouseEvent +from PyQt5.QtWidgets import QApplication, QAbstractSlider, QSizePolicy, QSlider, QStyle, QStyleOptionSlider class QRangeSlider(QAbstractSlider): @@ -25,24 +25,29 @@ class QRangeSlider(QAbstractSlider): ) def setRangeLimit(self, minimum: int, maximum: int): + """Set new range limit.""" self.opt.minimum = minimum self.opt.maximum = maximum def setRange(self, start: int, end: int): + """Set new range.""" self.first_position = start self.second_position = end def getRange(self): + """Get selected current range.""" return self.first_position, self.second_position def setTickPosition(self, position: QSlider.TickPosition): + """Set tick position.""" self.opt.tickPosition = position def setTickInterval(self, ti: int): + """Set tick interval.""" self.opt.tickInterval = ti def paintEvent(self, event: QPaintEvent): - + """Handle paint event.""" painter = QPainter(self) # Draw rule @@ -99,7 +104,7 @@ class QRangeSlider(QAbstractSlider): self.style().drawComplexControl(QStyle.CC_Slider, self.opt, painter) def mousePressEvent(self, event: QMouseEvent): - + """Handle mouse press event.""" self.opt.sliderPosition = self.first_position self._first_sc = self.style().hitTestComplexControl( QStyle.CC_Slider, self.opt, event.pos(), self @@ -111,7 +116,7 @@ class QRangeSlider(QAbstractSlider): ) def mouseMoveEvent(self, event: QMouseEvent): - + """Handle mouse move event.""" distance = self.opt.maximum - self.opt.minimum pos = self.style().sliderValueFromPosition( @@ -130,7 +135,7 @@ class QRangeSlider(QAbstractSlider): self.update() def sizeHint(self): - """ override """ + """ Override sizeHint """ SliderLength = 84 TickSpace = 5 diff --git a/src/python/classes/translate.py b/src/python/classes/translate.py index c4598b5..8578ef2 100644 --- a/src/python/classes/translate.py +++ b/src/python/classes/translate.py @@ -5,7 +5,7 @@ from PyQt5.QtCore import QTranslator class Translator(QTranslator): - + """Translator to change language for user interface.""" def __init__(self): QTranslator.__init__(self) diff --git a/src/python/ui/mainwindow_ui.py b/src/python/ui/mainwindow_ui.py index 315fb35..344ca24 100644 --- a/src/python/ui/mainwindow_ui.py +++ b/src/python/ui/mainwindow_ui.py @@ -261,11 +261,16 @@ class Ui_MainWindow(object): self.button_generate.setObjectName("button_generate") self.h_layout_preview_or_generate.addWidget(self.button_generate) self.verticalLayout.addLayout(self.h_layout_preview_or_generate) + self.progress_bar = QtWidgets.QProgressBar(self.central_widget) + self.progress_bar.setProperty("value", 24) + self.progress_bar.setObjectName("progress_bar") + self.verticalLayout.addWidget(self.progress_bar) self.h_line.raise_() self.h_line_2.raise_() self.threshold_slider.raise_() self.h_line_3.raise_() self.check_box_connected_channels.raise_() + self.progress_bar.raise_() MainWindow.setCentralWidget(self.central_widget) self.menu_bar = QtWidgets.QMenuBar(MainWindow) self.menu_bar.setGeometry(QtCore.QRect(0, 0, 554, 32))