Пример #1
0
  def remediate_audio(self, path):

    # Create our Input() object to specify file we will be transcoding
    input_file = Input(path)

    # Create variables we will be using in the following code
    codec = None
    output_path = re.match('^(.*)\.audio\.\d\.mkv$', path).group(1) + '.final.audio.' + re.match('^.*\.audio\.(\d)\.mkv$', path).group(1) + '.mkv'
    output_file = Output(output_path)

    # Check if self.finalfiles is not none and if so create a list object. This is so we don't lose files already in the list
    if self.finalfiles is None:
      self.finalfiles = []

    # Create our AudioCodec() object to define the output codec and bitrate
    codec = AudioCodec('ac3')
    codec = codec.bitrate('448k')

    # Instance our FFmpeg() object to begin processing
    remediate_audio_job = FFmpeg('/usr/bin/ffmpeg', input_file, codec, output_file)

    # Begin the transcoding operation iterating over the piped stdout from the command
    with remediate_audio_job as self._process:
      while not self.abort and self._process.running:
        for line in self._process.readlines():
          if mediamanager.VERBOSE:
            logger.log(line, logger.DEBUG)
      if self._process.failed:
        return False
      elif self._process.successful:
        self.finalfiles.append(output_path)
        return True
      else:
        return False
Пример #2
0
  def ScanForMedia(cls):
    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'ScanForMedia :: Starting', logger.DEBUG)
    _files = []
    _media = {}

    for _source in mediamanager.SOURCES:
      if mediamanager.SCANNER_VERBOSE:
        logger.log(u'ScanForMedia :: Getting files from source ' + _source, logger.DEBUG)
      if re.match('^(~).*$', _source) is not None:
        _files.extend(Files.getFilesFromDir(os.path.join(os.path.expanduser("~"), re.match('^~\/(.*)$', _source).group(1))))
      else:
        _files.extend(Files.getFilesFromDir(_source))

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'ScanForMedia :: Found %d files' % len(_files), logger.DEBUG)

    for item in _files:
      if isinstance(item, Files.VideoInfo):
        match = re.match('^(.*)\..*$',item.basename)
        if match is not None:
          _media[match.group(1)] = item

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'ScanForMedia :: Found %d video files' % len(_media.keys()), logger.DEBUG)
      logger.log(u'ScanForMedia :: Completed', logger.DEBUG)
    return _media
Пример #3
0
def shutdown():

  halt()

  logger.log(u'Exiting MediaManager')

  os._exit(0)
Пример #4
0
  def execute(self):
    self.amActive = True

    try:
      self.job.run()
    except Exception, e:
      logger.log(u"QueueTranscode :: Exception caught running job; %s" % e, logger.DEBUG)
Пример #5
0
  def run(self):

    # only start a new task if one isn't already going
    if self.thread == None or self.thread.isAlive() == False:

      # if the thread is dead then the current item should be finished
      if self.currentItem != None:
        self.currentItem.finish()
        self.currentItem = None

      # if there's something in the queue then run it in a thread and take it out of the queue
      if len(self.queues[QueuePriorities.HIGH]) > 0 or len(self.queues[QueuePriorities.NORMAL]) > 0 or len(self.queues[QueuePriorities.LOW]) > 0:

        # sort by priority
        queueItem = self.pop_queueitem()

        if queueItem.priority == QueuePriorities.NORMAL and media.is_pending(queueItem.job._file):
          logger.log("Queue_Transcode :: Item is already pending verification. Will remove from queue and continue; %s" % queueItem.name, logger.DEBUG)
          queueItem = None
        elif queueItem.priority == QueuePriorities.HIGH and not media.is_pending(queueItem.job._file):
          logger.log("Queue_Transcode :: Item is no longer pending verification. Will remove from queue and continue; %s" % queueItem.name, logger.DEBUG)
          queueItem = None
        else:

          # launch the queue item in a thread
          # TODO: improve thread name
          threadName = self.queue_name + '-' + queueItem.get_thread_name()
          self.thread = threading.Thread(None, queueItem.execute, threadName)
          self.thread.start()

          self.currentItem = queueItem
