Merge pull request #36 from djfun/newgui-project-settings

Project files save more settings
This commit is contained in:
Brianna 2017-06-25 15:53:49 -04:00 committed by GitHub
commit f86c33d0e5
7 changed files with 145 additions and 44 deletions

View File

@ -1,5 +1,4 @@
from PyQt4 import QtCore from PyQt5 import QtCore
from PyQt4.QtCore import QSettings
import argparse import argparse
import os import os
import sys import sys
@ -24,13 +23,20 @@ class Command(QtCore.QObject):
epilog='EXAMPLE COMMAND: main.py myvideotemplate.avp ' epilog='EXAMPLE COMMAND: main.py myvideotemplate.avp '
'-i ~/Music/song.mp3 -o ~/video.mp4 ' '-i ~/Music/song.mp3 -o ~/video.mp4 '
'-c 0 image path=~/Pictures/thisWeeksPicture.jpg ' '-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( self.parser.add_argument(
'-i', '--input', metavar='SOUND', '-i', '--input', metavar='SOUND',
help='input audio file') help='input audio file'
)
self.parser.add_argument( self.parser.add_argument(
'-o', '--output', metavar='OUTPUT', '-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 # optional arguments
self.parser.add_argument( self.parser.add_argument(
@ -43,12 +49,19 @@ class Command(QtCore.QObject):
nargs='*', action='append') nargs='*', action='append')
self.args = self.parser.parse_args() self.args = self.parser.parse_args()
self.settings = QSettings( self.settings = self.core.settings
os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
LoadDefaultSettings(self) LoadDefaultSettings(self)
if self.args.projpath: 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( self.core.selectedComponents = list(
reversed(self.core.selectedComponents)) reversed(self.core.selectedComponents))
self.core.componentListChanged() self.core.componentListChanged()
@ -72,13 +85,28 @@ class Command(QtCore.QObject):
for arg in args: for arg in args:
self.core.selectedComponents[i].command(arg) self.core.selectedComponents[i].command(arg)
if self.args.input and self.args.output: if self.args.export and self.args.projpath:
self.createAudioVisualisation() errcode, data = self.core.parseAvFile(projPath)
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 key:
input = value
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: elif 'help' not in sys.argv:
self.parser.print_help() self.parser.print_help()
quit(1) quit(1)
def createAudioVisualisation(self): def createAudioVisualisation(self, input, output):
self.videoThread = QtCore.QThread(self) self.videoThread = QtCore.QThread(self)
self.videoWorker = video_thread.Worker(self) self.videoWorker = video_thread.Worker(self)
self.videoWorker.moveToThread(self.videoThread) self.videoWorker.moveToThread(self.videoThread)
@ -86,8 +114,8 @@ class Command(QtCore.QObject):
self.videoThread.start() self.videoThread.start()
self.videoTask.emit( self.videoTask.emit(
self.args.input, input,
self.args.output, output,
list(reversed(self.core.selectedComponents)) list(reversed(self.core.selectedComponents))
) )

View File

@ -83,12 +83,12 @@ class Component(__base__.Component):
} }
def pickImage(self): def pickImage(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) imgDir = self.settings.value("componentDir", os.path.expanduser("~"))
filename, _ = QtWidgets.QFileDialog.getOpenFileName( filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self.page, "Choose Image", imgDir, self.page, "Choose Image", imgDir,
"Image Files (%s)" % " ".join(self.imageFormats)) "Image Files (%s)" % " ".join(self.imageFormats))
if filename: 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.page.lineEdit_image.setText(filename)
self.update() self.update()

View File

@ -88,9 +88,10 @@ class Video:
self.parent.showMessage( self.parent.showMessage(
msg='%s couldn\'t be loaded. ' msg='%s couldn\'t be loaded. '
'This is a fatal error.' % os.path.basename( 'This is a fatal error.' % os.path.basename(
self.videoPath self.videoPath
), ),
detail=str(e) detail=str(e),
icon='Warning'
) )
self.parent.stopVideo() self.parent.stopVideo()
break break
@ -188,13 +189,13 @@ class Component(__base__.Component):
} }
def pickVideo(self): def pickVideo(self):
imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) imgDir = self.settings.value("componentDir", os.path.expanduser("~"))
filename, _ = QtWidgets.QFileDialog.getOpenFileName( filename, _ = QtWidgets.QFileDialog.getOpenFileName(
self.page, "Choose Video", self.page, "Choose Video",
imgDir, "Video Files (%s)" % " ".join(self.videoFormats) imgDir, "Video Files (%s)" % " ".join(self.videoFormats)
) )
if filename: 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.page.lineEdit_video.setText(filename)
self.update() self.update()

