From: Urban Wallasch Date: Fri, 28 May 2021 11:21:35 +0000 (+0200) Subject: * Added GUI batch processing dialog. X-Git-Tag: v0.4~5 X-Git-Url: https://git.packet-gain.de/?a=commitdiff_plain;h=9a3a9057e45ffa7f613861c902d62189c3526b81;p=ffpreview.git * Added GUI batch processing dialog. --- diff --git a/README.md b/README.md index 47f275d..cd46c1c 100644 --- a/README.md +++ b/README.md @@ -107,6 +107,7 @@ window controls: Ctrl+G adjust window geometry for optimal fit Ctrl+O show open file dialog Ctrl+M open thumbnail manager + Ctrl+B open batch processing dialog Ctrl+Alt+P open preferences dialog Alt+H open about dialog Double-click, diff --git a/ffpreview.py b/ffpreview.py index 4e7b40f..e77db65 100755 --- a/ffpreview.py +++ b/ffpreview.py @@ -54,6 +54,9 @@ _FFPREVIEW_HELP = """ Ctrl+M Open thumbnail manager + + Ctrl+B + Open batch processing dialog """ @@ -247,6 +250,7 @@ class ffConfig: ' Ctrl+G adjust window geometry for optimal fit\n' ' Ctrl+O show open file dialog\n' ' Ctrl+M open thumbnail manager\n' + ' Ctrl+B open batch processing dialog\n' ' Ctrl+Alt+P open preferences dialog\n' ' Alt+H open about dialog\n' ' Double-click,\n' @@ -1223,6 +1227,117 @@ class cfgDialog(QDialog): self.reset_button.setEnabled(False) +class batchDialog(QDialog): + def __init__(self, *args, fnames=[], **kwargs): + super().__init__(*args, **kwargs) + self._abort = False + self._done = False + self.fnames = fnames + self.setAttribute(Qt.WA_DeleteOnClose) + self.setWindowTitle('Batch Processing') + self.resize(800, 700) + self.logview = QTextEdit() + self.logview.setReadOnly(True) + self.logview.setStyleSheet('QTextEdit {border: none;}') + self.statbar = QHBoxLayout() + self.proglabel = QLabel('') + self.progbar = QProgressBar() + self.progbar.resize(100, 20) + self.progbar.hide() + self.statbar.addWidget(self.proglabel) + self.statbar.addWidget(self.progbar) + self.abort_button = QPushButton('Abort') + self.abort_button.setIcon(ffIcon.close) + self.abort_button.clicked.connect(self.abort) + self.layout = QVBoxLayout(self) + self.layout.addWidget(self.logview) + self.layout.addLayout(self.statbar) + self.layout.addWidget(self.abort_button) + self.show() + self.run_batch() + self.proglabel.setText('') + self.progbar.hide() + self.abort_button.setText('Ok') + self.abort_button.setIcon(ffIcon.ok) + self.abort_button.clicked.disconnect() + self.abort_button.clicked.connect(self.accept) + + def log_append(self, *args): + sio = io.StringIO() + print(self.logview.toHtml(), *args, file=sio, end='') + self.logview.setHtml(sio.getvalue()) + sio.close() + sb = self.logview.verticalScrollBar() + sb.setValue(sb.maximum()) + + def reject(self): + if self._done: + self.accept() + else: + self.abort() + + def abort(self): + mbox = QMessageBox(self) + mbox.setWindowTitle('Abort Operation') + mbox.setIcon(QMessageBox.Warning) + mbox.setStandardButtons(QMessageBox.Yes | QMessageBox.No) + mbox.setDefaultButton(QMessageBox.No) + mbox.setText('Aborting now will likely leave you with a broken or ' + 'incomplete set of thumbnails.\n\nAbort anyway?') + if QMessageBox.Yes == mbox.exec_(): + kill_proc() + self._abort = True + + def prog_cb(self, n, tot): + if not n and not tot: + self.proglabel.setText('') + self.progbar.hide() + self.proglabel.setText('%d / %d' % (n, tot)) + self.progbar.setValue(int(n * 100 / max(0.01, tot))) + self.progbar.show() + QApplication.processEvents() + + def run_batch(self): + cnt = 0 + nfiles = len(self.fnames) + for fname in self.fnames: + self.prog_cb(0, 0) + if self._abort: + break + fname = os.path.abspath(fname) + vfile = os.path.basename(fname) + thdir = os.path.join(cfg['outdir'], vfile) + cnt += 1 + self.log_append('%d/%d:'%(cnt,nfiles), vfile) + QApplication.processEvents() + if not os.path.exists(fname) or not os.access(fname, os.R_OK): + self.log_append(' no permission\n') + continue + if os.path.isdir(fname): + self.log_append(' is a directory\n') + continue + thinfo, ok = get_thinfo(fname, thdir) + if thinfo is None: + self.log_append(' failed\n') + continue + if ok: + self.log_append(' nothing to do\n') + continue + clear_thumbdir(thdir) + thinfo, ok = make_thumbs(fname, thinfo, thdir, self.prog_cb) + if ok: + self.log_append(' ok\n') + else: + if self._abort: + clear_thumbdir(thdir) + self.log_append(' failed\n') + if self._abort: + self.log_append('

aborted

\n') + else: + self.log_append('

done

\n') + self._done = True + + class sMainWindow(QMainWindow): """ Application main window class singleton. """ _instance = None @@ -1441,6 +1556,7 @@ class sMainWindow(QMainWindow): if not (self.windowState() & (Qt.WindowFullScreen | Qt.WindowMaximized)): menu.addAction('Window Best Fit', self.optimize_geometry) menu.addAction('Thumbnail Manager', lambda: self.manage_thumbs(cfg['outdir'])) + menu.addAction('Batch Processing', self.batch_dlg) menu.addAction('Preferences', lambda: self.config_dlg()) else: if proc_running(): @@ -1565,6 +1681,7 @@ class sMainWindow(QMainWindow): QShortcut('Ctrl+Return', self).activated.connect(lambda: self.contextMenuEvent(None)) QShortcut('Ctrl+Alt+P', self).activated.connect(self.config_dlg) QShortcut('Alt+H', self).activated.connect(self.about_dlg) + QShortcut('Ctrl+B', self).activated.connect(self.batch_dlg) def show_progress(self, n, tot): @@ -1626,6 +1743,22 @@ class sMainWindow(QMainWindow): cfg['force'] = True self.load_view(self.fname) + def batch_dlg(self): + if self.view_locked: + return + self.lock_view(True) + fdir = os.path.dirname(self.fname) if self.fname else os.getcwd() + fnames, _ = QFileDialog.getOpenFileNames(self, 'Select Files for Batch Processing', + fdir, 'Video Files ('+ cfg['vformats'] +');;All Files (*)', + options=QFileDialog.Options()|QFileDialog.DontUseNativeDialog) + if len(fnames) < 1: + self.lock_view(False) + return + dlg = batchDialog(self, fnames=fnames) + res = dlg.exec_() + cfg['force'] = False + self.lock_view(False) + def load_view(self, fname): self.lock_view(True) # sanitize file name