From ba0409829de62b745d6f87749572a416061a42b4 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 4 Jul 2017 19:52:52 -0400 Subject: [PATCH] moved functions into toolkit, fixed CMD appearing on Windows --- src/command.py | 2 +- src/components/video.py | 5 ++- src/core.py | 67 ++++++++++++------------------- src/core.pyc | Bin 0 -> 15050 bytes src/main.py | 35 ----------------- src/mainwindow.py | 4 +- src/presetmanager.py | 5 ++- src/toolkit.py | 85 ++++++++++++++++++++++++++++++++++++++++ src/video_thread.py | 3 +- 9 files changed, 120 insertions(+), 86 deletions(-) create mode 100644 src/core.pyc create mode 100644 src/toolkit.py diff --git a/src/command.py b/src/command.py index 3eea1b6..ee0e48d 100644 --- a/src/command.py +++ b/src/command.py @@ -5,7 +5,7 @@ import sys import core import video_thread -from main import LoadDefaultSettings +from toolkit import LoadDefaultSettings class Command(QtCore.QObject): diff --git a/src/components/video.py b/src/components/video.py index 175cf29..19a9106 100644 --- a/src/components/video.py +++ b/src/components/video.py @@ -8,6 +8,7 @@ from queue import PriorityQueue from component import Component, BadComponentInit from frame import BlankFrame +from toolkit import openPipe class Video: @@ -72,7 +73,7 @@ class Video: self.frameBuffer.task_done() def fillBuffer(self): - pipe = subprocess.Popen( + pipe = openPipe( self.command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8 ) @@ -217,7 +218,7 @@ class Component(Component): '-ss', '90', '-vframes', '1', ] - pipe = subprocess.Popen( + pipe = openPipe( command, stdout=subprocess.PIPE, stderr=subprocess.DEVNULL, bufsize=10**8 ) diff --git a/src/core.py b/src/core.py index 3fa67db..9ea9666 100644 --- a/src/core.py +++ b/src/core.py @@ -1,21 +1,24 @@ +''' + Home to the Core class which tracks the program state +''' import sys import os from PyQt5 import QtCore, QtGui, uic -from os.path import expanduser import subprocess as sp import numpy -from PIL import Image -from shutil import rmtree -import time -from collections import OrderedDict import json from importlib import import_module from PyQt5.QtCore import QStandardPaths -import string + +import toolkit -class Core(): - +class Core: + ''' + MainWindow and Command module both use an instance of this class + to store the program state. This object tracks the components, + opens projects and presets, and stores settings/paths to data. + ''' def __init__(self): self.dataDir = QStandardPaths.writableLocation( QStandardPaths.AppConfigLocation @@ -34,7 +37,7 @@ class Core(): ) self.loadEncoderOptions() - self.videoFormats = Core.appendUppercase([ + self.videoFormats = toolkit.appendUppercase([ '*.mp4', '*.mov', '*.mkv', @@ -42,7 +45,7 @@ class Core(): '*.webm', '*.flv', ]) - self.audioFormats = Core.appendUppercase([ + self.audioFormats = toolkit.appendUppercase([ '*.mp3', '*.wav', '*.ogg', @@ -50,7 +53,7 @@ class Core(): '*.flac', '*.aac', ]) - self.imageFormats = Core.appendUppercase([ + self.imageFormats = toolkit.appendUppercase([ '*.png', '*.jpg', '*.tif', @@ -175,7 +178,7 @@ class Core(): return False with open(filepath, 'r') as f: for line in f: - saveValueStore = Core.presetFromString(line.strip()) + saveValueStore = toolkit.presetFromString(line.strip()) break return saveValueStore @@ -307,7 +310,7 @@ class Core(): lastCompVers = str(line) i += 1 elif i == 2: - lastCompPreset = Core.presetFromString(line) + lastCompPreset = toolkit.presetFromString(line) data[section].append(( lastCompName, lastCompVers, @@ -357,7 +360,7 @@ class Core(): with open(internalPath, 'r') as f: internalData = [line for line in f] try: - saveValueStore = Core.presetFromString(internalData[0].strip()) + saveValueStore = toolkit.presetFromString(internalData[0].strip()) self.createPresetFile( compName, vers, origName, saveValueStore, @@ -387,7 +390,7 @@ class Core(): f.write('[Components]\n') f.write('%s\n' % compName) f.write('%s\n' % str(vers)) - f.write(Core.presetToString(saveValueStore)) + f.write(toolkit.presetToString(saveValueStore)) def createProjectFile(self, filepath, window=None): '''Create a project file (.avp) using the current program state''' @@ -411,7 +414,7 @@ class Core(): 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('%s\n' % toolkit.presetToString(saveValueStore)) f.write('\n[Settings]\n') for key in self.settings.allKeys(): @@ -450,7 +453,9 @@ class Core(): else: try: with open(os.devnull, "w") as f: - sp.check_call(['ffmpeg', '-version'], stdout=f, stderr=f) + sp.check_call( + ['ffmpeg', '-version'], stdout=f, stderr=f + ) return "ffmpeg" except: return "avconv" @@ -459,10 +464,9 @@ class Core(): command = [self.FFMPEG_BIN, '-i', filename] try: - fileInfo = sp.check_output(command, stderr=sp.STDOUT, shell=False) + fileInfo = toolkit.checkOutput(command, stderr=sp.STDOUT) except sp.CalledProcessError as ex: fileInfo = ex.output - pass info = fileInfo.decode("utf-8").split('\n') for line in info: @@ -480,7 +484,7 @@ class Core(): '-ar', '44100', # ouput will have 44100 Hz '-ac', '1', # mono (set to '2' for stereo) '-'] - in_pipe = sp.Popen( + in_pipe = toolkit.openPipe( command, stdout=sp.PIPE, stderr=sp.DEVNULL, bufsize=10**8) completeAudioArray = numpy.empty(0, dtype="int16") @@ -525,26 +529,3 @@ class Core(): def reset(self): self.canceled = False - - @staticmethod - def badName(name): - '''Returns whether a name contains non-alphanumeric chars''' - return any([letter in string.punctuation for letter in name]) - - @staticmethod - def presetToString(dictionary): - '''Alphabetizes a dict into OrderedDict & returns string repr''' - return repr( - OrderedDict(sorted(dictionary.items(), key=lambda t: t[0])) - ) - - @staticmethod - def presetFromString(string): - '''Turns a string repr of OrderedDict into a regular dict''' - return dict(eval(string)) - - @staticmethod - def appendUppercase(lst): - for form, i in zip(lst, range(len(lst))): - lst.append(form.upper()) - return lst diff --git a/src/core.pyc b/src/core.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ce688310605a43d7ac0650e7bda18bfe1fbcbd22 GIT binary patch literal 15050 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 literal 0 HcmV?d00001 diff --git a/src/main.py b/src/main.py index bae9adf..b0ece29 100644 --- a/src/main.py +++ b/src/main.py @@ -7,41 +7,6 @@ import preview_thread import video_thread -def disableWhenEncoding(func): - def decorator(*args, **kwargs): - if args[0].encoding: - return - else: - return func(*args, **kwargs) - return decorator - - -def LoadDefaultSettings(self): - self.resolutions = [ - '1920x1080', - '1280x720', - '854x480' - ] - - default = { - "outputWidth": 1280, - "outputHeight": 720, - "outputFrameRate": 30, - "outputAudioCodec": "AAC", - "outputAudioBitrate": "192", - "outputVideoCodec": "H264", - "outputVideoBitrate": "2500", - "outputVideoFormat": "yuv420p", - "outputPreset": "medium", - "outputFormat": "mp4", - "outputContainer": "MP4", - "projectDir": os.path.join(self.dataDir, 'projects'), - } - - for parm, value in default.items(): - if self.settings.value(parm) is None: - self.settings.setValue(parm, value) - if __name__ == "__main__": mode = 'gui' if len(sys.argv) > 2: diff --git a/src/mainwindow.py b/src/mainwindow.py index 5068108..e8a3221 100644 --- a/src/mainwindow.py +++ b/src/mainwindow.py @@ -1,6 +1,6 @@ -from queue import Queue from PyQt5 import QtCore, QtGui, uic, QtWidgets from PyQt5.QtWidgets import QMenu, QShortcut +from queue import Queue import sys import os import signal @@ -11,7 +11,7 @@ import core import preview_thread import video_thread from presetmanager import PresetManager -from main import LoadDefaultSettings, disableWhenEncoding +from toolkit import LoadDefaultSettings, disableWhenEncoding class PreviewWindow(QtWidgets.QLabel): diff --git a/src/presetmanager.py b/src/presetmanager.py index 68679ec..805b93e 100644 --- a/src/presetmanager.py +++ b/src/presetmanager.py @@ -3,6 +3,7 @@ import string import os import core +import toolkit class PresetManager(QtWidgets.QDialog): @@ -147,7 +148,7 @@ class PresetManager(QtWidgets.QDialog): currentPreset ) if OK: - if core.Core.badName(newName): + if toolkit.badName(newName): self.warnMessage(self.parent.window) continue if newName: @@ -252,7 +253,7 @@ class PresetManager(QtWidgets.QDialog): self.presetRows[index][2] ) if OK: - if core.Core.badName(newName): + if toolkit.badName(newName): self.warnMessage() continue if newName: diff --git a/src/toolkit.py b/src/toolkit.py new file mode 100644 index 0000000..8dce645 --- /dev/null +++ b/src/toolkit.py @@ -0,0 +1,85 @@ +''' + Common functions +''' +import string +import os +import sys +import subprocess +from collections import OrderedDict + + +def badName(name): + '''Returns whether a name contains non-alphanumeric chars''' + return any([letter in string.punctuation for letter in name]) + + +def presetToString(dictionary): + '''Alphabetizes a dict into OrderedDict & returns string repr''' + return repr( + OrderedDict(sorted(dictionary.items(), key=lambda t: t[0])) + ) + + +def presetFromString(string): + '''Turns a string repr of OrderedDict into a regular dict''' + return dict(eval(string)) + + +def appendUppercase(lst): + for form, i in zip(lst, range(len(lst))): + lst.append(form.upper()) + return lst + + +def checkOutput(commandList, **kwargs): + _subprocess(subprocess.check_output) + + +def openPipe(commandList, **kwargs): + _subprocess(subprocess.Popen) + + +def _subprocess(func, commandList, **kwargs): + if not sys.platform == 'win32': + # Stop CMD window from appearing on Windows + # http://code.activestate.com/recipes/409002/ + startupinfo = subprocess.STARTUPINFO() + startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW + kwargs['startupinfo'] = startupinfo + return func(commandList, shell=False, **kwargs) + + +def disableWhenEncoding(func): + def decorator(*args, **kwargs): + if args[0].encoding: + return + else: + return func(*args, **kwargs) + return decorator + + +def LoadDefaultSettings(self): + self.resolutions = [ + '1920x1080', + '1280x720', + '854x480' + ] + + default = { + "outputWidth": 1280, + "outputHeight": 720, + "outputFrameRate": 30, + "outputAudioCodec": "AAC", + "outputAudioBitrate": "192", + "outputVideoCodec": "H264", + "outputVideoBitrate": "2500", + "outputVideoFormat": "yuv420p", + "outputPreset": "medium", + "outputFormat": "mp4", + "outputContainer": "MP4", + "projectDir": os.path.join(self.dataDir, 'projects'), + } + + for parm, value in default.items(): + if self.settings.value(parm) is None: + self.settings.setValue(parm, value) diff --git a/src/video_thread.py b/src/video_thread.py index 9b0bf56..aed4d60 100644 --- a/src/video_thread.py +++ b/src/video_thread.py @@ -13,6 +13,7 @@ from copy import copy import signal import core +from toolkit import openPipe class Worker(QtCore.QObject): @@ -191,7 +192,7 @@ class Worker(QtCore.QObject): self.progressBarUpdate.emit(100) # Create ffmpeg pipe and queues for frames - self.out_pipe = sp.Popen( + self.out_pipe = openPipe( ffmpegCommand, stdin=sp.PIPE, stdout=sys.stdout, stderr=sys.stdout) self.compositeQueue = Queue() self.compositeQueue.maxsize = 20