From 675a06dd4c10babb3ef2553f6c7cdd92b5f5ef0a Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 25 Jun 2017 14:27:56 -0400 Subject: project files save settings & out/in fields --- src/command.py | 6 ++--- src/components/image.py | 4 +-- src/components/video.py | 8 +++--- src/core.py | 71 ++++++++++++++++++++++++++++++++++++++++++------- src/mainwindow.py | 30 +++++++++++++++------ src/presetmanager.py | 4 +-- 6 files changed, 94 insertions(+), 29 deletions(-) diff --git a/src/command.py b/src/command.py index 2f71f31..b400773 100644 --- a/src/command.py +++ b/src/command.py @@ -1,5 +1,4 @@ -from PyQt4 import QtCore -from PyQt4.QtCore import QSettings +from PyQt5 import QtCore import argparse import os import sys @@ -43,8 +42,7 @@ class Command(QtCore.QObject): nargs='*', action='append') self.args = self.parser.parse_args() - self.settings = QSettings( - os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat) + self.settings = self.core.settings LoadDefaultSettings(self) if self.args.projpath: diff --git a/src/components/image.py b/src/components/image.py index 143ae59..4bb33b1 100644 --- a/src/components/image.py +++ b/src/components/image.py @@ -83,12 +83,12 @@ class Component(__base__.Component): } def pickImage(self): - imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) + imgDir = self.settings.value("componentDir", os.path.expanduser("~")) filename, _ = QtWidgets.QFileDialog.getOpenFileName( self.page, "Choose Image", imgDir, "Image Files (%s)" % " ".join(self.imageFormats)) if filename: - self.settings.setValue("backgroundDir", os.path.dirname(filename)) + self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_image.setText(filename) self.update() diff --git a/src/components/video.py b/src/components/video.py index 44f88a5..d37dd99 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -88,8 +88,8 @@ class Video: self.parent.showMessage( msg='%s couldn\'t be loaded. ' 'This is a fatal error.' % os.path.basename( - self.videoPath - ), + self.videoPath + ), detail=str(e) ) self.parent.stopVideo() @@ -188,13 +188,13 @@ class Component(__base__.Component): } def pickVideo(self): - imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) + imgDir = self.settings.value("componentDir", os.path.expanduser("~")) filename, _ = QtWidgets.QFileDialog.getOpenFileName( self.page, "Choose Video", imgDir, "Video Files (%s)" % " ".join(self.videoFormats) ) if filename: - self.settings.setValue("backgroundDir", os.path.dirname(filename)) + self.settings.setValue("componentDir", os.path.dirname(filename)) self.page.lineEdit_video.setText(filename) self.update() diff --git a/src/core.py b/src/core.py index fdba1c4..d7e8219 100644 --- a/src/core.py +++ b/src/core.py @@ -30,6 +30,10 @@ class Core(): # unfrozen self.wd = os.path.dirname(os.path.realpath(__file__)) self.componentsPath = os.path.join(self.wd, 'components') + self.settings = QtCore.QSettings( + os.path.join(self.dataDir, 'settings.ini'), + QtCore.QSettings.IniFormat + ) self.loadEncoderOptions() self.videoFormats = Core.appendUppercase([ @@ -169,13 +173,23 @@ class Core(): its own showMessage(**kwargs) method for displaying errors. ''' if not os.path.exists(filepath): - loader.showMessage(msg='Project file not found') + loader.showMessage(msg='Project file not found.') return errcode, data = self.parseAvFile(filepath) if errcode == 0: try: - for i, tup in enumerate(data['Components']): + if hasattr(loader, 'window'): + for pair in data['WindowFields']: + widget, value = pair.split('=', 1) + widget = eval('loader.window.%s' % widget) + widget.setText(value.strip()) + + for pair in data['Settings']: + key, value = pair.split('=', 1) + self.settings.setValue(key, value.strip()) + + for tup in data['Components']: name, vers, preset = tup clearThis = False modified = False @@ -213,7 +227,7 @@ class Core(): preset['preset'] ) except KeyError as e: - print('%s missing value %s' % ( + print('%s missing value: %s' % ( self.selectedComponents[i], e) ) @@ -221,23 +235,26 @@ class Core(): self.clearPreset(i) if hasattr(loader, 'updateComponentTitle'): loader.updateComponentTitle(i, modified) + except: errcode = 1 data = sys.exc_info() if errcode == 1: - typ, value, _ = data - if typ.__name__ == KeyError: + typ, value, tb = data + if typ.__name__ == 'KeyError': # probably just an old version, still loadable print('file missing value: %s' % value) return if hasattr(loader, 'createNewProject'): loader.createNewProject() - msg = '%s: %s' % (typ.__name__, value) + import traceback + msg = '%s: %s\n\nTraceback:\n' % (typ.__name__, value) + msg += "\n".join(traceback.format_tb(tb)) loader.showMessage( msg="Project file '%s' is corrupted." % filepath, showCancel=False, - icon=QtGui.QMessageBox.Warning, + icon='Warning', detail=msg) def parseAvFile(self, filepath): @@ -250,7 +267,11 @@ class Core(): with open(filepath, 'r') as f: def parseLine(line): '''Decides if a file line is a section header''' - validSections = ('Components') + validSections = ( + 'Components', + 'Settings', + 'WindowFields' + ) line = line.strip() newSection = '' @@ -283,6 +304,8 @@ class Core(): lastCompPreset )) i = 0 + elif line and section: + data[section].append(line) return 0, data except: return 1, sys.exc_info() @@ -354,8 +377,22 @@ class Core(): f.write('%s\n' % str(vers)) f.write(Core.presetToString(saveValueStore)) - def createProjectFile(self, filepath): + def createProjectFile(self, filepath, window=None): '''Create a project file (.avp) using the current program state''' + forbiddenSettingsKeys = [ + 'currentProject', + 'outputAudioBitrate', + 'outputAudioCodec', + 'outputContainer', + 'outputFormat', + 'outputFrameRate', + 'outputHeight', + 'outputPreset', + 'outputVideoBitrate', + 'outputVideoCodec', + 'outputVideoFormat', + 'outputWidth', + ] try: if not filepath.endswith(".avp"): filepath += '.avp' @@ -363,12 +400,28 @@ class Core(): os.remove(filepath) with open(filepath, 'w') as f: print('creating %s' % filepath) + f.write('[Components]\n') for comp in self.selectedComponents: saveValueStore = comp.savePreset() f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp.version())) f.write('%s\n' % Core.presetToString(saveValueStore)) + + f.write('[Settings]\n') + for key in self.settings.allKeys(): + if key not in forbiddenSettingsKeys: + f.write('%s=%s\n' % (key, self.settings.value(key))) + + if window: + f.write('[WindowFields]\n') + f.write( + 'lineEdit_audioFile=%s\n' + 'lineEdit_outputFile=%s\n' % ( + window.lineEdit_audioFile.text(), + window.lineEdit_outputFile.text() + ) + ) return True except: return False diff --git a/src/mainwindow.py b/src/mainwindow.py index 76c2b62..e4e4f38 100644 --- a/src/mainwindow.py +++ b/src/mainwindow.py @@ -1,6 +1,5 @@ from queue import Queue from PyQt5 import QtCore, QtGui, uic, QtWidgets -from PyQt5.QtCore import QSettings, Qt from PyQt5.QtWidgets import QMenu, QShortcut import sys import os @@ -27,7 +26,9 @@ class PreviewWindow(QtWidgets.QLabel): painter = QtGui.QPainter(self) point = QtCore.QPoint(0, 0) scaledPix = self.pixmap.scaled( - size, Qt.KeepAspectRatio, transformMode=Qt.SmoothTransformation) + size, + QtCore.Qt.KeepAspectRatio, + transformMode=QtCore.Qt.SmoothTransformation) # start painting the label from left upper corner point.setX((size.width() - scaledPix.width())/2) @@ -59,8 +60,7 @@ class MainWindow(QtWidgets.QMainWindow): # Create data directory, load/create settings self.dataDir = self.core.dataDir self.autosavePath = os.path.join(self.dataDir, 'autosave.avp') - self.settings = QSettings( - os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat) + self.settings = self.core.settings LoadDefaultSettings(self) self.presetManager = PresetManager( uic.loadUi( @@ -94,6 +94,13 @@ class MainWindow(QtWidgets.QMainWindow): window.toolButton_selectOutputFile.clicked.connect( self.openOutputFileDialog) + def changedField(): + self.autosave() + self.updateWindowTitle() + + window.lineEdit_audioFile.textChanged.connect(changedField) + window.lineEdit_outputFile.textChanged.connect(changedField) + window.progressBar_createVideo.setValue(0) window.pushButton_createVideo.clicked.connect( @@ -359,7 +366,7 @@ class MainWindow(QtWidgets.QMainWindow): if os.path.exists(self.autosavePath): os.remove(self.autosavePath) elif force or time.time() - self.lastAutosave >= 0.1: - self.core.createProjectFile(self.autosavePath) + self.core.createProjectFile(self.autosavePath, self.window) self.lastAutosave = time.time() def autosaveExists(self, identical=True): @@ -625,6 +632,13 @@ class MainWindow(QtWidgets.QMainWindow): for widget in self.pages: self.window.stackedWidget.removeWidget(widget) self.pages = [] + for field in ( + self.window.lineEdit_audioFile, + self.window.lineEdit_outputFile + ): + field.blockSignals(True) + field.setText('') + field.blockSignals(False) @disableWhenEncoding def createNewProject(self): @@ -637,7 +651,7 @@ class MainWindow(QtWidgets.QMainWindow): def saveCurrentProject(self): if self.currentProject: - self.core.createProjectFile(self.currentProject) + self.core.createProjectFile(self.currentProject, self.window) self.updateWindowTitle() else: self.openSaveProjectDialog() @@ -670,7 +684,7 @@ class MainWindow(QtWidgets.QMainWindow): self.settings.setValue("projectDir", os.path.dirname(filename)) self.settings.setValue("currentProject", filename) self.currentProject = filename - self.core.createProjectFile(filename) + self.core.createProjectFile(filename, self.window) self.updateWindowTitle() @disableWhenEncoding @@ -707,7 +721,7 @@ class MainWindow(QtWidgets.QMainWindow): msg.setModal(True) msg.setText(kwargs['msg']) msg.setIcon( - kwargs['icon'] + eval('QtWidgets.QMessageBox.%s' % kwargs['icon']) if 'icon' in kwargs else QtWidgets.QMessageBox.Information ) msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None) diff --git a/src/presetmanager.py b/src/presetmanager.py index 069bf62..3ab49ef 100644 --- a/src/presetmanager.py +++ b/src/presetmanager.py @@ -176,7 +176,7 @@ class PresetManager(QtWidgets.QDialog): msg="%s already exists! Overwrite it?" % os.path.basename(path), showCancel=True, - icon=QtWidgets.QMessageBox.Warning, + icon='Warning', parent=window) if not ch: # user clicked cancel @@ -209,7 +209,7 @@ class PresetManager(QtWidgets.QDialog): ch = self.parent.showMessage( msg='Really delete %s?' % name, showCancel=True, - icon=QtWidgets.QMessageBox.Warning, + icon='Warning', parent=self.window ) if not ch: -- cgit v1.2.3 From 6a1a5cd6eb931f5f9316f89c680ca318f845a746 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 25 Jun 2017 15:31:42 -0400 Subject: --export commandline option overrides -i and -o to use saved fields from a project file --- src/command.py | 48 +++++++++++++++++++++++++++++++++++++++--------- src/components/video.py | 3 ++- src/core.py | 2 ++ src/mainwindow.py | 7 +++++-- src/preview_thread.py | 3 ++- 5 files changed, 50 insertions(+), 13 deletions(-) diff --git a/src/command.py b/src/command.py index b400773..09b54ac 100644 --- a/src/command.py +++ b/src/command.py @@ -23,13 +23,20 @@ class Command(QtCore.QObject): epilog='EXAMPLE COMMAND: main.py myvideotemplate.avp ' '-i ~/Music/song.mp3 -o ~/video.mp4 ' '-c 0 image path=~/Pictures/thisWeeksPicture.jpg ' - '-c 1 video "preset=My Logo" -c 2 vis layout=classic') + '-c 1 video "preset=My Logo" -c 2 vis layout=classic' + ) self.parser.add_argument( '-i', '--input', metavar='SOUND', - help='input audio file') + help='input audio file' + ) self.parser.add_argument( '-o', '--output', metavar='OUTPUT', - help='output video file') + help='output video file' + ) + self.parser.add_argument( + '-e', '--export', action='store_true', + help='use input and output files from project file' + ) # optional arguments self.parser.add_argument( @@ -46,7 +53,15 @@ class Command(QtCore.QObject): LoadDefaultSettings(self) if self.args.projpath: - self.core.openProject(self, self.args.projpath) + projPath = self.args.projpath + if not os.path.dirname(projPath): + projPath = os.path.join( + self.settings.value("projectDir"), + projPath + ) + if not projPath.endswith('.avp'): + projPath += '.avp' + self.core.openProject(self, projPath) self.core.selectedComponents = list( reversed(self.core.selectedComponents)) self.core.componentListChanged() @@ -70,13 +85,28 @@ class Command(QtCore.QObject): for arg in args: self.core.selectedComponents[i].command(arg) - if self.args.input and self.args.output: - self.createAudioVisualisation() + if self.args.export and self.args.projpath: + errcode, data = self.core.parseAvFile(projPath) + for line in data['WindowFields']: + if 'outputFile' in line: + output = line.split('=', 1)[1] + if not os.path.dirname(output): + output = os.path.join( + os.path.expanduser('~'), + output + ) + if 'audioFile' in line: + input = line.split('=', 1)[1] + self.createAudioVisualisation(input, output) + + elif self.args.input and self.args.output: + self.createAudioVisualisation(self.args.input, self.args.output) + elif 'help' not in sys.argv: self.parser.print_help() quit(1) - def createAudioVisualisation(self): + def createAudioVisualisation(self, input, output): self.videoThread = QtCore.QThread(self) self.videoWorker = video_thread.Worker(self) self.videoWorker.moveToThread(self.videoThread) @@ -84,8 +114,8 @@ class Command(QtCore.QObject): self.videoThread.start() self.videoTask.emit( - self.args.input, - self.args.output, + input, + output, list(reversed(self.core.selectedComponents)) ) diff --git a/src/components/video.py b/src/components/video.py index d37dd99..02bb44b 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -90,7 +90,8 @@ class Video: 'This is a fatal error.' % os.path.basename( self.videoPath ), - detail=str(e) + detail=str(e), + icon='Warning' ) self.parent.stopVideo() break diff --git a/src/core.py b/src/core.py index d7e8219..a435c2c 100644 --- a/src/core.py +++ b/src/core.py @@ -183,7 +183,9 @@ class Core(): for pair in data['WindowFields']: widget, value = pair.split('=', 1) widget = eval('loader.window.%s' % widget) + widget.blockSignals(True) widget.setText(value.strip()) + widget.blockSignals(False) for pair in data['Settings']: key, value = pair.split('=', 1) diff --git a/src/mainwindow.py b/src/mainwindow.py index e4e4f38..203992b 100644 --- a/src/mainwindow.py +++ b/src/mainwindow.py @@ -229,7 +229,9 @@ class MainWindow(QtWidgets.QMainWindow): project += '.avp' # open a project from the commandline if not os.path.dirname(project): - project = os.path.join(os.path.expanduser('~'), project) + project = os.path.join( + self.settings.value("projectDir"), project + ) self.currentProject = project self.settings.setValue("currentProject", project) if os.path.exists(self.autosavePath): @@ -433,7 +435,8 @@ class MainWindow(QtWidgets.QMainWindow): self.showMessage( msg='Chosen filename matches a directory, which ' 'cannot be overwritten. Please choose a different ' - 'filename or move the directory.' + 'filename or move the directory.', + icon='Warning', ) return else: diff --git a/src/preview_thread.py b/src/preview_thread.py index 769656b..e58f04e 100644 --- a/src/preview_thread.py +++ b/src/preview_thread.py @@ -58,7 +58,8 @@ class Worker(QtCore.QObject): msg="Bad frame returned by %s's previewRender method. " "This is a fatal error." % str(component), - detail=str(e) + detail=str(e), + icon='Warning' ) quit(1) -- cgit v1.2.3 From fc2951379c418086bcc00af2b8901f92eafc224a Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 25 Jun 2017 15:34:33 -0400 Subject: newlines make project file easier to read --- src/core.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core.py b/src/core.py index a435c2c..341aa01 100644 --- a/src/core.py +++ b/src/core.py @@ -410,13 +410,13 @@ class Core(): f.write('%s\n' % str(comp.version())) f.write('%s\n' % Core.presetToString(saveValueStore)) - f.write('[Settings]\n') + f.write('\n[Settings]\n') for key in self.settings.allKeys(): if key not in forbiddenSettingsKeys: f.write('%s=%s\n' % (key, self.settings.value(key))) if window: - f.write('[WindowFields]\n') + f.write('\n[WindowFields]\n') f.write( 'lineEdit_audioFile=%s\n' 'lineEdit_outputFile=%s\n' % ( -- cgit v1.2.3 From 2c82a65d1b79b898b2bc27fc5b1e0362fc160c46 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 25 Jun 2017 15:50:31 -0400 Subject: needs more tuples --- src/command.py | 12 ++++++------ src/core.py | 27 +++++++++++++-------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/src/command.py b/src/command.py index 09b54ac..3eea1b6 100644 --- a/src/command.py +++ b/src/command.py @@ -87,16 +87,16 @@ class Command(QtCore.QObject): if self.args.export and self.args.projpath: errcode, data = self.core.parseAvFile(projPath) - for line in data['WindowFields']: - if 'outputFile' in line: - output = line.split('=', 1)[1] - if not os.path.dirname(output): + for key, value in data['WindowFields']: + if 'outputFile' in key: + output = value + if not os.path.dirname(value): output = os.path.join( os.path.expanduser('~'), output ) - if 'audioFile' in line: - input = line.split('=', 1)[1] + if 'audioFile' in key: + input = value self.createAudioVisualisation(input, output) elif self.args.input and self.args.output: diff --git a/src/core.py b/src/core.py index 341aa01..2994a24 100644 --- a/src/core.py +++ b/src/core.py @@ -180,16 +180,14 @@ class Core(): if errcode == 0: try: if hasattr(loader, 'window'): - for pair in data['WindowFields']: - widget, value = pair.split('=', 1) + for widget, value in data['WindowFields']: widget = eval('loader.window.%s' % widget) widget.blockSignals(True) - widget.setText(value.strip()) + widget.setText(value) widget.blockSignals(False) - for pair in data['Settings']: - key, value = pair.split('=', 1) - self.settings.setValue(key, value.strip()) + for key, value in data['Settings']: + self.settings.setValue(key, value) for tup in data['Components']: name, vers, preset = tup @@ -264,16 +262,16 @@ class Core(): Returns dictionary with section names as the keys, each one contains a list of tuples: (compName, version, compPresetDict) ''' - data = {} + validSections = ( + 'Components', + 'Settings', + 'WindowFields' + ) + data = {sect: [] for sect in validSections} try: with open(filepath, 'r') as f: def parseLine(line): '''Decides if a file line is a section header''' - validSections = ( - 'Components', - 'Settings', - 'WindowFields' - ) line = line.strip() newSection = '' @@ -289,7 +287,6 @@ class Core(): line, newSection = parseLine(line) if newSection: section = str(newSection) - data[section] = [] continue if line and section == 'Components': if i == 0: @@ -307,7 +304,9 @@ class Core(): )) i = 0 elif line and section: - data[section].append(line) + key, value = line.split('=', 1) + data[section].append((key, value.strip())) + return 0, data except: return 1, sys.exc_info() -- cgit v1.2.3