Пример #6
0
 def add_item(self, item):
   if not self.is_in_queue(item):
     with self.queue_lock:
       item.added = datetime.datetime.now()
       self.queues[item.priority].append(item)
     return True
   else:
     if mediamanager.VERBOSE:
       logger.log(u"Not adding item, it's already in the queue", logger.DEBUG)
     return False
Пример #7
0
  def finalize(self):

    # Create some variables to contain all the paths and basenames
    self._pending_file_tempbasename = self._outfile_base + '.' + 'copytemp'
    self._pending_file_temppath = os.path.join(os.path.dirname(self._file.path), self._pending_file_tempbasename)
    self._pending_file_basename = self._outfile_base + '.' + mediamanager.TRANSCODER_PENDING_EXTENSION
    self._pending_file_path = os.path.join(os.path.dirname(self._file.path), self._pending_file_basename)

    # First copy file to final destination directory with a temporary name
    try:
      shutil.copyfile(self._muxed_file_path, self._pending_file_temppath)
    except IOError, e:
      logger.log("finalize() :: Exception raised during copy to temp location, not writable; %s" % self._file.path, logger.DEBUG)
      return False
Пример #8
0
def is_compliant_audio(fileInfo, stream_id=None):
  if stream_id == None:
    for stream in fileInfo.audioStreams:
      if (re.match(re.compile('^.*(' + mediamanager.COMPLIANCE['Media']['Audio']['Codec'] + ').*$', re.I), stream['codec']) is None):
        return False
    return True
  else:
    try:
      if (re.match(re.compile('^.*(' + mediamanager.COMPLIANCE['Media']['Audio']['Codec'] + ').*$', re.I), fileInfo.audioStreams[stream_id]['codec']) is None):
        return False
      else:
        return True
    except Exception, e:
      logger.log(u"is_compliant_audio :: Exception caught; %s" % e, logger.DEBUG)
      return False
Пример #9
0
 def stop(self):
   logger.log("%s :: Stop has been called" % self.queue_name, logger.DEBUG)
   try:
     if self.thread.isAlive():
       self.currentItem.finish()
       logger.log("%s :: Waiting for queue thread to stop" % self.queue_name, logger.DEBUG)
       self.thread.join(10)
       self.thread = None
     else:
       logger.log("%s :: Thread is not running" % self.queue_name, logger.DEBUG)
   except Exception, e:
     logger.log("%s :: Exception was caught; %s" % (self.queue_name, e), logger.DEBUG)
Пример #10
0
  def runAction(self):
    while True:

      current_time = datetime.datetime.now()
      should_run = False

      # check if interval has passed
      if (len(self.action.queues[queue_generic.QueuePriorities.HIGH])) > 0:
        should_run = True
      elif (len(self.action.queues[queue_generic.QueuePriorities.NORMAL]) > 0 and len(media.PENDING.keys()) <= mediamanager.TRANSCODER_PENDING_LIMIT):
        should_run = True
      elif (len(self.action.queues[queue_generic.QueuePriorities.LOW]) > 0 and len(media.PENDING.keys()) <= mediamanager.TRANSCODER_PENDING_LIMIT):
        should_run = True
      if should_run:
        self.lastRun = current_time
        try:
          if logger.LOG_EXTRA_DEBUG:
            logger.log(u"Starting new thread: " + self.threadName, logger.DEBUG)
          self.action.run()
        except Exception, e:
          logger.log(u"Exception generated in thread " + self.threadName, logger.ERROR)
          logger.log(repr(traceback.format_exc()), logger.DEBUG)
          self.abort = True

      if self.abort:
        self.abort = False
        try:
          self.action.stop()
        except:
          pass
        finally:
          self.thread = None
        return

      time.sleep(1)
