Browse Source

Add usage of NZB-meta data and X-headers for Sorting.

Meta records: "episodename", "propername" and "year".
X-headers: "x-dnzb-episodename", "x-dnzb-propername" and "x-dnzb-year".
Controlled by an option.
pull/121/head
shypike 12 years ago
parent
commit
3b3759e81e
  1. 1
      sabnzbd/cfg.py
  2. 4
      sabnzbd/interface.py
  3. 5
      sabnzbd/postproc.py
  4. 199
      sabnzbd/tvsort.py
  5. 6
      sabnzbd/urlgrabber.py

1
sabnzbd/cfg.py

@ -128,6 +128,7 @@ folder_rename = OptionBool('misc', 'folder_rename', True)
folder_max_length = OptionNumber('misc', 'folder_max_length', DEF_FOLDER_MAX, 20, 65000)
pause_on_pwrar = OptionBool('misc', 'pause_on_pwrar', True)
prio_sort_list = OptionList('misc', 'prio_sort_list')
enable_meta = OptionBool('misc', 'enable_meta', True)
safe_postproc = OptionBool('misc', 'safe_postproc', True)
empty_postproc = OptionBool('misc', 'empty_postproc', False)

4
sabnzbd/interface.py

@ -1231,8 +1231,8 @@ SPECIAL_BOOL_LIST = \
'never_repair', 'allow_streaming', 'ignore_unrar_dates', 'rss_filenames',
'osx_menu', 'osx_speed', 'win_menu', 'uniconfig', 'use_pickle', 'allow_incomplete_nzb',
'randomize_server_ip', 'no_ipv6', 'keep_awake', 'overwrite_files', 'empty_postproc',
'web_watchdog', 'wait_for_dfolder', 'warn_empty_nzb', 'enable_recursive', 'sanitize_safe'
'web_watchdog', 'wait_for_dfolder', 'warn_empty_nzb', 'enable_recursive', 'sanitize_safe',
'enable_meta'
)
SPECIAL_VALUE_LIST = \
( 'size_limit', 'folder_max_length', 'fsys_type', 'movie_rename_limit', 'nomedia_marker',

5
sabnzbd/postproc.py

@ -307,7 +307,10 @@ def process_job(nzo):
complete_dir = real_path(cfg.complete_dir.get_path(), catdir)
## TV/Movie/Date Renaming code part 1 - detect and construct paths
file_sorter = Sorter(cat)
if cfg.enable_meta():
file_sorter = Sorter(nzo, cat)
else:
file_sorter = Sorter(None, cat)
complete_dir = file_sorter.detect(dirname, complete_dir)
if file_sorter.sort_file:
one_folder = False

199
sabnzbd/tvsort.py

@ -31,7 +31,7 @@ from sabnzbd.misc import move_to_path, cleanup_empty_directories, get_unique_pat
get_unique_filename, get_ext, renamer, sanitize_foldername
from sabnzbd.constants import series_match, date_match, year_match, sample_match
import sabnzbd.cfg as cfg
from sabnzbd.encoding import titler
from sabnzbd.encoding import titler, latin1
RE_SAMPLE = re.compile(sample_match, re.I)
# Do not rename .vob files as they are usually DVD's
@ -96,31 +96,32 @@ def move_to_parent_folder(workdir):
class Sorter(object):
""" Generic Sorter class
"""
def __init__(self, cat):
def __init__(self, nzo, cat):
self.sorter = None
self.type = None
self.sort_file = False
self.nzo = nzo
self.cat = cat
self.ext = ''
def detect(self, dirname, complete_dir):
""" Detect which kind of sort applies
"""
self.sorter = SeriesSorter(dirname, complete_dir, self.cat)
self.sorter = SeriesSorter(self.nzo, dirname, complete_dir, self.cat)
if self.sorter.matched:
complete_dir = self.sorter.get_final_path()
self.type = 'tv'
self.sort_file = True
return complete_dir
self.sorter = DateSorter(dirname, complete_dir, self.cat)
self.sorter = DateSorter(self.nzo, dirname, complete_dir, self.cat)
if self.sorter.matched:
complete_dir = self.sorter.get_final_path()
self.type = 'date'
self.sort_file = True
return complete_dir
self.sorter = GenericSorter(dirname, complete_dir, self.cat)
self.sorter = GenericSorter(self.nzo, dirname, complete_dir, self.cat)
if self.sorter.matched:
complete_dir = self.sorter.get_final_path()
self.type = 'movie'
@ -182,11 +183,12 @@ class Sorter(object):
class SeriesSorter(object):
""" Methods for Series Sorting
"""
def __init__(self, dirname, path, cat):
def __init__(self, nzo, dirname, path, cat):
self.matched = False
self.original_dirname = dirname
self.original_path = path
self.nzo = nzo
self.cat = cat
self.sort_string = cfg.tv_sort_string()
self.cats = cfg.tv_categories()
@ -252,8 +254,8 @@ class SeriesSorter(object):
def get_shownames(self):
''' Get the show name from the match object and format it '''
# Get the formatted title and alternate title formats
self.show_info['show_tname'], self.show_info['show_tname_two'], self.show_info['show_tname_three'] = get_titles(self.match_obj, self.original_dirname, True)
self.show_info['show_name'], self.show_info['show_name_two'], self.show_info['show_name_three'] = get_titles(self.match_obj, self.original_dirname)
self.show_info['show_tname'], self.show_info['show_tname_two'], self.show_info['show_tname_three'] = get_titles(self.nzo, self.match_obj, self.original_dirname, True)
self.show_info['show_name'], self.show_info['show_name_two'], self.show_info['show_name_three'] = get_titles(self.nzo, self.match_obj, self.original_dirname)
def get_seasons(self):
@ -302,7 +304,7 @@ class SeriesSorter(object):
def get_showdescriptions(self):
''' Get the show descriptions from the match object and format them '''
self.show_info['ep_name'], self.show_info['ep_name_two'], self.show_info['ep_name_three'] = get_descriptions(self.match_obj, self.original_dirname)
self.show_info['ep_name'], self.show_info['ep_name_two'], self.show_info['ep_name_three'] = get_descriptions(self.nzo, self.match_obj, self.original_dirname)
def get_values(self):
@ -518,7 +520,7 @@ def check_for_sequence(regex, files):
class GenericSorter(object):
""" Methods for Generic Sorting
"""
def __init__(self, dirname, path, cat):
def __init__(self, nzo, dirname, path, cat):
self.matched = False
self.original_dirname = dirname
@ -527,6 +529,7 @@ class GenericSorter(object):
self.extra = cfg.movie_sort_extra()
self.cats = cfg.movie_categories()
self.cat = cat
self.nzo = nzo
self.filename_set = ''
self.fname = '' # Value for %fn substitution in folders
self.final_path = ''
@ -567,23 +570,30 @@ class GenericSorter(object):
""" Collect and construct all the values needed for path replacement
"""
## - Get Year
dirname = self.original_dirname.replace('_', ' ')
RE_YEAR = re.compile(year_match, re.I)
year_m = RE_YEAR.search(dirname)
if year_m:
# Find the last matched date
# Keep year_m to use in get_titles
year = RE_YEAR.findall(dirname)[-1][0]
self.movie_info['year'] = year
if self.nzo:
year = self.nzo.nzo_info.get('year') or self.nzo.meta.get('year')[0]
else:
self.movie_info['year'] = ''
year = ''
if year:
year_m = None
else:
dirname = self.original_dirname.replace('_', ' ')
RE_YEAR = re.compile(year_match, re.I)
year_m = RE_YEAR.search(dirname)
if year_m:
# Find the last matched date
# Keep year_m to use in get_titles
year = RE_YEAR.findall(dirname)[-1][0]
else:
year = ''
self.movie_info['year'] = year
## - Get Decades
self.movie_info['decade'], self.movie_info['decade_two'] = get_decades(self.movie_info['year'])
self.movie_info['decade'], self.movie_info['decade_two'] = get_decades(year)
## - Get Title
self.movie_info['ttitle'], self.movie_info['ttitle_two'], self.movie_info['ttitle_three'] = get_titles(year_m, self.original_dirname, True)
self.movie_info['title'], self.movie_info['title_two'], self.movie_info['title_three'] = get_titles(year_m, self.original_dirname)
self.movie_info['ttitle'], self.movie_info['ttitle_two'], self.movie_info['ttitle_three'] = get_titles(self.nzo, year_m, self.original_dirname, True)
self.movie_info['title'], self.movie_info['title_two'], self.movie_info['title_three'] = get_titles(self.nzo, year_m, self.original_dirname)
return True
@ -721,7 +731,7 @@ class GenericSorter(object):
class DateSorter(object):
""" Methods for Date Sorting
"""
def __init__(self, dirname, path, cat):
def __init__(self, nzo, dirname, path, cat):
self.matched = False
self.original_dirname = dirname
@ -729,6 +739,7 @@ class DateSorter(object):
self.sort_string = cfg.date_sort_string()
self.cats = cfg.date_categories()
self.cat = cat
self.nzo = nzo
self.filename_set = ''
self.fname = '' # Value for %fn substitution in folders
@ -791,10 +802,10 @@ class DateSorter(object):
self.date_info['decade'], self.date_info['decade_two'] = get_decades(self.date_info['year'])
## - Get Title
self.date_info['ttitle'], self.date_info['ttitle_two'], self.date_info['ttitle_three'] = get_titles(self.match_obj, self.original_dirname, True)
self.date_info['title'], self.date_info['title_two'], self.date_info['title_three'] = get_titles(self.match_obj, self.original_dirname)
self.date_info['ttitle'], self.date_info['ttitle_two'], self.date_info['ttitle_three'] = get_titles(self.nzo, self.match_obj, self.original_dirname, True)
self.date_info['title'], self.date_info['title_two'], self.date_info['title_three'] = get_titles(self.nzo, self.match_obj, self.original_dirname)
self.date_info['ep_name'], self.date_info['ep_name_two'], self.date_info['ep_name_three'] = get_descriptions(self.match_obj, self.original_dirname)
self.date_info['ep_name'], self.date_info['ep_name_two'], self.date_info['ep_name_three'] = get_descriptions(self.nzo, self.match_obj, self.original_dirname)
return True
@ -927,7 +938,7 @@ def path_subst(path, mapping):
return ''.join(newpath)
def get_titles(match, name, titleing=False):
def get_titles(nzo, match, name, titleing=False):
'''
The title will be the part before the match
Clean it up and title() it
@ -935,59 +946,64 @@ def get_titles(match, name, titleing=False):
''.title() isn't very good under python so this contains
a lot of little hacks to make it better and for more control
'''
if match:
name = name[:match.start()]
# Replace .US. with (US)
if cfg.tv_sort_countries() == 1:
for rep in COUNTRY_REP:
# (us) > (US)
name = replace_word(name, rep.lower(), rep)
# (Us) > (US)
name = replace_word(name, titler(rep), rep)
# .US. > (US)
dotted_country = '.%s.' % (rep.strip('()'))
name = replace_word(name, dotted_country, rep)
# Remove .US. and (US)
elif cfg.tv_sort_countries() == 2:
for rep in COUNTRY_REP:
# Remove (US)
name = replace_word(name, rep, '')
dotted_country = '.%s.' % (rep.strip('()'))
# Remove .US.
name = replace_word(name, dotted_country, '.')
title = name.replace('.', ' ').replace('_', ' ')
title = title.strip().strip('(').strip('_').strip('-').strip().strip('_')
if titleing:
title = titler(title) # title the show name so it is in a consistant letter case
#title applied uppercase to 's Python bug?
title = title.replace("'S", "'s")
# Replace titled country names, (Us) with (US) and so on
if nzo:
title = latin1(nzo.nzo_info.get('propername') or nzo.meta.get('propername')[0])
else:
title = ''
if not title:
if match:
name = name[:match.start()]
# Replace .US. with (US)
if cfg.tv_sort_countries() == 1:
for rep in COUNTRY_REP:
title = title.replace(titler(rep), rep)
# Remove country names, ie (Us)
# (us) > (US)
name = replace_word(name, rep.lower(), rep)
# (Us) > (US)
name = replace_word(name, titler(rep), rep)
# .US. > (US)
dotted_country = '.%s.' % (rep.strip('()'))
name = replace_word(name, dotted_country, rep)
# Remove .US. and (US)
elif cfg.tv_sort_countries() == 2:
for rep in COUNTRY_REP:
title = title.replace(titler(rep), '').strip()
# Make sure some words such as 'and' or 'of' stay lowercased.
for x in LOWERCASE:
xtitled = titler(x)
title = replace_word(title, xtitled, x)
# Make sure some words such as 'III' or 'IV' stay uppercased.
for x in UPPERCASE:
xtitled = titler(x)
title = replace_word(title, xtitled, x)
# Make sure the first letter of the title is always uppercase
if title:
title = titler(title[0]) + title[1:]
# Remove (US)
name = replace_word(name, rep, '')
dotted_country = '.%s.' % (rep.strip('()'))
# Remove .US.
name = replace_word(name, dotted_country, '.')
title = name.replace('.', ' ').replace('_', ' ')
title = title.strip().strip('(').strip('_').strip('-').strip().strip('_')
if titleing:
title = titler(title) # title the show name so it is in a consistant letter case
#title applied uppercase to 's Python bug?
title = title.replace("'S", "'s")
# Replace titled country names, (Us) with (US) and so on
if cfg.tv_sort_countries() == 1:
for rep in COUNTRY_REP:
title = title.replace(titler(rep), rep)
# Remove country names, ie (Us)
elif cfg.tv_sort_countries() == 2:
for rep in COUNTRY_REP:
title = title.replace(titler(rep), '').strip()
# Make sure some words such as 'and' or 'of' stay lowercased.
for x in LOWERCASE:
xtitled = titler(x)
title = replace_word(title, xtitled, x)
# Make sure some words such as 'III' or 'IV' stay uppercased.
for x in UPPERCASE:
xtitled = titler(x)
title = replace_word(title, xtitled, x)
# Make sure the first letter of the title is always uppercase
if title:
title = titler(title[0]) + title[1:]
# The title with spaces replaced by dots
dots = title.replace(" - ", "-").replace(' ','.').replace('_','.')
@ -1007,22 +1023,27 @@ def replace_word(input, one, two):
input = input.replace(one, two)
return input
def get_descriptions(match, name):
def get_descriptions(nzo, match, name):
'''
If present, get a description from the nzb name.
A description has to be after the matched item, seperated either
like ' - Description' or '_-_Description'
'''
if match:
ep_name = name[match.end():] # Need to improve for multi ep support
if nzo:
ep_name = latin1(nzo.nzo_info.get('episodename') or nzo.meta.get('episodename')[0])
else:
ep_name = name
ep_name = ep_name.strip(' _.')
if ep_name.startswith('-'):
ep_name = ep_name.strip('- _.')
if '.' in ep_name and ' ' not in ep_name:
ep_name = ep_name.replace('.', ' ')
ep_name = ep_name.replace('_', ' ')
ep_name = ''
if not ep_name:
if match:
ep_name = name[match.end():] # Need to improve for multi ep support
else:
ep_name = name
ep_name = ep_name.strip(' _.')
if ep_name.startswith('-'):
ep_name = ep_name.strip('- _.')
if '.' in ep_name and ' ' not in ep_name:
ep_name = ep_name.replace('.', ' ')
ep_name = ep_name.replace('_', ' ')
ep_name2 = ep_name.replace(" - ", "-").replace(" ", ".")
ep_name3 = ep_name.replace(" ", "_")
return ep_name, ep_name2, ep_name3
@ -1189,13 +1210,13 @@ def eval_sort(sorttype, expression, name=None, multipart=''):
name = sanitize_foldername(name)
if sorttype == 'series':
name = name or ('%s S01E05 - %s [DTS]' % (Ttemplate('show-name'), Ttemplate('ep-name')))
sorter = sabnzbd.tvsort.SeriesSorter(name, path, 'tv')
sorter = sabnzbd.tvsort.SeriesSorter(None, name, path, 'tv')
elif sorttype == 'generic':
name = name or (Ttemplate('movie-sp-name') + ' (2009)')
sorter = sabnzbd.tvsort.GenericSorter(name, path, 'tv')
sorter = sabnzbd.tvsort.GenericSorter(None, name, path, 'tv')
elif sorttype == 'date':
name = name or (Ttemplate('show-name') + ' 2009-01-02')
sorter = sabnzbd.tvsort.DateSorter(name, path, 'tv')
sorter = sabnzbd.tvsort.DateSorter(None, name, path, 'tv')
else:
return None
sorter.sort_string = expression

6
sabnzbd/urlgrabber.py

@ -147,6 +147,12 @@ class URLGrabber(Thread):
filename = value
if not filename.endswith('.nzb'):
filename += '.nzb'
elif item == 'x-dnzb-propername':
nzo_info['propername'] = value
elif item == 'x-dnzb-episodename':
nzo_info['episodename'] = value
elif item == 'x-dnzb-year':
nzo_info['year'] = value
elif item in ('content-length',):
length = misc.int_conv(value)

Loading…
Cancel
Save