View File

@ -30,6 +30,10 @@ class Core():
# unfrozen # unfrozen
self.wd = os.path.dirname(os.path.realpath(__file__)) self.wd = os.path.dirname(os.path.realpath(__file__))
self.componentsPath = os.path.join(self.wd, 'components') 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.loadEncoderOptions()
self.videoFormats = Core.appendUppercase([ self.videoFormats = Core.appendUppercase([
@ -169,13 +173,23 @@ class Core():
its own showMessage(**kwargs) method for displaying errors. its own showMessage(**kwargs) method for displaying errors.
''' '''
if not os.path.exists(filepath): if not os.path.exists(filepath):
loader.showMessage(msg='Project file not found') loader.showMessage(msg='Project file not found.')
return return
errcode, data = self.parseAvFile(filepath) errcode, data = self.parseAvFile(filepath)
if errcode == 0: if errcode == 0:
try: try:
for i, tup in enumerate(data['Components']): if hasattr(loader, 'window'):
for widget, value in data['WindowFields']:
widget = eval('loader.window.%s' % widget)
widget.blockSignals(True)
widget.setText(value)
widget.blockSignals(False)
for key, value in data['Settings']:
self.settings.setValue(key, value)
for tup in data['Components']:
name, vers, preset = tup name, vers, preset = tup
clearThis = False clearThis = False
modified = False modified = False
@ -213,7 +227,7 @@ class Core():
preset['preset'] preset['preset']
) )
except KeyError as e: except KeyError as e:
print('%s missing value %s' % ( print('%s missing value: %s' % (
self.selectedComponents[i], e) self.selectedComponents[i], e)
) )
@ -221,23 +235,26 @@ class Core():
self.clearPreset(i) self.clearPreset(i)
if hasattr(loader, 'updateComponentTitle'): if hasattr(loader, 'updateComponentTitle'):
loader.updateComponentTitle(i, modified) loader.updateComponentTitle(i, modified)
except: except:
errcode = 1 errcode = 1
data = sys.exc_info() data = sys.exc_info()
if errcode == 1: if errcode == 1:
typ, value, _ = data typ, value, tb = data
if typ.__name__ == KeyError: if typ.__name__ == 'KeyError':
# probably just an old version, still loadable # probably just an old version, still loadable
print('file missing value: %s' % value) print('file missing value: %s' % value)
return return
if hasattr(loader, 'createNewProject'): if hasattr(loader, 'createNewProject'):
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( loader.showMessage(
msg="Project file '%s' is corrupted." % filepath, msg="Project file '%s' is corrupted." % filepath,
showCancel=False, showCancel=False,
icon=QtGui.QMessageBox.Warning, icon='Warning',
detail=msg) detail=msg)
def parseAvFile(self, filepath): def parseAvFile(self, filepath):
@ -245,12 +262,16 @@ class Core():
Returns dictionary with section names as the keys, each one Returns dictionary with section names as the keys, each one
contains a list of tuples: (compName, version, compPresetDict) contains a list of tuples: (compName, version, compPresetDict)
''' '''
data = {} validSections = (
'Components',
'Settings',
'WindowFields'
)
data = {sect: [] for sect in validSections}
try: try:
with open(filepath, 'r') as f: with open(filepath, 'r') as f:
def parseLine(line): def parseLine(line):
'''Decides if a file line is a section header''' '''Decides if a file line is a section header'''
validSections = ('Components')
line = line.strip() line = line.strip()
newSection = '' newSection = ''
@ -266,7 +287,6 @@ class Core():
line, newSection = parseLine(line) line, newSection = parseLine(line)
if newSection: if newSection:
section = str(newSection) section = str(newSection)
data[section] = []
continue continue
if line and section == 'Components': if line and section == 'Components':
if i == 0: if i == 0:
@ -283,6 +303,10 @@ class Core():
lastCompPreset lastCompPreset
)) ))
i = 0 i = 0
elif line and section:
key, value = line.split('=', 1)
data[section].append((key, value.strip()))
return 0, data return 0, data
except: except:
return 1, sys.exc_info() return 1, sys.exc_info()
@ -354,8 +378,22 @@ class Core():
f.write('%s\n' % str(vers)) f.write('%s\n' % str(vers))
f.write(Core.presetToString(saveValueStore)) 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''' '''Create a project file (.avp) using the current program state'''
forbiddenSettingsKeys = [
'currentProject',
'outputAudioBitrate',
'outputAudioCodec',
'outputContainer',
'outputFormat',
'outputFrameRate',
'outputHeight',
'outputPreset',
'outputVideoBitrate',
'outputVideoCodec',
'outputVideoFormat',
'outputWidth',
]
try: try:
if not filepath.endswith(".avp"): if not filepath.endswith(".avp"):
filepath += '.avp' filepath += '.avp'
@ -363,12 +401,28 @@ class Core():
os.remove(filepath) os.remove(filepath)
with open(filepath, 'w') as f: with open(filepath, 'w') as f:
print('creating %s' % filepath) print('creating %s' % filepath)
f.write('[Components]\n') f.write('[Components]\n')
for comp in self.selectedComponents: for comp in self.selectedComponents:
saveValueStore = comp.savePreset() saveValueStore = comp.savePreset()
f.write('%s\n' % str(comp)) f.write('%s\n' % str(comp))
f.write('%s\n' % str(comp.version())) f.write('%s\n' % str(comp.version()))
f.write('%s\n' % Core.presetToString(saveValueStore)) f.write('%s\n' % Core.presetToString(saveValueStore))
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('\n[WindowFields]\n')
f.write(
'lineEdit_audioFile=%s\n'
'lineEdit_outputFile=%s\n' % (
window.lineEdit_audioFile.text(),
window.lineEdit_outputFile.text()
)
)
return True return True
except: except:
return False return False

View File

@ -1,6 +1,5 @@
from queue import Queue from queue import Queue
from PyQt5 import QtCore, QtGui, uic, QtWidgets from PyQt5 import QtCore, QtGui, uic, QtWidgets
from PyQt5.QtCore import QSettings, Qt
from PyQt5.QtWidgets import QMenu, QShortcut from PyQt5.QtWidgets import QMenu, QShortcut
import sys import sys
import os import os
@ -27,7 +26,9 @@ class PreviewWindow(QtWidgets.QLabel):
painter = QtGui.QPainter(self) painter = QtGui.QPainter(self)
point = QtCore.QPoint(0, 0) point = QtCore.QPoint(0, 0)
scaledPix = self.pixmap.scaled( 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 # start painting the label from left upper corner
point.setX((size.width() - scaledPix.width())/2) point.setX((size.width() - scaledPix.width())/2)
@ -59,8 +60,7 @@ class MainWindow(QtWidgets.QMainWindow):
# Create data directory, load/create settings # Create data directory, load/create settings
self.dataDir = self.core.dataDir self.dataDir = self.core.dataDir
self.autosavePath = os.path.join(self.dataDir, 'autosave.avp') self.autosavePath = os.path.join(self.dataDir, 'autosave.avp')
self.settings = QSettings( self.settings = self.core.settings
os.path.join(self.dataDir, 'settings.ini'), QSettings.IniFormat)
LoadDefaultSettings(self) LoadDefaultSettings(self)
self.presetManager = PresetManager( self.presetManager = PresetManager(
uic.loadUi( uic.loadUi(
@ -94,6 +94,13 @@ class MainWindow(QtWidgets.QMainWindow):
window.toolButton_selectOutputFile.clicked.connect( window.toolButton_selectOutputFile.clicked.connect(
self.openOutputFileDialog) 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.progressBar_createVideo.setValue(0)
window.pushButton_createVideo.clicked.connect( window.pushButton_createVideo.clicked.connect(
@ -222,7 +229,9 @@ class MainWindow(QtWidgets.QMainWindow):
project += '.avp' project += '.avp'
# open a project from the commandline # open a project from the commandline
if not os.path.dirname(project): 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.currentProject = project
self.settings.setValue("currentProject", project) self.settings.setValue("currentProject", project)
if os.path.exists(self.autosavePath): if os.path.exists(self.autosavePath):
@ -359,7 +368,7 @@ class MainWindow(QtWidgets.QMainWindow):
if os.path.exists(self.autosavePath): if os.path.exists(self.autosavePath):
os.remove(self.autosavePath) os.remove(self.autosavePath)
elif force or time.time() - self.lastAutosave >= 0.1: 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() self.lastAutosave = time.time()
def autosaveExists(self, identical=True): def autosaveExists(self, identical=True):
@ -426,7 +435,8 @@ class MainWindow(QtWidgets.QMainWindow):
self.showMessage( self.showMessage(
msg='Chosen filename matches a directory, which ' msg='Chosen filename matches a directory, which '
'cannot be overwritten. Please choose a different ' 'cannot be overwritten. Please choose a different '
'filename or move the directory.' 'filename or move the directory.',
icon='Warning',
) )
return return
else: else:
@ -625,6 +635,13 @@ class MainWindow(QtWidgets.QMainWindow):
for widget in self.pages: for widget in self.pages:
self.window.stackedWidget.removeWidget(widget) self.window.stackedWidget.removeWidget(widget)
self.pages = [] self.pages = []
for field in (
self.window.lineEdit_audioFile,
self.window.lineEdit_outputFile
):
field.blockSignals(True)
field.setText('')
field.blockSignals(False)
@disableWhenEncoding @disableWhenEncoding
def createNewProject(self): def createNewProject(self):
@ -637,7 +654,7 @@ class MainWindow(QtWidgets.QMainWindow):
def saveCurrentProject(self): def saveCurrentProject(self):
if self.currentProject: if self.currentProject:
self.core.createProjectFile(self.currentProject) self.core.createProjectFile(self.currentProject, self.window)
self.updateWindowTitle() self.updateWindowTitle()
else: else:
self.openSaveProjectDialog() self.openSaveProjectDialog()
@ -670,7 +687,7 @@ class MainWindow(QtWidgets.QMainWindow):
self.settings.setValue("projectDir", os.path.dirname(filename)) self.settings.setValue("projectDir", os.path.dirname(filename))
self.settings.setValue("currentProject", filename) self.settings.setValue("currentProject", filename)
self.currentProject = filename self.currentProject = filename
self.core.createProjectFile(filename) self.core.createProjectFile(filename, self.window)
self.updateWindowTitle() self.updateWindowTitle()
@disableWhenEncoding @disableWhenEncoding
@ -707,7 +724,7 @@ class MainWindow(QtWidgets.QMainWindow):
msg.setModal(True) msg.setModal(True)
msg.setText(kwargs['msg']) msg.setText(kwargs['msg'])
msg.setIcon( msg.setIcon(
kwargs['icon'] eval('QtWidgets.QMessageBox.%s' % kwargs['icon'])
if 'icon' in kwargs else QtWidgets.QMessageBox.Information if 'icon' in kwargs else QtWidgets.QMessageBox.Information
) )
msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None) msg.setDetailedText(kwargs['detail'] if 'detail' in kwargs else None)

View File

@ -176,7 +176,7 @@ class PresetManager(QtWidgets.QDialog):
msg="%s already exists! Overwrite it?" % msg="%s already exists! Overwrite it?" %
os.path.basename(path), os.path.basename(path),
showCancel=True, showCancel=True,
icon=QtWidgets.QMessageBox.Warning, icon='Warning',
parent=window) parent=window)
if not ch: if not ch:
# user clicked cancel # user clicked cancel
@ -209,7 +209,7 @@ class PresetManager(QtWidgets.QDialog):
ch = self.parent.showMessage( ch = self.parent.showMessage(
msg='Really delete %s?' % name, msg='Really delete %s?' % name,
showCancel=True, showCancel=True,
icon=QtWidgets.QMessageBox.Warning, icon='Warning',
parent=self.window parent=self.window
) )
if not ch: if not ch:

View File

@ -58,7 +58,8 @@ class Worker(QtCore.QObject):
msg="Bad frame returned by %s's previewRender method. " msg="Bad frame returned by %s's previewRender method. "
"This is a fatal error." % "This is a fatal error." %
str(component), str(component),
detail=str(e) detail=str(e),
icon='Warning'
) )
quit(1) quit(1)