Пример #11
0
  def remux_files(self):

    # Create our output file object for ffmpegwrapper
    if mediamanager.COMPLIANCE['Media']['Container']['Codec'] == 'Matroska':
      self._muxed_file_basename = self._outfile_base + '.' + 'mkv'
    elif mediamanager.COMPLIANCE['Media']['Container']['Codec'] == 'MPEG-4':
      self._muxed_file_basename = self._outfile_base + '.' + 'mp4'
    self._muxed_file_path = os.path.join(mediamanager.TRANSCODER_TEMPDIR, self._muxed_file_basename)
    output_file = Output(self._muxed_file_path)

    # Create our FFmpeg job object with path to ffmpeg binary
    remux_job = FFmpeg('/usr/bin/ffmpeg')

    # Iterate for self.finalfiles and create Input() objects for input files and insert at the end of the list
    for _file in self.finalfiles:
      input_file = Input(_file)
      remux_job.insert(len(remux_job), input_file)

    # Add video codec object with 'copy' as the codec specified so it just muxes the streams
    remux_job.insert(len(remux_job), VideoCodec('copy'))

    # Add audio codec object with 'copy' as the codec specified so it just muxes the streams
    remux_job.insert(len(remux_job), AudioCodec('copy'))

    # Add Output() object to specify the output path and container
    remux_job.insert(len(remux_job), output_file)

    # Begin remux job and iterate over the piped stdout from the command logging it to debug
    with remux_job as self._process:
      while not self.abort and self._process.running:
        for line in self._process.readlines():
          if mediamanager.VERBOSE:
            logger.log(line, logger.DEBUG)
      if self._process.failed:
        return False
      elif self._process.successful:
        return True
      else:
        return False
Пример #12
0
  def finish(self):

    # Lock the finish operation so only one thread can cleanup at a time
    with self.__FINISH_LOCK__:

      # If another thread cleaned up while waiting for the lock than just return
      if self.__FINISHED__:
        return

      # Save the current self.abort value so we can late determine if finish() was called because of an abort
      wasaborted = self.abort

      logger.log("TranscodeJob :: Finish has been called", logger.DEBUG)
      try:
        self.abort = True

        # Check if self.process exists and running
        if self._process is not None and self._process.poll() is None:
          # Kill the popen process
          self._process.terminate()
          # Release the reference to the process
          self._process = None
      except Exception, e:
        logger.log("TranscodeJob :: Exception caught in finish(); %s" % e, logger.DEBUG)

      # Delete all contents from tempdir since we are either done or aborted
      filelist = os.listdir(mediamanager.TRANSCODER_TEMPDIR)
      for f in filelist:
        os.remove(os.path.join(mediamanager.TRANSCODER_TEMPDIR ,f))

      # If finish() was called and being aborted during operation than check if a pending file was created and delete it
      outfile_basename = self._outfile_base + '.' + mediamanager.TRANSCODER_PENDING_EXTENSION
      if wasaborted and os.path.isfile(os.path.join(os.path.dirname(self._file.path), outfile_basename)):
        os.remove(os.path.join(os.path.dirname(self._file.path), outfile_basename))

      self.__FINISHED__ = True
Пример #13
0
  def demux_file(self):

    # Return if we couldn't get the base file name without extension from the self._file.basename
    if not self._outfile_base:
      logger.log("Unable to get base file name; %s" % self._file.path, logger.DEBUG)
      return False

    # Create our Input() object to specify the file we will be demuxing
    input_file = Input(self._file.path)

    # Create a list of the codecs with maps or input stream to output file
    codecs = []

    # Create a list to contain the paths of all the output files
    self.demuxfiles = []

    # Iterate over self._file.videoStreams and create codecs for each video stream with 'copy' specified so no transcoding is done
    for i, stream in enumerate(self._file.videoStreams):
      stream_id = int(stream['track_id']) - 1
      outfile_path = os.path.join(mediamanager.TRANSCODER_TEMPDIR, self._outfile_base + '.video.' + str(stream_id) + '.mkv')
      video_codec = VideoCodec('copy')
      video_codec = video_codec.mapstream("0:%d" % stream_id, outfile_path)
      self.demuxfiles.append(outfile_path)
      codecs.append(video_codec)

    # Iterate over self._file.audioStreams and create codecs for each audio stream with 'copy' specified so no transcoding is done
    for i, stream in enumerate(self._file.audioStreams):
      stream_id = int(stream['track_id']) - 1
      outfile_path = os.path.join(mediamanager.TRANSCODER_TEMPDIR, self._outfile_base + '.audio.' + str(stream_id) + '.mkv')
      audio_codec = AudioCodec('copy')
      audio_codec = audio_codec.mapstream("0:%d" % stream_id, outfile_path)
      self.demuxfiles.append(outfile_path)
      codecs.append(audio_codec)

    # Create FFmpeg() object to begin demux operation
    demux_job = FFmpeg('/usr/bin/ffmpeg', input_file)

    # Iterate over items in codecs list and insert them at the end of the FFmpeg() object's list
    for codec in codecs:
      demux_job.insert(len(demux_job), codec)

    # Begin demux operation and iterate over piped stdout from the popen process
    logger.log("demux_job: %s" % demux_job, logger.DEBUG)
    with demux_job as self._process:
      while  not self.abort and self._process.running:
        for line in self._process.readlines():
          if mediamanager.VERBOSE:
            logger.log(line, logger.DEBUG)
      if self._process.failed:
        return False
      elif self._process.successful:
        return True
      else:
        return False
