From ba0409829de62b745d6f87749572a416061a42b4 Mon Sep 17 00:00:00 2001 From: tassaron Date: Tue, 4 Jul 2017 19:52:52 -0400 Subject: moved functions into toolkit, fixed CMD appearing on Windows --- src/command.py | 2 +- src/components/video.py | 5 +-- src/core.py | 65 +++++++++++++----------------------- 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, 119 insertions(+), 85 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 0000000..ce68831 Binary files /dev/null and b/src/core.pyc differ 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 -- cgit v1.2.3