diff --git a/couchpotato/core/plugins/quality/main.py b/couchpotato/core/plugins/quality/main.py index beff517..d24fa0c 100644 --- a/couchpotato/core/plugins/quality/main.py +++ b/couchpotato/core/plugins/quality/main.py @@ -136,7 +136,7 @@ class QualityPlugin(Plugin): def guess(self, files, extra = {}, loose = False): for file in files: - size = (os.path.getsize(file) / 1024 / 1024) + size = (os.path.getsize(file) / 1024 / 1024) if os.path.isfile(file) else 0 words = re.split('\W+', file.lower()) for quality in self.all(): diff --git a/couchpotato/core/plugins/renamer/__init__.py b/couchpotato/core/plugins/renamer/__init__.py index dcf1897..cc6b411 100644 --- a/couchpotato/core/plugins/renamer/__init__.py +++ b/couchpotato/core/plugins/renamer/__init__.py @@ -30,7 +30,7 @@ config = [{ { 'name': 'folder_name', 'label': 'Folder naming', - 'description': 'Name of the folder', + 'description': 'Name of the folder. Keep empty for no folder.', 'default': ' ()', }, { @@ -40,6 +40,19 @@ config = [{ 'default': '.', }, { + 'name': 'cleanup', + 'type': 'bool', + 'description': 'Cleanup leftover files after successful rename.', + 'default': False, + }, + { + 'name': 'move_leftover', + 'type': 'bool', + 'description': 'Move all leftover file after renaming, to the movie folder.', + 'default': False, + 'advanced': True, + }, + { 'advanced': True, 'name': 'separator', 'label': 'Separator', @@ -72,7 +85,7 @@ config = [{ { 'name': 'nfo_name', 'label': 'NFO naming', - 'default': '.-orig', + 'default': '.orig.', }, { 'name': 'trailer_name', diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index adee1f4..2cc3e82 100644 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -4,7 +4,7 @@ from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.variable import getExt from couchpotato.core.logger import CPLog from couchpotato.core.plugins.base import Plugin -from couchpotato.core.settings.model import Library, Movie +from couchpotato.core.settings.model import Library import os.path import re import shutil @@ -15,6 +15,8 @@ log = CPLog(__name__) class Renamer(Plugin): + renaming_started = False + def __init__(self): addEvent('renamer.scan', self.scan) @@ -27,6 +29,10 @@ class Renamer(Plugin): if self.isDisabled(): return + if self.renaming_started is True: + log.error('Renamer is disabled to avoid infinite looping of the same error.') + return + # Check to see if the "to" folder is inside the "from" folder. if self.conf('from') in self.conf('to'): log.error('The "to" can\'t be inside of the "from" folder. You\'ll get an infinite loop.') @@ -35,11 +41,12 @@ class Renamer(Plugin): groups = fireEvent('scanner.scan', folder = self.conf('from'), single = True) if groups is None: return + self.renaming_started = True + destination = self.conf('to') folder_name = self.conf('folder_name') file_name = self.conf('file_name') trailer_name = self.conf('trailer_name') - backdrop_name = self.conf('fanart_name') nfo_name = self.conf('nfo_name') separator = self.conf('separator') @@ -47,6 +54,8 @@ class Renamer(Plugin): group = groups[group_identifier] rename_files = {} + remove_files = [] + remove_releases = [] # Add _UNKNOWN_ if no library item is connected if not group['library']: @@ -159,7 +168,10 @@ class Renamer(Plugin): # Do rename others else: - rename_files[file] = os.path.join(destination, final_folder_name, final_file_name) + if self.conf('move_leftover') and file_type is 'leftover': + rename_files[file] = os.path.join(destination, final_folder_name, os.path.basename(file)) + else: + rename_files[file] = os.path.join(destination, final_folder_name, final_file_name) # Check for extra subtitle files if file_type is 'subtitle': @@ -203,19 +215,21 @@ class Renamer(Plugin): # Go over current movie releases for release in movie.releases: - # This is where CP removes older, lesser quality releases - if release.quality.order > group['meta_data']['quality']['order']: - log.info('Removing older release for %s, with quality %s' % (movie.library.titles[0].title, release.quality.label)) - - for file in release.files: - log.info('Removing (not really) "%s"' % file.path) - # When a release already exists - elif release.status_id is done_status.get('id'): - + if release.status_id is done_status.get('id'): + + # This is where CP removes older, lesser quality releases + if release.quality.order > group['meta_data']['quality']['order']: + log.info('Removing lesser quality %s for %s.' % (movie.library.titles[0].title, release.quality.label)) + for file in release.files: + remove_files.append(file) + remove_releases.append(release) # Same quality, but still downloaded, so maybe repack/proper/unrated/directors cut etc - if release.quality.order is group['meta_data']['quality']['order']: + elif release.quality.order is group['meta_data']['quality']['order']: log.info('Same quality release already exists for %s, with quality %s. Assuming repack.' % (movie.library.titles[0].title, release.quality.label)) + for file in release.files: + remove_files.append(file) + remove_releases.append(release) # Downloaded a lower quality, rename the newly downloaded files/folder to exclude them from scan else: @@ -237,26 +251,39 @@ class Renamer(Plugin): break + # Remove leftover files + if self.conf('cleanup') and not self.conf('move_leftover'): + log.debug('Removing leftover files') + for file in group['files']['leftover']: + remove_files.append(file) + # Rename all files marked for src in rename_files: if rename_files[src]: - dst = rename_files[src] - log.info('Renaming "%s" to "%s"' % (src, dst)) - path = os.path.dirname(dst) - # Create dir - self.makeDir(path) + self.makeDir(os.path.dirname(dst)) try: - pass - #shutil.move(src, dst) + self.moveFile(src, dst) except: log.error('Failed moving the file "%s" : %s' % (os.path.basename(src), traceback.format_exc())) - #print rename_me, rename_files[rename_me] + # Remove files + for src in remove_files: + log.info('Removing "%s"' % src) + + # Remove matching releases + for release in remove_releases: + log.info('Removing release %s' % release) + + # Add this release to the library + if not group['destination_dir'] is destination: + fireEventAsync('scanner.to_library', folder = group['destination_dir']) + else: + log.error('Single destination folder not fully supported yet.') # Search for trailers etc fireEventAsync('renamer.after', group) @@ -269,12 +296,14 @@ class Renamer(Plugin): if self.shuttingDown(): break - def moveFile(self, old, dest, suppress = True): + self.renaming_started = False + + def moveFile(self, old, dest): try: shutil.move(old, dest) except: log.error("Couldn't move file '%s' to '%s': %s" % (old, dest, traceback.format_exc())) - return False + raise Exception return True diff --git a/couchpotato/core/plugins/scanner/main.py b/couchpotato/core/plugins/scanner/main.py index 7535d3a..c2d4a77 100644 --- a/couchpotato/core/plugins/scanner/main.py +++ b/couchpotato/core/plugins/scanner/main.py @@ -69,14 +69,16 @@ class Scanner(Plugin): def __init__(self): - #addEvent('app.load', self.scanLibrary) addEvent('scanner.create_file_identifier', self.createStringIdentifier) addEvent('scanner.scan', self.scan) + addEvent('scanner.to_library', self.scanToLibrary) + addEvent('scanner.name_year', self.getReleaseNameYear) - def scanLibrary(self): + def scanToLibrary(self, folder = None, files = []): - folder = '/Volumes/Media/Test/' + if not os.path.isdir(folder): + return groups = self.scan(folder = folder) @@ -223,7 +225,8 @@ class Scanner(Plugin): # Leftover "sorted" files for type in group['files']: - group['files']['leftover'] -= set(group['files'][type]) + if not type is 'leftover': + group['files']['leftover'] -= set(group['files'][type]) # Delete the unsorted list del group['unsorted_files'] @@ -463,12 +466,17 @@ class Scanner(Plugin): # groups, release tags, scenename cleaner, regex isn't correct identifier = re.sub(self.clean, '::', simplifyString(identifier)) + # Year year = self.findYear(identifier) if year: identifier = '%s %s' % (identifier.split(year)[0].strip(), year) else: identifier = identifier.split('::')[0] + # Quality + quality = fireEvent('quality.guess', [file_path], single = True) + identifier += ' %s' % quality.get('identifier', '') + # Remove duplicates out = [] for word in identifier.split(): @@ -530,3 +538,29 @@ class Scanner(Plugin): return matches.group('year') return '' + + def getReleaseNameYear(self, release_name): + cleaned = ' '.join(re.split('\W+', simplifyString(release_name))) + cleaned = re.sub(self.clean, ' ', cleaned) + year = self.findYear(cleaned) + + if year: # Split name on year + try: + movie_name = cleaned.split(year).pop(0).strip() + return { + 'name': movie_name, + 'year': year, + } + except: + pass + else: # Split name on multiple spaces + try: + movie_name = cleaned.split(' ').pop(0).strip() + return { + 'name': movie_name, + 'year': year, + } + except: + pass + + return {} diff --git a/couchpotato/core/plugins/searcher/main.py b/couchpotato/core/plugins/searcher/main.py index 6e07f0e..74f7752 100644 --- a/couchpotato/core/plugins/searcher/main.py +++ b/couchpotato/core/plugins/searcher/main.py @@ -194,7 +194,7 @@ class Searcher(Plugin): return True # if no IMDB link, at least check year - if len(movie_words) == 2 and self.correctYear([nzb['name']], movie['library']['year'], 0): + if len(movie_words) <= 2 and self.correctYear([nzb['name']], movie['library']['year'], 0): return True log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'" % (nzb['name'], movie['library']['titles'][0]['title'], movie['library']['year'])) @@ -244,7 +244,9 @@ class Searcher(Plugin): def correctName(self, check_name, movie_name): - check_words = re.split('\W+', simplifyString(check_name)) + check_movie = fireEvent('scanner.name_year', check_name, single = True) + + check_words = re.split('\W+', check_movie.get('name', '')) movie_words = re.split('\W+', simplifyString(movie_name)) - return len(list(set(check_words) & set(movie_words))) == len(movie_words) + return len(list(set(check_words) - set(movie_words))) == 0 diff --git a/couchpotato/core/providers/movie/imdbapi/__init__.py b/couchpotato/core/providers/movie/imdbapi/__init__.py index f10505d..dd1202e 100644 --- a/couchpotato/core/providers/movie/imdbapi/__init__.py +++ b/couchpotato/core/providers/movie/imdbapi/__init__.py @@ -1,6 +1,6 @@ -from .main import IMDB +from .main import IMDBAPI def start(): - return IMDB() + return IMDBAPI() config = []