Python автоматизирует преобразование ffmpeg из каталога загрузки

У меня есть сценарий загрузки. Но мне нужно выяснить, как создать скрипт, который я могу запускать как демон в python, чтобы обрабатывать часть преобразования и перемещать преобразованный файл в место его последнего упокоения. Вот что у меня есть для сценария просмотра каталогов:

 #!/usr/bin/python

import os
import pyinotify import WatchManager, Notifier, ThreadedNotifier, ProcessEvent, EventCodes
import sys, time, syslog, config
from os import system
from daemon import Daemon

class myLog(ProcessEvent):
 def process_IN_CREATE(self, event):
  syslog.syslog("creating: " + event.pathname)
 def process_IN_DELETE(self, event):
  syslog.syslog("deleting: " + event.pathname)
 def process_default(self, event):
  syslog.syslog("default: " + event.pathname)

class MyDaemon(Daemon):
 def loadConfig(self):
  """Load user configuration file"""
  self.config = {}
  self.parser = ConfigParser.ConfigParser()
  if not os.path.isfile(self.configfile):
   self.parser.write(open(self.configfile, 'w'))
  self.parser.readfp(open(self.configfile, 'r'))

  variables = { \
   'mplayer':  ['paths', self.findProgram("mplayer")], \
   'mencoder':  ['paths', self.findProgram("mencoder")], \
   'tcprobe':  ['paths', self.findProgram("tcprobe")], \
   'transcode':  ['paths', self.findProgram("transcode")], \
   'ogmmerge':  ['paths', self.findProgram("ogmmerge")], \
   'outputdir':  ['paths', os.path.expanduser("~")], \
   }

  for key in variables.keys():
   self.cautiousLoad(variables[key][0], key, variables[key][1])

 def cautiousLoad(self, section, var, default):
  """Load a configurable variable within an exception clause,
  in case variable is not in configuration file"""
  try:
   self.config[var] = int(self.parser.get(section, var))
  except:
   self.config[var] = default
   try:
    self.parser.set(section, var, default)
   except:
    self.parser.add_section(section)
    self.parser.set(section, var, default)
   self.parser.write(open(self.configfile, 'w'))


 def findProgram(self, program):
  """Looks for program in path, and returns full path if found"""
  for path in config.paths:
   if os.path.isfile(os.path.join(path, program)):
    return os.path.join(path, program)
  self.ui_configError(program)

 def run(self):
  syslog.openlog('mediaConvertor', syslog.LOG_PID,syslog.LOG_DAEMON)
  syslog.syslog('daemon started, entering loop')
  wm = WatchManager()
  mask = IN_DELETE | IN_CREATE
  notifier = ThreadedNotifier(wm, myLog())
  notifier.start()
  wdd = wm.add_watch(self.config['outputdir'], mask, rec=True)
  while True:
   time.sleep(1)
  wm.rm_watch(wdd.values())
  notifier.stop()
  syslog.syslog('exiting media convertor')
  syslog.closelog()

if __name__ == "__main__":
 daemon = MyDaemon('/tmp/mediaconvertor.pid')
 if len(sys.argv) == 2:
  if 'start' == sys.argv[1]:
   daemon.run()
  if 'stop' == sys.argv[1]:
   daemon.stop()
  if 'restart' == sys.argv[1]:
   daemon.restart()
  else:
   print "Unknown Command"
   sys.exit(2)
  sys.exit(0)
 else:
  print "Usage: %s start|stop|restart" % sys.argv[0]
  sys.exit(2)

не уверен, куда идти отсюда.


person Moos3    schedule 23.01.2010    source источник


Ответы (1)


Я не работаю в Linux и никогда не использовал возможности inotify, которые вы используете здесь. Я опишу, как бы я поступил в общем.

В простейшем случае вам нужно проверить, есть ли новый файл в каталоге загрузки, и когда он есть, начать делать уведомление о преобразовании.

Чтобы проверить, есть ли новые файлы, вы можете сделать что-то вроде:

import os
import time

def watch_directory(dirname="."):
    old_files = set(os.listdir(dirname))
    while 1:
        time.sleep(1)
        new_files = set(os.listdir(dirname))
        diff = new_files - old_files
        if diff:
            print "New files", diff
        old_files = new_files

watch_directory()

Вы можете минимизировать некоторые накладные расходы файловой системы, сначала указав каталог, чтобы увидеть, есть ли какие-либо изменения.

def watch_directory(dirname="."):
    old_files = set(os.listdir(dirname))
    old_stat = os.stat(dirname)
    while 1:
        time.sleep(1)
        new_stat = os.stat(dirname)
        if new_stat == old_stat:
            continue
        new_files = set(os.listdir(dirname))
        diff = new_files - old_files
        if diff:
            print "New files", diff
        old_stat = new_stat
        old_files = new_files

Я думаю, что с inotify все это делается за вас, и вы помещаете свой код в process_IN_CREATE(), который вызывается, когда доступен новый файл.

Небольшая хитрость — как наблюдатель узнает, что загрузка завершена? Что произойдет, если загрузка будет отменена на полпути во время загрузки? Это может быть так же просто, как заставить веб-сервер выполнить rename(), чтобы использовать одно расширение во время загрузки и другое расширение, когда это будет сделано.

Как только вы узнаете файл, используйте subprocess.Popen(conversion_program, "new_filename") или os.system("conversion_program new_filename &"), чтобы запустить преобразование в новом процессе, который выполняет преобразование. Вам нужно будет обрабатывать такие вещи, как отчеты об ошибках, например, когда ввод не в правильном формате. Он также должен очищаться, а это означает, что после завершения преобразования входной файл должен быть удален из рассмотрения. Это может быть так же просто, как удалить файл.

Вам также нужно будет побеспокоиться о перезапуске любых конверсий, которые были убиты. Если машина не работает, как перезапущенный наблюдатель узнает, какие преобразования файлов данных также были уничтожены и должны быть перезапущены. Но это может быть выполнимо как шаг вручную.

person Andrew Dalke    schedule 24.01.2010
comment
круто, спасибо, я собираюсь попробовать то, что вы упомянули, и узнать больше о том, как inotify знает, завершен или не завершен процесс создания файла. - person Moos3; 25.01.2010
comment
Это известно, потому что есть подсистема, специфичная для Linux, которую программы могут использовать для наблюдения за изменениями в каталоге. Это не стандартно и не работает на других ОС. - person Andrew Dalke; 26.01.2010