Merge pull request #640 from JackDandy/feature/ChangeProcessEps

Change process episodes with utf8 dir and nzb names, handle failed ep…
This commit is contained in:
JackDandy 2016-02-04 16:05:55 +00:00
commit 4743d77bbd
5 changed files with 65 additions and 20 deletions

View file

@ -24,6 +24,7 @@
* Change refactor email notifier
* Change emails to Unicode aware
* Add force episode recent search to API
* Change process episodes with utf8 dir and nzb names, handle failed episodes without a dir, add log output streaming
### 0.11.5 (2016-02-01 19:40:00 UTC)

View file

@ -23,6 +23,7 @@ import os
import re
import subprocess
import stat
import threading
import sickbeard
@ -60,7 +61,7 @@ class PostProcessor(object):
IGNORED_FILESTRINGS = ['/.AppleDouble/', '.DS_Store']
def __init__(self, file_path, nzb_name=None, process_method=None, force_replace=None, use_trash=None):
def __init__(self, file_path, nzb_name=None, process_method=None, force_replace=None, use_trash=None, webhandler=None):
"""
Creates a new post processor with the given file path and optionally an NZB name.
@ -86,6 +87,8 @@ class PostProcessor(object):
self.use_trash = use_trash
self.webhandler = webhandler
self.in_history = False
self.release_group = None
@ -817,7 +820,7 @@ class PostProcessor(object):
Post-process a given file
"""
self._log(u'Processing %s%s' % (self.file_path, (u'<br />.. from nzb %s' % str(self.nzb_name), u'')[None is self.nzb_name]))
self._log(u'Processing %s%s' % (self.file_path, (u'<br />.. from nzb %s' % self.nzb_name, u'')[None is self.nzb_name]))
if ek.ek(os.path.isdir, self.file_path):
self._log(u'File %s<br />.. seems to be a directory' % self.file_path)
@ -963,6 +966,16 @@ class PostProcessor(object):
if sickbeard.ANIDB_USE_MYLIST and ep_obj.show.is_anime:
self._add_to_anidb_mylist(self.file_path)
if self.webhandler:
def keep_alive(webh, stop_event):
while not stop_event.is_set():
stop_event.wait(60)
webh('.')
webh(u'\n')
keepalive_stop = threading.Event()
keepalive = threading.Thread(target=keep_alive, args=(self.webhandler, keepalive_stop))
try:
# move the episode and associated files to the show dir
args_link = {'file_path': self.file_path, 'new_path': dest_path,
@ -971,6 +984,9 @@ class PostProcessor(object):
args_cpmv = {'subtitles': sickbeard.USE_SUBTITLES and ep_obj.show.subtitles,
'action_tmpl': u' %s<br />.. to %s'}
args_cpmv.update(args_link)
if self.webhandler:
self.webhandler('Processing method is "%s"' % self.process_method)
keepalive.start()
if 'copy' == self.process_method:
self._copy(**args_cpmv)
elif 'move' == self.process_method:
@ -984,7 +1000,11 @@ class PostProcessor(object):
raise exceptions.PostProcessingFailed(u'Unable to move the files to the new location')
except (OSError, IOError):
raise exceptions.PostProcessingFailed(u'Unable to move the files to the new location')
finally:
if self.webhandler:
#stop the keep_alive
keepalive_stop.set()
# download subtitles
dosubs = sickbeard.USE_SUBTITLES and ep_obj.show.subtitles

View file

@ -47,10 +47,11 @@ except ImportError:
class ProcessTVShow(object):
""" Process a TV Show """
def __init__(self):
def __init__(self, webhandler=None):
self.files_passed = 0
self.files_failed = 0
self._output = []
self.webhandler = webhandler
@property
def any_vid_processed(self):
@ -63,6 +64,10 @@ class ProcessTVShow(object):
def _buffer(self, text=None):
if None is not text:
self._output.append(text)
if self.webhandler:
logger_msg = re.sub(r'(?i)<br(?:[\s/]+)>', '\n', text)
logger_msg = re.sub('(?i)<a[^>]+>([^<]+)<[/]a>', r'\1', logger_msg)
self.webhandler('%s%s' % (logger_msg, u'\n'))
def _log_helper(self, message, log_level=logger.DEBUG):
logger_msg = re.sub(r'(?i)<br(?:[\s/]+)>\.*', '', message)
@ -153,22 +158,26 @@ class ProcessTVShow(object):
"""
# if they passed us a real directory then assume it's the one we want
if ek.ek(os.path.isdir, dir_name):
if dir_name and ek.ek(os.path.isdir, dir_name):
self._log_helper(u'Processing folder... ' + dir_name)
dir_name = ek.ek(os.path.realpath, dir_name)
# if the client and SickGear are not on the same machine translate the directory in a network directory
elif sickbeard.TV_DOWNLOAD_DIR and ek.ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR)\
elif dir_name and sickbeard.TV_DOWNLOAD_DIR and ek.ek(os.path.isdir, sickbeard.TV_DOWNLOAD_DIR)\
and ek.ek(os.path.normpath, dir_name) != ek.ek(os.path.normpath, sickbeard.TV_DOWNLOAD_DIR):
dir_name = ek.ek(os.path.join, sickbeard.TV_DOWNLOAD_DIR, ek.ek(os.path.abspath, dir_name).split(os.path.sep)[-1])
self._log_helper(u'SickGear PP Config, completed TV downloads folder: ' + sickbeard.TV_DOWNLOAD_DIR)
self._log_helper(u'Trying to use folder... ' + dir_name)
# if we didn't find a real directory then quit
if not ek.ek(os.path.isdir, dir_name):
self._log_helper(
u'Unable to figure out what folder to process. If your downloader and SickGear aren\'t on the same PC then make sure you fill out your completed TV download folder in the PP config.')
return self.result
if not dir_name or not ek.ek(os.path.isdir, dir_name):
if nzb_name and failed:
self._process_failed(dir_name, nzb_name)
return self.result
else:
self._log_helper(
u'Unable to figure out what folder to process. If your downloader and SickGear aren\'t on the same PC then make sure you fill out your completed TV download folder in the PP config.')
return self.result
path, dirs, files = self._get_path_dir_files(dir_name, nzb_name, pp_type)
@ -503,7 +512,7 @@ class ProcessTVShow(object):
cur_video_file_path = ek.ek(os.path.join, process_path, cur_video_file)
try:
processor = postProcessor.PostProcessor(cur_video_file_path, nzb_name, process_method, force_replace, use_trash=use_trash)
processor = postProcessor.PostProcessor(cur_video_file_path, nzb_name, process_method, force_replace, use_trash=use_trash, webhandler=self.webhandler)
file_success = processor.process()
process_fail_message = ''
except exceptions.PostProcessingFailed as e:
@ -577,6 +586,6 @@ class ProcessTVShow(object):
# backward compatibility prevents the case of this function name from being updated to PEP8
def processDir(dir_name, nzb_name=None, process_method=None, force=False, force_replace=None, failed=False, type='auto', cleanup=False):
def processDir(dir_name, nzb_name=None, process_method=None, force=False, force_replace=None, failed=False, type='auto', cleanup=False, webhandler=None):
# backward compatibility prevents the case of this function name from being updated to PEP8
return ProcessTVShow().process_dir(dir_name, nzb_name, process_method, force, force_replace, failed, type, cleanup)
return ProcessTVShow(webhandler).process_dir(dir_name, nzb_name, process_method, force, force_replace, failed, type, cleanup)

View file

@ -285,7 +285,7 @@ def determineReleaseName(dir_name=None, nzb_name=None):
logger.log(u'Using nzb name for release name.')
return nzb_name.rpartition('.')[0]
if dir_name is None:
if not dir_name or not ek.ek(os.path.isdir, dir_name):
return None
# try to get the release name from nzb/nfo

View file

@ -28,6 +28,7 @@ import re
import time
import traceback
import urllib
import threading
from mimetypes import MimeTypes
from Cheetah.Template import Template
@ -287,6 +288,10 @@ class IsAliveHandler(BaseHandler):
class WebHandler(BaseHandler):
def __init__(self, *arg, **kwargs):
super(BaseHandler, self).__init__(*arg, **kwargs)
self.lock = threading.Lock()
def page_not_found(self):
t = PageTemplate(headers=self.request.headers, file='404.tmpl')
return t.respond()
@ -308,6 +313,11 @@ class WebHandler(BaseHandler):
if result:
self.finish(result)
def send_message(self, message):
with self.lock:
self.write(message)
self.flush()
post = get
@ -1043,9 +1053,12 @@ class Home(MainHandler):
else:
if change:
output.append(change)
change = None
if line.startswith('* '):
change_parts = re.findall(r'^[\*\W]+(Add|Change|Fix|Port|Remove|Update)\W(.*)', line)
change = change_parts and {'type': change_parts[0][0], 'text': change_parts[0][1].strip()} or {}
elif not max_rel:
break
elif line.startswith('### '):
rel_data = re.findall(r'(?im)^###\W*([^\s]+)\W\(([^\)]+)\)', line)
rel_data and output.append({'type': 'rel', 'ver': rel_data[0][0], 'date': rel_data[0][1]})
@ -1053,8 +1066,6 @@ class Home(MainHandler):
elif line.startswith('# '):
max_data = re.findall(r'^#\W*([\d]+)\W*$', line)
max_rel = max_data and helpers.tryInt(max_data[0], None) or 5
if not max_rel:
break
if change:
output.append(change)
@ -2110,17 +2121,21 @@ class HomePostProcess(Home):
return t.respond()
def processEpisode(self, dir=None, nzbName=None, jobName=None, quiet=None, process_method=None, force=None,
force_replace=None, failed='0', type='auto', **kwargs):
force_replace=None, failed='0', type='auto', stream='0', **kwargs):
if not dir:
if not dir and ('0' == failed or not nzbName):
self.redirect('/home/postprocess/')
else:
result = processTV.processDir(dir, nzbName, process_method=process_method, type=type,
result = processTV.processDir(dir.decode('utf-8') if dir else None, nzbName.decode('utf-8') if nzbName else None,
process_method=process_method, type=type,
cleanup='cleanup' in kwargs and kwargs['cleanup'] in ['on', '1'],
force=force in ['on', '1'],
force_replace=force_replace in ['on', '1'],
failed=not '0' == failed)
failed='0' != failed,
webhandler=self.send_message if stream != '0' else None)
if '0' != stream:
return
result = re.sub(r'(?i)<br(?:[\s/]+)>', '\n', result)
if None is not quiet and 1 == int(quiet):
return u'%s' % re.sub('(?i)<a[^>]+>([^<]+)<[/]a>', r'\1', result)