#!/usr/bin/env python3 import subprocess import pyinotify import logging import io import time import os import shutil import multiprocessing import logging.handlers indir = "upload/convert/" outdir = "upload/" faildir = "upload/fail/" logf = "[%(name)s] %(levelname)s: %(message)s" logging.basicConfig(format=logf) class Worker(multiprocessing.Process): def __init__(self, path): super(Worker, self).__init__() self.path = path self.basename = path.rpartition("/")[-1].rpartition(".")[0] self.ext = path.rpartition(".")[-1] self.time = int(time.time()) self.string = io.StringIO() self.logger = logging.getLogger("mp4conv") self.handler = logging.StreamHandler(self.string) self.logger.addHandler(self.handler) self.logger.setLevel(logging.DEBUG) def subprocess_logger(self, output): for line in io.TextIOWrapper(output, encoding="utf-8"): self.logger.debug("(ffmpeg - %s) %r" % (self.basename, line)) def build_command(self): return ["ffmpeg", "-i", self.path, "-vcodec", "h264", "-acodec", "aac", "-strict", "-2", "%s/%s_%i.tmp.mp4" % (outdir, self.basename, self.time), "-nostats", "-hide_banner"] def process(self): self.logger.info("Discovered file %s." % self.path) time.sleep(5) if not os.path.exists(self.path): self.logger.info("File %s disappeared." % self.path) return self.string self.logger.info("Starting to process %s." % self.path) try: sub = subprocess.Popen(self.build_command(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) with sub.stdout as output: self.subprocess_logger(output) assert not sub.wait() os.rename("%s/%s_%i.tmp.mp4" % (outdir, self.basename, self.time), "%s/%s_%i.mp4" % (outdir, self.basename, self.time)) if os.path.exists(self.path): os.unlink(self.path) except Exception as e: self.logger.exception("Something went wrong. See the log file.") with open("%s/%s_%i.log" % (faildir, self.basename, self.time), "w+") as logfile: self.string.seek(0) shutil.copyfileobj(self.string, logfile) os.rename(self.path, "%s/%s_%i.%s" % (faildir, self.basename, self.time, self.ext)) finally: return self.string def run(self): self.process() class Handler(pyinotify.ProcessEvent): def process_IN_CLOSE_WRITE(self, event): Worker(event.pathname).start() def process_IN_MOVED_TO(self, event): self.process_IN_CLOSE_WRITE(event) def runner(): watch = pyinotify.WatchManager() event = pyinotify.IN_CLOSE_WRITE | pyinotify.IN_MOVED_TO notifier = pyinotify.ThreadedNotifier(watch, Handler()) watch.add_watch(indir, event, rec=True) notifier.start() if __name__ == "__main__": runner()