Пример #14
0
def cleanPending():
  with PENDING_LOCK:

    _files = []

    pattern = re.compile('^.*\.(' + mediamanager.TRANSCODER_PENDING_EXTENSION + ')$', re.I)

    for _source in mediamanager.SOURCES:
      if re.match('^(~).*$', _source) is not None:
        _files.extend(Files.getFilesFromDir(os.path.join(os.path.expanduser("~"), re.match('^~\/(.*)$', _source).group(1)), pattern))
      else:
        _files.extend(Files.getFilesFromDir(_source, pattern))

    for _file in _files:
      try:
        logger.log("CleanPending :: Removing pending file; %s" % _file.path, logger.DEBUG)
        os.remove(_file.path)
      except Exception, e:
        logger.log("CleanPending :: Exception raised cleaing up pending file; %s" % _file.path, logger.DEBUG)
        logger.log("CleanPending :: Exception :: %s" % e, logger.DEBUG)
Пример #15
0
def halt():

  global __INITIALIZED__, schedulerScanner

  with INIT_LOCK:

    if __INITIALIZED__:

      logger.log(u'Aborting all threads')

      schedulerScanner.abort = True
      logger.log(u'Waiting for the SCANNER thread to exit')
      try:
        schedulerScanner.thread.join(10)
      except:
        pass
      schedulerTranscode.abort = True
      logger.log(u'Waiting for the TRANSCODER thread to exit')
      try:
        schedulerTranscode.thread.join(10)
      except:
        pass

      __INITIALIZED__ = False
Пример #16
0
    def runAction(self):

        while True:

            current_time = datetime.datetime.now()
            should_run = False

            # check if interval has passed
            if current_time - self.lastRun >= self.cycleTime:
                # check if wanting to start around certain time taking interval into account
                if self.start_time:
                    hour_diff = current_time.time().hour - self.start_time.hour
                    if hour_diff >= 0 and hour_diff < self.cycleTime.seconds / 3600:
                        should_run = True
                    else:
                        # set lastRun to only check start_time after another cycleTime
                        self.lastRun = current_time
                else:
                    should_run = True

            if should_run:
                self.lastRun = current_time
                try:
                    if logger.LOG_EXTRA_DEBUG:
                        logger.log(u"Starting new thread: " + self.threadName, logger.DEBUG)
                    self.action.run()
                except Exception, e:
                    logger.log(u"Exception generated in thread " + self.threadName, logger.ERROR)
                    logger.log(repr(traceback.format_exc()), logger.DEBUG)

            if self.abort:
                self.abort = False
                self.thread = None
                return

            time.sleep(1)
Пример #17
0
 def pause(self):
   logger.log(u"Pausing queue")
   self.min_priority = 999999999999
Пример #18
0
 def finish(self):
   logger.log(u"QueueTranscode :: Finish has been called; %s" % self.thread_name, logger.DEBUG)
   self.job.finish()
   self.amActive = False
Пример #19
0
  def run(self):

    global MEDIA, NONCOMPLIANT

    if self.amActive == True:
      if mediamanager.SCANNER_VERBOSE:
        logger.log(u'Scanner is still running, not starting it again', logger.MESSAGE)
      return

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'Scanner has started', logger.MESSAGE)
    self.amActive = True

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'Scanner is starting ScanForMedia()', logger.DEBUG)
    MEDIA = Scan.ScanForMedia()
    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'Scanner has completed ScanForMedia()', logger.DEBUG)
      logger.log(u'Scanner is starting updatePending()', logger.DEBUG)
    if updatePending():
      if mediamanager.SCANNER_VERBOSE:
        logger.log(u'Scanner has completed updatePending()', logger.DEBUG)
    else:
      if mediamanager.SCANNER_VERBOSE:
        logger.log(u'Scanner is skipping updatePending() due to insufficient time lapse since last update', logger.DEBUG)

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'Scanner is queing items for transcode', logger.DEBUG)
    NONCOMPLIANT = Scan.ScanForCompliance(MEDIA.values())
    transcode_files = []

    for _file in NONCOMPLIANT:
      if not re.match('^(.*)\..*$', _file.basename).group(1) in PENDING.keys():
        transcode_files.append(_file)

    for _file in transcode_files:
      queueItem = None
      job = transcode.Factory.TranscodeJobFactory(_file)
      if job is not None:
        queueItem = mediamanager.queue_transcode.QueueItemTranscode(job)
      else:
        if mediamanager.SCANNER_VERBOSE:
          logger.log(u"Scanner TranscodeJob is None; %s" % _file.path, logger.DEBUG)

      if queueItem is not None and mediamanager.schedulerTranscode.action.add_item(queueItem):
        if mediamanager.SCANNER_VERBOSE:
          logger.log(u'Scanner has queued item for transcode; %s' % _file.path, logger.DEBUG)
      else:
        if queueItem is None:
          if mediamanager.SCANNER_VERBOSE:
            logger.log(u'Scanner unable to queue item, queueItem is None; %s' % _file.path, logger.DEBUG)

    if mediamanager.SCANNER_VERBOSE:
      logger.log(u'Scanner has completed', logger.MESSAGE)

    self.amActive = False
Пример #20
0
 def unpause(self):
   logger.log(u"Unpausing queue")
   self.min_priority = 0
Пример #21
0
      return False
    except Exception, e:
      logger.log("finalize() :: Exception raised during copy to temp location, unknown; %s" % self._file.path, logger.DEBUG)
      logger.log("finalize() :: Exception :: %s" % e, logger.DEBUG)
      try:
        if os.path.isfile(self._pending_file_temppath):
          os.remove(self._pending_file_temppath)
      except Exception, e:
        logger.log("finalize() :: Exception raised cleaing up partially copied file; %s" % self._file.path, logger.DEBUG)
      return False

    # Second do a move operation from temp basename to final basename
    try:
      shutil.move(self._pending_file_temppath, self._pending_file_path)
    except Exception, e:
      logger.log("finalize() :: Exception raised during move to final location, unknown; %s" % self._file.path, logger.DEBUG)
      logger.log("finalize() :: Exception :: %s" % e, logger.DEBUG)
      try:
        if os.path.isfile(self._pending_file_temppath):
          os.remove(self._pending_file_temppath)
      except Exception, e:
        logger.log("finalize() :: Exception raised cleaing up partially copied file; %s" % self._file.path, logger.DEBUG)
      try:
        if os.path.isfile(self._pending_file_path):
          os.remove(self._pending_file_path)
      except Exception, e:
        logger.log("finalize() :: Exception raised cleaing up partially moved file; %s" % self._file.path, logger.DEBUG)
      return False

    return True
Пример #22
0
 def ScanForCompliance(cls, files):
   retval = []
   if mediamanager.SCANNER_VERBOSE:
     logger.log(u"ScanForCompliance :: Starting", logger.DEBUG)
   for fileInfo in files:
     if isinstance(fileInfo, Files.VideoInfo):
       compliant = True
       if is_compliant_container(fileInfo):
         if mediamanager.SCANNER_VERBOSE:
           logger.log(u"ScanForCompliance :: File has compliant container; %s" % fileInfo.path, logger.DEBUG)
       else:
         if mediamanager.SCANNER_VERBOSE:
           logger.log(u"ScanForCompliance :: File has non-compliant container %s; %s" % (fileInfo.container, fileInfo.path))
         compliant = False
       for i, stream in enumerate(fileInfo.videoStreams):
         if is_compliant_video(fileInfo, stream_id=i):
           if mediamanager.SCANNER_VERBOSE:
             logger.log(u"ScanForCompliance :: File has compliant video stream at ID %s; %s" % (i, fileInfo.path), logger.DEBUG)
         else:
           if mediamanager.SCANNER_VERBOSE:
             logger.log(u"ScanForCompliance :: File has non-compliant video stream at ID %s of codec %s; %s" % (i, stream['codec'], fileInfo.path), logger.DEBUG)
           compliant = False
       for i, stream in enumerate(fileInfo.audioStreams):
         if is_compliant_audio(fileInfo, stream_id=i):
           if mediamanager.SCANNER_VERBOSE:
             logger.log(u"ScanForCompliance :: File has compliant audio stream at ID %s; %s" % (i, fileInfo.path), logger.DEBUG)
         else:
           if mediamanager.SCANNER_VERBOSE:
             logger.log(u"ScanForCompliance :: File has non-compliant audio stream at ID %s of codec %s; %s" % (i, stream['codec'], fileInfo.path), logger.DEBUG)
           compliant = False
       if not compliant:
         retval.append(fileInfo)
   if mediamanager.SCANNER_VERBOSE:
     logger.log(u"ScanForCompliance :: Completed", logger.DEBUG)
   return retval
Пример #23
0
  def run(self):
    # List of all finalized files that need to be remuxed into final product
    self.finalfiles = []
    logger.log("Entering transcode job; %s" % self._file.path, logger.MESSAGE)

    #Beginning demux operations
    logger.log("Beginning deumx; %s" % self._file.path, logger.DEBUG)
    demux_successful = self.demux_file()
    logger.log("Completed deumx; %s" % self._file.path, logger.DEBUG)
    if not demux_successful:
      logger.log("Demux failed; %s" % self._file.path, logger.MESSAGE)
      logger.log("Exiting transcode job; %s" % self._file.path, logger.MESSAGE)
      return
    else:
      logger.log("Demux successful; %s" % self._file.path, logger.DEBUG)

    # Since we aren't transcoding video just identify the streams and add them to the self.finalfiles list
    for _file in self.demuxfiles:
      if re.match('^.*\.(video.\d)\..*$', _file) is not None:
        self.finalfiles.append(_file)

    # Check if we need to abort before proceeding
    if self.abort:
      self.finish()
      return

    # Begin audio transcoding operation looping over demuxed files where contents is audio
    convert_results = []
    for _file in self.demuxfiles:
      if re.match('^.*\.(audio.\d)\..*$', _file) is not None:
        logger.log("Beginning remediate audio; %s" % _file, logger.DEBUG)
        result = self.remediate_audio(_file)
        if result:
          logger.log("Remediate audio successful; %s" % _file, logger.DEBUG)
        else:
          logger.log("Remediate audio successful; %s" % _file, logger.DEBUG)
        convert_results.append(result)
    if False in convert_results:
      logger.log("Remediation of audio Failed; %s" % _file, logger.DEBUG)
      logger.log("Exiting transcode job; %s" % self._file.path, logger.MESSAGE)
      return

    # Check if we need to abort before proceeding
    if self.abort:
      self.finish()
      return

    # Begin remuxing operation
    logger.log("Beginning remux of sreams; %s" % self._file.path, logger.DEBUG)
    if self.remux_files():
      logger.log("Remuxing of sreams successful; %s" % self._file.path, logger.DEBUG)
    else:
      logger.log("Remuxing of streams unsuccessful; %s" % self._file.path, logger.DEBUG)
      logger.log("Exiting transcode job; %s" % self._file.path, logger.MESSAGE)
      return

    # Perform final operation of copying file from temp to src file's parent directory and renaming according to user set pending extension
    logger.log("Beginning finalization of job; %s" % self._file.path, logger.DEBUG)
    if not self.finalize():
      logger.log("Finalization of job failed; %s" % self._file.path, logger.DEBUG)
      logger.log("Exiting transcode job; %s" % self._file.path, logger.MESSAGE)
      return
    else:
      logger.log("Finalization of job successful; %s" % self._file.path, logger.DEBUG)

    # All done. State some logging.
    logger.log("Completed job execution; %s" % self._file.path, logger.DEBUG)
    logger.log("Exiting transcode job; %s" % self._file.path, logger.MESSAGE)
Пример #24
0
 def run(self):
   logger.log(u'VerificationDeclineJob :: Job run for file %s' % self.name)
Пример #25
0
 def run(self):
   logger.log(u'VerificationAcceptJob :: Job run for file %s' % self.name)