From 39e66ffa2d07b87b57ed90b369ab26aedf0a69e8 Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 4 Jun 2017 13:00:36 -0400 Subject: video component almost working, rm hardcoded backgrounds --- main.py | 50 ++++++++++++++++---------------------------------- 1 file changed, 16 insertions(+), 34 deletions(-) (limited to 'main.py') diff --git a/main.py b/main.py index 2aa7fa9..da72b1e 100644 --- a/main.py +++ b/main.py @@ -133,9 +133,9 @@ class PreviewWindow(QtGui.QLabel): class Main(QtCore.QObject): - newTask = QtCore.pyqtSignal(str, list) + newTask = QtCore.pyqtSignal(list) processTask = QtCore.pyqtSignal() - videoTask = QtCore.pyqtSignal(str, str, str, list) + videoTask = QtCore.pyqtSignal(str, str, list) def __init__(self, window): QtCore.QObject.__init__(self) @@ -172,14 +172,13 @@ class Main(QtCore.QObject): # begin decorating the window and connecting events window.toolButton_selectAudioFile.clicked.connect(self.openInputFileDialog) - window.toolButton_selectBackground.clicked.connect(self.openBackgroundFileDialog) window.toolButton_selectOutputFile.clicked.connect(self.openOutputFileDialog) window.progressBar_createVideo.setValue(0) window.pushButton_createVideo.clicked.connect(self.createAudioVisualisation) window.pushButton_Cancel.clicked.connect(self.stopVideo) window.setWindowTitle("Audio Visualizer") - self.previewWindow = PreviewWindow(self, os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.jpg")) + self.previewWindow = PreviewWindow(self, os.path.join(os.path.dirname(os.path.realpath(__file__)), "background.png")) window.verticalLayout_previewWrapper.addWidget(self.previewWindow) self.modules = self.findComponents() @@ -260,17 +259,6 @@ class Main(QtCore.QObject): self.settings.setValue("outputDir", os.path.dirname(fileName)) self.window.lineEdit_outputFile.setText(fileName) - def openBackgroundFileDialog(self): - backgroundDir = self.settings.value("backgroundDir", expanduser("~")) - - fileName = QtGui.QFileDialog.getOpenFileName(self.window, - "Open Background Image", backgroundDir, "Image Files (*.jpg *.png);; Video Files (*.mp4)"); - - if not fileName == "": - self.settings.setValue("backgroundDir", os.path.dirname(fileName)) - self.window.lineEdit_background.setText(fileName) - self.drawPreview() - def stopVideo(self): print('stop') self.videoWorker.cancel() @@ -291,8 +279,7 @@ class Main(QtCore.QObject): self.videoWorker.imageCreated.connect(self.showPreviewImage) self.videoWorker.encoding.connect(self.changeEncodingStatus) self.videoThread.start() - self.videoTask.emit(self.window.lineEdit_background.text(), - self.window.lineEdit_audioFile.text(), + self.videoTask.emit(self.window.lineEdit_audioFile.text(), self.window.lineEdit_outputFile.text(), self.selectedComponents) else: @@ -323,10 +310,6 @@ class Main(QtCore.QObject): self.window.pushButton_savePreset.setEnabled(False) self.window.pushButton_openProject.setEnabled(False) self.window.listWidget_componentList.setEnabled(False) - - self.window.label_background.setEnabled(False) - self.window.lineEdit_background.setEnabled(False) - self.window.toolButton_selectBackground.setEnabled(False) else: self.window.pushButton_createVideo.setEnabled(True) self.window.pushButton_Cancel.setEnabled(False) @@ -349,12 +332,6 @@ class Main(QtCore.QObject): self.window.pushButton_openProject.setEnabled(True) self.window.listWidget_componentList.setEnabled(True) - self.window.label_background.setEnabled(True) - self.window.lineEdit_background.setEnabled(True) - self.window.toolButton_selectBackground.setEnabled(True) - - - def progressBarSetText(self, value): self.window.progressBar_createVideo.setFormat(value) @@ -370,7 +347,7 @@ class Main(QtCore.QObject): self.drawPreview() def drawPreview(self): - self.newTask.emit(self.window.lineEdit_background.text(), self.selectedComponents) + self.newTask.emit(self.selectedComponents) # self.processTask.emit() self.autosave() @@ -381,7 +358,7 @@ class Main(QtCore.QObject): def findComponents(): srcPath = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'components') if os.path.exists(srcPath): - for f in os.listdir(srcPath): + for f in sorted(os.listdir(srcPath)): name, ext = os.path.splitext(f) if name.startswith("__"): continue @@ -507,7 +484,7 @@ class Main(QtCore.QObject): if self.window.comboBox_openPreset.itemText(i) == filename: self.window.comboBox_openPreset.removeItem(i) with open(filepath, 'w') as f: - f.write(core.Core.sortedStringDict(saveValueStore)) + f.write(core.Core.stringOrderedDict(saveValueStore)) self.window.comboBox_openPreset.addItem(filename) self.window.comboBox_openPreset.setCurrentIndex(self.window.comboBox_openPreset.count()-1) @@ -550,12 +527,13 @@ class Main(QtCore.QObject): if not filepath.endswith(".avp"): filepath += '.avp' 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.Core.sortedStringDict(saveValueStore)) + f.write('%s\n' % core.Core.stringOrderedDict(saveValueStore)) if filepath != self.autosavePath: self.settings.setValue("projectDir", os.path.dirname(filepath)) self.settings.setValue("currentProject", filepath) @@ -604,14 +582,18 @@ class Main(QtCore.QObject): saveValueStore = dict(eval(line)) self.selectedComponents[-1].loadPreset(saveValueStore) i = 0 - except: + except (IndexError, ValueError, KeyError, NameError, SyntaxError, AttributeError, TypeError) as e: self.clear() - self.showMessage("Project file '%s' is corrupted." % filepath) + typ, value, _ = sys.exc_info() + msg = '%s: %s' % (typ.__name__, value) + self.showMessage("Project file '%s' is corrupted." % filepath, False, + QtGui.QMessageBox.Warning, msg) - def showMessage(self, string, showCancel=False, icon=QtGui.QMessageBox.Information): + def showMessage(self, string, showCancel=False, icon=QtGui.QMessageBox.Information, detail=None): msg = QtGui.QMessageBox() msg.setIcon(icon) msg.setText(string) + msg.setDetailedText(detail) if showCancel: msg.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) else: -- cgit v1.2.3 From 277e86f2795093deaa12f294c29ac2f951ae65cd Mon Sep 17 00:00:00 2001 From: tassaron Date: Sun, 4 Jun 2017 20:27:43 -0400 Subject: not dumping frames anymore, but not working yet either will finish later --- components/video.py | 69 +++++++++++++++++++++++++++++++++-------------------- core.py | 5 ++-- main.py | 2 +- video_thread.py | 1 - 4 files changed, 47 insertions(+), 30 deletions(-) (limited to 'main.py') diff --git a/components/video.py b/components/video.py index 1a9f344..97b824c 100644 --- a/components/video.py +++ b/components/video.py @@ -30,11 +30,11 @@ class Component(__base__.Component): def previewRender(self, previewWorker): self.width = int(previewWorker.core.settings.value('outputWidth')) self.height = int(previewWorker.core.settings.value('outputHeight')) - frames = self.getVideoFrames(True) - if not hasattr(self, 'staticFrame') or not self.working and frames: + frame1 = self.getPreviewFrame() + if not hasattr(self, 'staticFrame') or not self.working and frame1: frame = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) - if frames: - im = Image.open(frames[0]) + if frame1: + im = Image.open(frame1) im = self.resize(im) frame.paste(im) if not self.working: @@ -77,39 +77,56 @@ class Component(__base__.Component): self.settings.setValue("backgroundDir", os.path.dirname(filename)) self.page.lineEdit_video.setText(filename) self.update() - - def getVideoFrames(self, preview=False): - # recreate the temporary directory so it is empty - # FIXME: don't dump all the frames at once, don't dump more than sound length - # FIXME: make cancellable, report status to user, etc etc etc + + def getPreviewFrame(self): if not self.videoPath: return name = os.path.basename(self.videoPath).split('.', 1)[0] - if preview: - filename = 'preview%s.jpg' % name - if os.path.exists(os.path.join(self.parent.core.tempDir, filename)): - return False - else: - filename = name+'-frame%05d.jpg' - - # recreate tempDir and dump needed frame(s) - self.parent.core.deleteTempDir() - os.mkdir(self.parent.core.tempDir) - if preview: - options = '-ss 10 -vframes 1' - else: - options = '' #'-vframes 99999' + filename = 'preview%s.jpg' % name + if os.path.exists(os.path.join(self.parent.core.tempDir, filename)): + # no, we don't need a new preview frame + return False + + # get a preview frame subprocess.call( \ '%s -i "%s" -y %s "%s"' % ( \ self.parent.core.FFMPEG_BIN, self.videoPath, - options, + '-ss 10 -vframes 1', os.path.join(self.parent.core.tempDir, filename) ), shell=True ) - print('### Got Preview Frame From %s ###' % name if preview else '### Finished Dumping Frames From %s ###' % name) - return sorted([os.path.join(self.parent.core.tempDir, f) for f in os.listdir(self.parent.core.tempDir)]) + print('### Got Preview Frame From %s ###' % name) + return os.path.join(self.parent.core.tempDir, filename) + + def getVideoFrames(self): + # FIXME: make cancellable, report status to user, etc etc etc + if not self.videoPath: + return + + command = [ + self.parent.core.FFMPEG_BIN, + '-i', self.videoPath, + '-f', 'image2pipe', + '-vcodec', 'rawvideo', '-', + '-pix_fmt', 'rgba', + ] + + # pipe in video frames from ffmpeg + in_pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=8**10) + # maybe bufsize=4*self.width*self.height+100 ? + chunk = 4*self.width*self.height + + frames = [] + while True: + byteFrame = in_pipe.stdout.read(chunk) + if len(byteFrame) == 0: + break + img = Image.frombytes('RGBA', (self.width, self.height), byteFrame, 'raw', 'RGBa') + frames.append(img) + + return frames def resize(self, im): if im.size != (self.width, self.height): diff --git a/core.py b/core.py index ecbf12c..99403f1 100644 --- a/core.py +++ b/core.py @@ -15,6 +15,8 @@ class Core(): def __init__(self): self.FFMPEG_BIN = self.findFfmpeg() self.tempDir = os.path.join(tempfile.gettempdir(), 'audio-visualizer-python-data') + if not os.path.exists(self.tempDir): + os.makedirs(self.tempDir) atexit.register(self.deleteTempDir) def findFfmpeg(self): @@ -94,8 +96,7 @@ class Core(): def deleteTempDir(self): try: - if os.path.exists(self.tempDir): - rmtree(self.tempDir) + rmtree(self.tempDir) except FileNotFoundError: pass diff --git a/main.py b/main.py index da72b1e..637ece8 100644 --- a/main.py +++ b/main.py @@ -253,7 +253,7 @@ class Main(QtCore.QObject): outputDir = self.settings.value("outputDir", expanduser("~")) fileName = QtGui.QFileDialog.getSaveFileName(self.window, - "Set Output Video File", outputDir, "Video Files (*.mkv)"); + "Set Output Video File", outputDir, "Video Files (*.mkv *.mp4)"); if not fileName == "": self.settings.setValue("outputDir", os.path.dirname(fileName)) diff --git a/video_thread.py b/video_thread.py index e74fffa..0542bc2 100644 --- a/video_thread.py +++ b/video_thread.py @@ -228,7 +228,6 @@ class Worker(QtCore.QObject): self.error = False self.canceled = False self.parent.drawPreview() - self.core.deleteTempDir() self.stopped = True self.encoding.emit(False) self.videoCreated.emit() -- cgit v1.2.3 From be18deece5843ac8d2c7af64704e3fb360a05a25 Mon Sep 17 00:00:00 2001 From: DH4 Date: Mon, 5 Jun 2017 04:54:58 -0500 Subject: Performance Tuning. FIXME: Video component frames are rendered out of order. Video component creates a severe performance bottleneck. --- components/video.py | 21 ++++++++++----------- main.py | 4 ++-- video_thread.py | 20 ++++++++++---------- 3 files changed, 22 insertions(+), 23 deletions(-) (limited to 'main.py') diff --git a/components/video.py b/components/video.py index b009baa..422b952 100644 --- a/components/video.py +++ b/components/video.py @@ -36,8 +36,6 @@ class Component(__base__.Component): frame = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) if frame1: im = Image.open(frame1) - self.realSize = im.size - im = self.resize(im) frame.paste(im) if not self.working: self.staticFrame = frame @@ -61,11 +59,9 @@ class Component(__base__.Component): return self.staticFrame # make a new frame - width, height = self.realSize - image = numpy.fromstring(byteFrame, dtype='uint8') - image = image.reshape((width, height, 4)) - image = Image.frombytes('RGBA', (width, height), image, 'raw', 'RGBa') - image = self.resize(image) + width = self.width + height = self.height + image = Image.frombytes('RGBA', (width, height), byteFrame) self.staticFrame = image return self.staticFrame @@ -80,7 +76,7 @@ class Component(__base__.Component): def pickVideo(self): imgDir = self.settings.value("backgroundDir", os.path.expanduser("~")) filename = QtGui.QFileDialog.getOpenFileName(self.page, - "Choose Video", imgDir, "Video Files (*.mp4)") + "Choose Video", imgDir, "Video Files (*.mp4 *.mov)") if filename: self.settings.setValue("backgroundDir", os.path.dirname(filename)) self.page.lineEdit_video.setText(filename) @@ -97,10 +93,11 @@ class Component(__base__.Component): # get a preview frame subprocess.call( \ - '%s -i "%s" -y %s "%s"' % ( \ + '%s -i "%s" -y %s %s "%s"' % ( \ self.parent.core.FFMPEG_BIN, self.videoPath, '-ss 10 -vframes 1', + '-filter:v scale='+str(self.width)+':'+str(self.height), os.path.join(self.parent.core.tempDir, filename) ), shell=True @@ -114,16 +111,18 @@ class Component(__base__.Component): command = [ self.parent.core.FFMPEG_BIN, + '-thread_queue_size', '512', '-i', self.videoPath, '-f', 'image2pipe', '-pix_fmt', 'rgba', + '-filter:v', 'scale='+str(self.width)+':'+str(self.height), '-vcodec', 'rawvideo', '-', ] # pipe in video frames from ffmpeg in_pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8) - width, height = self.realSize - self.chunkSize = 4*width*height + #width, height = self.realSize + self.chunkSize = 4*self.width*self.height return in_pipe diff --git a/main.py b/main.py index 637ece8..36fc989 100644 --- a/main.py +++ b/main.py @@ -243,7 +243,7 @@ class Main(QtCore.QObject): inputDir = self.settings.value("inputDir", expanduser("~")) fileName = QtGui.QFileDialog.getOpenFileName(self.window, - "Open Music File", inputDir, "Music Files (*.mp3 *.wav *.ogg *.flac)"); + "Open Music File", inputDir, "Music Files (*.mp3 *.wav *.ogg *.fla *.aac)"); if not fileName == "": self.settings.setValue("inputDir", os.path.dirname(fileName)) @@ -253,7 +253,7 @@ class Main(QtCore.QObject): outputDir = self.settings.value("outputDir", expanduser("~")) fileName = QtGui.QFileDialog.getSaveFileName(self.window, - "Set Output Video File", outputDir, "Video Files (*.mkv *.mp4)"); + "Set Output Video File", outputDir, "Video Files (*.mp4 *.mov *.mkv *.avi *.webm *.flv)"); if not fileName == "": self.settings.setValue("outputDir", os.path.dirname(fileName)) diff --git a/video_thread.py b/video_thread.py index 0542bc2..ac4162c 100644 --- a/video_thread.py +++ b/video_thread.py @@ -37,20 +37,19 @@ class Worker(QtCore.QObject): def renderNode(self): while not self.stopped: i = self.compositeQueue.get() - - frame = Image.new( - "RGBA", - (self.width, self.height), - (0, 0, 0, 0) - ) + frame = None for compNo, comp in reversed(list(enumerate(self.components))): if compNo in self.staticComponents and self.staticComponents[compNo] != None: - frame = Image.alpha_composite(frame, self.staticComponents[compNo]) + if frame is None: + frame = self.staticComponents[compNo] + else: + frame = Image.alpha_composite(frame, self.staticComponents[compNo]) else: - frame = Image.alpha_composite(frame, comp.frameRender(compNo, i[0], i[1])) - - # frame.paste(compFrame, mask=compFrame) + if frame is None: + frame = comp.frameRender(compNo, i[0], i[1]) + else: + frame = Image.alpha_composite(frame, comp.frameRender(compNo, i[0], i[1])) self.renderQueue.put([i[0], frame]) self.compositeQueue.task_done() @@ -98,6 +97,7 @@ class Worker(QtCore.QObject): ffmpegCommand = [ self.core.FFMPEG_BIN, + '-thread_queue_size', '512', '-y', # (optional) means overwrite the output file if it already exists. '-f', 'rawvideo', '-vcodec', 'rawvideo', -- cgit v1.2.3 From 47509ae2b19e5a05211ae06114ba4675aa60a793 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 6 Jun 2017 01:40:26 -0400 Subject: added framebuffer to keep frames in order NOT WORKING: end of video detection --- components/video.py | 144 +++++++++++++++++++++++++--------------------------- main.py | 13 +++-- 2 files changed, 76 insertions(+), 81 deletions(-) (limited to 'main.py') diff --git a/components/video.py b/components/video.py index 422b952..0ae5348 100644 --- a/components/video.py +++ b/components/video.py @@ -1,15 +1,56 @@ from PIL import Image, ImageDraw from PyQt4 import uic, QtGui, QtCore -import os, subprocess -import numpy +import os, subprocess, threading +from queue import PriorityQueue from . import __base__ +class Video: + '''Video Component Frame-Fetcher''' + def __init__(self, ffmpeg, videoPath, width, height, frameRate, chunkSize, parent): + self.parent = parent + self.chunkSize = chunkSize + self.size = (width, height) + self.frameNo = -1 + self.command = [ + ffmpeg, + '-thread_queue_size', '512', + '-r', frameRate, + '-i', videoPath, + '-f', 'image2pipe', + '-pix_fmt', 'rgba', + '-filter:v', 'scale='+str(width)+':'+str(height), + '-vcodec', 'rawvideo', '-', + ] + + self.frameBuffer = PriorityQueue() + self.frameBuffer.maxsize = int(frameRate) + self.finishedFrames = {} + + self.thread = threading.Thread(target=self.fillBuffer, name=self.__doc__) + self.thread.daemon = True + self.thread.start() + + def frame(self, num): + while True: + if num in self.finishedFrames: + image = self.finishedFrames.pop(num) + return Image.frombytes('RGBA', self.size, image) + i, image = self.frameBuffer.get() + self.finishedFrames[i] = image + self.frameBuffer.task_done() + + def fillBuffer(self): + self.pipe = subprocess.Popen(self.command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8) + while True: + if self.parent.canceled: + break + self.frameNo += 1 + image = self.pipe.stdout.read(self.chunkSize) + print('creating frame #%s' % str(self.frameNo)) + self.frameBuffer.put((self.frameNo, image)) + class Component(__base__.Component): '''Video''' - def __init__(self): - super().__init__() - self.working = False - def widget(self, parent): self.parent = parent self.settings = parent.settings @@ -29,41 +70,22 @@ class Component(__base__.Component): self.parent.drawPreview() def previewRender(self, previewWorker): - self.width = int(previewWorker.core.settings.value('outputWidth')) - self.height = int(previewWorker.core.settings.value('outputHeight')) - frame1 = self.getPreviewFrame() - if not hasattr(self, 'staticFrame') or not self.working and frame1: - frame = Image.new("RGBA", (self.width, self.height), (0, 0, 0, 0)) - if frame1: - im = Image.open(frame1) - frame.paste(im) - if not self.working: - self.staticFrame = frame - return self.staticFrame + width = int(previewWorker.core.settings.value('outputWidth')) + height = int(previewWorker.core.settings.value('outputHeight')) + self.chunkSize = 4*width*height + return self.getPreviewFrame(width, height) def preFrameRender(self, **kwargs): super().preFrameRender(**kwargs) - self.width = int(self.worker.core.settings.value('outputWidth')) - self.height = int(self.worker.core.settings.value('outputHeight')) - self.working = True - self.frames = self.getVideoFrames() + width = int(self.worker.core.settings.value('outputWidth')) + height = int(self.worker.core.settings.value('outputHeight')) + self.chunkSize = 4*width*height + self.video = Video(self.parent.core.FFMPEG_BIN, self.videoPath, + width, height, self.settings.value("outputFrameRate"), + self.chunkSize, self.parent) def frameRender(self, moduleNo, arrayNo, frameNo): - # don't make a new frame - if not self.working: - return self.staticFrame - byteFrame = self.frames.stdout.read(self.chunkSize) - if len(byteFrame) == 0: - self.working = False - self.frames.kill() - return self.staticFrame - - # make a new frame - width = self.width - height = self.height - image = Image.frombytes('RGBA', (width, height), byteFrame) - self.staticFrame = image - return self.staticFrame + return self.video.frame(frameNo) def loadPreset(self, pr): self.page.lineEdit_video.setText(pr['video']) @@ -82,51 +104,21 @@ class Component(__base__.Component): self.page.lineEdit_video.setText(filename) self.update() - def getPreviewFrame(self): - if not self.videoPath: - return - name = os.path.basename(self.videoPath).split('.', 1)[0] - filename = 'preview%s.jpg' % name - if os.path.exists(os.path.join(self.parent.core.tempDir, filename)): - # no, we don't need a new preview frame - return False - - # get a preview frame - subprocess.call( \ - '%s -i "%s" -y %s %s "%s"' % ( \ - self.parent.core.FFMPEG_BIN, - self.videoPath, - '-ss 10 -vframes 1', - '-filter:v scale='+str(self.width)+':'+str(self.height), - os.path.join(self.parent.core.tempDir, filename) - ), - shell=True - ) - print('### Got Preview Frame From %s ###' % name) - return os.path.join(self.parent.core.tempDir, filename) - - def getVideoFrames(self): - if not self.videoPath: - return - + def getPreviewFrame(self, width, height): command = [ self.parent.core.FFMPEG_BIN, '-thread_queue_size', '512', '-i', self.videoPath, '-f', 'image2pipe', '-pix_fmt', 'rgba', - '-filter:v', 'scale='+str(self.width)+':'+str(self.height), + '-filter:v', 'scale='+str(width)+':'+str(height), '-vcodec', 'rawvideo', '-', + '-ss', '90', + '-vframes', '1', ] - - # pipe in video frames from ffmpeg - in_pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8) - #width, height = self.realSize - self.chunkSize = 4*self.width*self.height - - return in_pipe - - def resize(self, im): - if im.size != (self.width, self.height): - im = im.resize((self.width, self.height), Image.ANTIALIAS) - return im + pipe = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8) + byteFrame = pipe.stdout.read(self.chunkSize) + image = Image.frombytes('RGBA', (width, height), byteFrame) + pipe.stdout.close() + pipe.kill() + return image diff --git a/main.py b/main.py index 36fc989..c75a7f7 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -import sys, io, os, shutil, atexit, string, signal, filecmp +import sys, io, os, shutil, atexit, string, signal, filecmp, time from os.path import expanduser from queue import Queue from importlib import import_module @@ -145,6 +145,7 @@ class Main(QtCore.QObject): self.core = core.Core() self.pages = [] self.selectedComponents = [] + self.lastAutosave = time.time() # create data directory, load/create settings self.dataDir = QDesktopServices.storageLocation(QDesktopServices.DataLocation) @@ -235,9 +236,11 @@ class Main(QtCore.QObject): self.autosave() def autosave(self): - if os.path.exists(self.autosavePath): - os.remove(self.autosavePath) - self.createProjectFile(self.autosavePath) + if time.time() - self.lastAutosave >= 1.0: + if os.path.exists(self.autosavePath): + os.remove(self.autosavePath) + self.createProjectFile(self.autosavePath) + self.lastAutosave = time.time() def openInputFileDialog(self): inputDir = self.settings.value("inputDir", expanduser("~")) @@ -423,7 +426,7 @@ class Main(QtCore.QObject): def moveComponentDown(self): row = self.window.listWidget_componentList.currentRow() - if row < len(self.pages) + 1: + if row != -1 and row < len(self.pages)+1: module = self.selectedComponents[row] self.selectedComponents.pop(row) self.selectedComponents.insert(row + 1,module) -- cgit v1.2.3