Searcher and scanner fixes
This commit is contained in:
1 parent
eafce4436e
commit
5f23a16fae
6 files changed
+112
-34
No files matched your search
@@ -136,7 +136,7 @@ class QualityPlugin(Plugin):
|
|||||||
def guess(self, files, extra = {}, loose = False):
|
def guess(self, files, extra = {}, loose = False):
|
||||||
|
|
||||||
for file in files:
|
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())
|
words = re.split('\W+', file.lower())
|
||||||
|
|
||||||
for quality in self.all():
|
for quality in self.all():
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ config = [{
|
|||||||
{
|
{
|
||||||
'name': 'folder_name',
|
'name': 'folder_name',
|
||||||
'label': 'Folder naming',
|
'label': 'Folder naming',
|
||||||
'description': 'Name of the folder',
|
'description': 'Name of the folder. Keep empty for no folder.',
|
||||||
'default': '<namethe> (<year>)',
|
'default': '<namethe> (<year>)',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -39,6 +39,19 @@ config = [{
|
|||||||
'description': 'Name of the file',
|
'description': 'Name of the file',
|
||||||
'default': '<thename><cd>.<ext>',
|
'default': '<thename><cd>.<ext>',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'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,
|
'advanced': True,
|
||||||
'name': 'separator',
|
'name': 'separator',
|
||||||
@@ -72,7 +85,7 @@ config = [{
|
|||||||
{
|
{
|
||||||
'name': 'nfo_name',
|
'name': 'nfo_name',
|
||||||
'label': 'NFO naming',
|
'label': 'NFO naming',
|
||||||
'default': '<filename>.<ext>-orig',
|
'default': '<filename>.orig.<ext>',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'name': 'trailer_name',
|
'name': 'trailer_name',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ from couchpotato.core.helpers.encoding import toUnicode
|
|||||||
from couchpotato.core.helpers.variable import getExt
|
from couchpotato.core.helpers.variable import getExt
|
||||||
from couchpotato.core.logger import CPLog
|
from couchpotato.core.logger import CPLog
|
||||||
from couchpotato.core.plugins.base import Plugin
|
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 os.path
|
||||||
import re
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
@@ -15,6 +15,8 @@ log = CPLog(__name__)
|
|||||||
|
|
||||||
class Renamer(Plugin):
|
class Renamer(Plugin):
|
||||||
|
|
||||||
|
renaming_started = False
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
addEvent('renamer.scan', self.scan)
|
addEvent('renamer.scan', self.scan)
|
||||||
@@ -27,6 +29,10 @@ class Renamer(Plugin):
|
|||||||
if self.isDisabled():
|
if self.isDisabled():
|
||||||
return
|
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.
|
# Check to see if the "to" folder is inside the "from" folder.
|
||||||
if self.conf('from') in self.conf('to'):
|
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.')
|
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)
|
groups = fireEvent('scanner.scan', folder = self.conf('from'), single = True)
|
||||||
if groups is None: return
|
if groups is None: return
|
||||||
|
|
||||||
|
self.renaming_started = True
|
||||||
|
|
||||||
destination = self.conf('to')
|
destination = self.conf('to')
|
||||||
folder_name = self.conf('folder_name')
|
folder_name = self.conf('folder_name')
|
||||||
file_name = self.conf('file_name')
|
file_name = self.conf('file_name')
|
||||||
trailer_name = self.conf('trailer_name')
|
trailer_name = self.conf('trailer_name')
|
||||||
backdrop_name = self.conf('fanart_name')
|
|
||||||
nfo_name = self.conf('nfo_name')
|
nfo_name = self.conf('nfo_name')
|
||||||
separator = self.conf('separator')
|
separator = self.conf('separator')
|
||||||
|
|
||||||
@@ -47,6 +54,8 @@ class Renamer(Plugin):
|
|||||||
|
|
||||||
group = groups[group_identifier]
|
group = groups[group_identifier]
|
||||||
rename_files = {}
|
rename_files = {}
|
||||||
|
remove_files = []
|
||||||
|
remove_releases = []
|
||||||
|
|
||||||
# Add _UNKNOWN_ if no library item is connected
|
# Add _UNKNOWN_ if no library item is connected
|
||||||
if not group['library']:
|
if not group['library']:
|
||||||
@@ -159,7 +168,10 @@ class Renamer(Plugin):
|
|||||||
|
|
||||||
# Do rename others
|
# Do rename others
|
||||||
else:
|
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
|
# Check for extra subtitle files
|
||||||
if file_type is 'subtitle':
|
if file_type is 'subtitle':
|
||||||
@@ -203,19 +215,21 @@ class Renamer(Plugin):
|
|||||||
# Go over current movie releases
|
# Go over current movie releases
|
||||||
for release in 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
|
# 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
|
# 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))
|
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
|
# Downloaded a lower quality, rename the newly downloaded files/folder to exclude them from scan
|
||||||
else:
|
else:
|
||||||
@@ -237,26 +251,39 @@ class Renamer(Plugin):
|
|||||||
|
|
||||||
break
|
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
|
# Rename all files marked
|
||||||
for src in rename_files:
|
for src in rename_files:
|
||||||
if rename_files[src]:
|
if rename_files[src]:
|
||||||
|
|
||||||
dst = rename_files[src]
|
dst = rename_files[src]
|
||||||
|
|
||||||
log.info('Renaming "%s" to "%s"' % (src, dst))
|
log.info('Renaming "%s" to "%s"' % (src, dst))
|
||||||
|
|
||||||
path = os.path.dirname(dst)
|
|
||||||
|
|
||||||
# Create dir
|
# Create dir
|
||||||
self.makeDir(path)
|
self.makeDir(os.path.dirname(dst))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
pass
|
self.moveFile(src, dst)
|
||||||
#shutil.move(src, dst)
|
|
||||||
except:
|
except:
|
||||||
log.error('Failed moving the file "%s" : %s' % (os.path.basename(src), traceback.format_exc()))
|
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
|
# Search for trailers etc
|
||||||
fireEventAsync('renamer.after', group)
|
fireEventAsync('renamer.after', group)
|
||||||
@@ -269,12 +296,14 @@ class Renamer(Plugin):
|
|||||||
if self.shuttingDown():
|
if self.shuttingDown():
|
||||||
break
|
break
|
||||||
|
|
||||||
def moveFile(self, old, dest, suppress = True):
|
self.renaming_started = False
|
||||||
|
|
||||||
|
def moveFile(self, old, dest):
|
||||||
try:
|
try:
|
||||||
shutil.move(old, dest)
|
shutil.move(old, dest)
|
||||||
except:
|
except:
|
||||||
log.error("Couldn't move file '%s' to '%s': %s" % (old, dest, traceback.format_exc()))
|
log.error("Couldn't move file '%s' to '%s': %s" % (old, dest, traceback.format_exc()))
|
||||||
return False
|
raise Exception
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|||||||
@@ -69,14 +69,16 @@ class Scanner(Plugin):
|
|||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
|
||||||
#addEvent('app.load', self.scanLibrary)
|
|
||||||
addEvent('scanner.create_file_identifier', self.createStringIdentifier)
|
addEvent('scanner.create_file_identifier', self.createStringIdentifier)
|
||||||
|
|
||||||
addEvent('scanner.scan', self.scan)
|
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)
|
groups = self.scan(folder = folder)
|
||||||
|
|
||||||
@@ -223,7 +225,8 @@ class Scanner(Plugin):
|
|||||||
|
|
||||||
# Leftover "sorted" files
|
# Leftover "sorted" files
|
||||||
for type in group['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
|
# Delete the unsorted list
|
||||||
del group['unsorted_files']
|
del group['unsorted_files']
|
||||||
@@ -463,12 +466,17 @@ class Scanner(Plugin):
|
|||||||
# groups, release tags, scenename cleaner, regex isn't correct
|
# groups, release tags, scenename cleaner, regex isn't correct
|
||||||
identifier = re.sub(self.clean, '::', simplifyString(identifier))
|
identifier = re.sub(self.clean, '::', simplifyString(identifier))
|
||||||
|
|
||||||
|
# Year
|
||||||
year = self.findYear(identifier)
|
year = self.findYear(identifier)
|
||||||
if year:
|
if year:
|
||||||
identifier = '%s %s' % (identifier.split(year)[0].strip(), year)
|
identifier = '%s %s' % (identifier.split(year)[0].strip(), year)
|
||||||
else:
|
else:
|
||||||
identifier = identifier.split('::')[0]
|
identifier = identifier.split('::')[0]
|
||||||
|
|
||||||
|
# Quality
|
||||||
|
quality = fireEvent('quality.guess', [file_path], single = True)
|
||||||
|
identifier += ' %s' % quality.get('identifier', '')
|
||||||
|
|
||||||
# Remove duplicates
|
# Remove duplicates
|
||||||
out = []
|
out = []
|
||||||
for word in identifier.split():
|
for word in identifier.split():
|
||||||
@@ -530,3 +538,29 @@ class Scanner(Plugin):
|
|||||||
return matches.group('year')
|
return matches.group('year')
|
||||||
|
|
||||||
return ''
|
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 {}
|
||||||
@@ -194,7 +194,7 @@ class Searcher(Plugin):
|
|||||||
return True
|
return True
|
||||||
|
|
||||||
# if no IMDB link, at least check year
|
# 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
|
return True
|
||||||
|
|
||||||
log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'" % (nzb['name'], movie['library']['titles'][0]['title'], movie['library']['year']))
|
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):
|
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))
|
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
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
from .main import IMDB
|
from .main import IMDBAPI
|
||||||
|
|
||||||
def start():
|
def start():
|
||||||
return IMDB()
|
return IMDBAPI()
|
||||||
|
|
||||||
config = []
|
config = []
|
||||||
Reference in new issue
Block a user