Skip to content

Instantly share code, notes, and snippets.

@Melanpan
Created December 1, 2015 00:53
Show Gist options
  • Save Melanpan/c0baf37bff735e56ba89 to your computer and use it in GitHub Desktop.
Save Melanpan/c0baf37bff735e56ba89 to your computer and use it in GitHub Desktop.
#!/usr/bin/python3.5
import os
import subprocess
import json
import pyinotify
import time
import logging
class autoEncoder():
"""
Monitors a folder and encodes files inside that
folder according to settings
"""
settings = {}
def __init__(self):
self.configPath = "/mnt/docuraid/Documents/Development/AutoEncoder/settings.json"
self.loadConfig()
self.logger = logging.getLogger(__name__)
self.logger.setLevel(logging.DEBUG)
self.setupLogging()
if not os.path.exists(self.settings['outputFolder']):
os.makedirs(self.settings['outputFolder'])
self.logger.info("Auto encoder v1.0 online.")
def setupLogging(self):
""" Set up the loggers """
logFormatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
fileHandler = logging.FileHandler(self.settings['log'])
fileHandler.setFormatter(logFormatter)
consoleHandler = logging.StreamHandler()
consoleHandler.setFormatter(logFormatter)
self.logger.addHandler(fileHandler)
self.logger.addHandler(consoleHandler)
def watch(self):
""" Main watch loop """
files = []
while True:
time.sleep(1)
for videoFile in os.listdir(self.settings['watchFolder']):
filePath = os.path.join(self.settings['watchFolder'], videoFile)
# If the file is new, start monitoring it for changes.
if videoFile not in [file['name'] for file in files]:
self.logger.info("New file %s, waiting for copying to be finished before encoding." % videoFile)
files.append({"name": videoFile, "modified": os.path.getmtime(filePath)})
else:
dictPos = 0
# update the modified time if it differs.
if file['name'] == videoFile:
if file['modified'] != os.path.getmtime(filePath):
files.pop(dictPos)
files.append({"name": videoFile, "modified": os.path.getmtime(filePath)})
dictPos +=1
dictPos = 0
for file in files:
timePassed = round(time.time()-file['modified'])
if timePassed >= self.settings['acceptTime']:
files.pop(dictPos)
encodePath = os.path.join(self.settings['watchFolder'], file['name'])
self.encode(encodePath)
def loadConfig(self):
""" Load our config file """
self.settings = {}
with open(self.configPath, "r") as configFile:
self.settings = json.load(configFile)
def buildCommand(self, input):
""" Parse and build the ffmpeg command paraments """
if self.settings is not None:
outputArg = os.path.join(self.settings['outputFolder'],
self.settings['encodingSettings']['outputName'])
cmdArguments = self.settings['encodingSettings']['cmdArguments']
for key, value in self.settings['encodingSettings'].items():
# Proccess sub arguments such as video, and audio
if type(value) == dict:
for subKey, subValue in self.settings['encodingSettings'][key].items():
argKey = "{%s-%s}" % (key, subKey)
cmdArguments = cmdArguments.replace(argKey, subValue)
# replace other arguments
if type(value) is str and type(key) is str:
if "{input}" != key or "{output}" != key:
cmdArguments = cmdArguments.replace("{%s}" % key, value)
outputArg = outputArg.replace("{%s}" % key, value)
outputArg = outputArg.replace("{input}", os.path.basename(os.path.splitext(input)[0]))
cmdArguments = cmdArguments.replace("{input}", input)
cmdArguments = cmdArguments.replace("{output}", outputArg)
return cmdArguments
def runCommand(self, command):
""" Execute a command and return dict containing stdout and stderr """
pipe = subprocess.Popen(command, shell=True,
stdout = subprocess.PIPE,stderr = subprocess.PIPE)
stdout, stderr = pipe.communicate()
return {"out": stdout, "err": stderr}
def encode(self, input):
""" Encode a file """
if self.settings is not None:
arg = self.buildCommand(input)
self.logger.info("Encoding %s (%s)" % (input, arg))
ffout = self.runCommand(arg)
self.logger.info("Finished encoding %s" % input)
if self.settings['removeInput']:
os.remove(input)
encoder = autoEncoder()
encoder.watch()
@Melanpan
Copy link
Author

Melanpan commented Dec 1, 2015

Example config file:

{
  "watchFolder": "/mnt/raid5/encode/G4/4K/",
  "outputFolder": "/mnt/raid5/encode/G4/1080/",
  "log": "/var/log/autoEncoder.log",
  "removeInput": true,
  "acceptTime": 3,
  "encodingSettings": {
      "audio": {
        "codec": "copy"
      },
      "video": {
        "resolution": "hd1080",
        "codec": "libx264",
        "crf": "25",
        "preset": "veryfast"
      },
      "ffmpeg": "/usr/bin/ffmpeg",
      "threads": "16",
      "fileFormat": "mp4",
      "outputName": "{input}.{fileFormat}",
      "cmdArguments": "{ffmpeg} -y -i '{input}' -s {video-resolution} -acodec {audio-codec} -vcodec {video-codec} -crf {video-crf} -preset {video-preset} -threads {threads} '{output}'"
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment