Browse Source

Searcher and renamer fixes

pull/51/merge
Ruud 14 years ago
parent
commit
dc4b4676f6
  1. 2
      couchpotato/core/notifications/base.py
  2. 7
      couchpotato/core/plugins/base.py
  3. 2
      couchpotato/core/plugins/library/main.py
  4. 4
      couchpotato/core/plugins/movie/main.py
  5. 7
      couchpotato/core/plugins/movie/static/search.css
  6. 45
      couchpotato/core/plugins/quality/main.py
  7. 15
      couchpotato/core/plugins/renamer/__init__.py
  8. 49
      couchpotato/core/plugins/renamer/main.py
  9. 41
      couchpotato/core/plugins/scanner/main.py

2
couchpotato/core/notifications/base.py

@ -39,7 +39,7 @@ class Notification(Plugin):
data = {} data = {}
) )
#return jsonified({'success': success}) return jsonified({'success': success})
def testNotifyName(self): def testNotifyName(self):
return 'notify.%s.test' % self.getName().lower() return 'notify.%s.test' % self.getName().lower()

7
couchpotato/core/plugins/base.py

@ -73,9 +73,12 @@ class Plugin(object):
try: try:
if not os.path.isdir(path): if not os.path.isdir(path):
os.makedirs(path, Env.getPermission('folder')) os.makedirs(path, Env.getPermission('folder'))
return True
except Exception, e: except Exception, e:
log.error('Unable to create folder "%s": %s' % (path, e)) log.error('Unable to create folder "%s": %s' % (path, e))
return False
# http request # http request
def urlopen(self, url, timeout = 10, params = {}, headers = {}): def urlopen(self, url, timeout = 10, params = {}, headers = {}):
@ -93,7 +96,7 @@ class Plugin(object):
data = urllib2.urlopen(request).read() data = urllib2.urlopen(request).read()
except IOError, e: except IOError, e:
log.error('Failed opening url, %s: %s' % (url, e)) log.error('Failed opening url, %s: %s' % (url, e))
data = '' data = None
self.http_last_use[host] = time.time() self.http_last_use[host] = time.time()
@ -111,7 +114,7 @@ class Plugin(object):
time.sleep(last_use - now + self.http_time_between_calls) time.sleep(last_use - now + self.http_time_between_calls)
def beforeCall(self, handler): def beforeCall(self, handler):
log.debug('Calling %s.%s' % (self.getName(), handler.__name__)) #log.debug('Calling %s.%s' % (self.getName(), handler.__name__))
self.isRunning('%s.%s' % (self.getName(), handler.__name__)) self.isRunning('%s.%s' % (self.getName(), handler.__name__))
def afterCall(self, handler): def afterCall(self, handler):

2
couchpotato/core/plugins/library/main.py

@ -62,7 +62,7 @@ class LibraryPlugin(Plugin):
info = fireEvent('provider.movie.info', merge = True, identifier = identifier) info = fireEvent('provider.movie.info', merge = True, identifier = identifier)
if not info or len(info) == 0: if not info or len(info) == 0:
log.error('Could not update, no movie info to work with: %s' % identifier) log.error('Could not update, no movie info to work with: %s' % identifier)
do_update = False return False
# Main info # Main info
if do_update: if do_update:

4
couchpotato/core/plugins/movie/main.py

@ -118,11 +118,15 @@ class MoviePlugin(Plugin):
if release.status_id == status_snatched.get('id'): if release.status_id == status_snatched.get('id'):
release.delete() release.delete()
m.profile_id = params.get('profile_id')
m.status_id = status_active.get('id') m.status_id = status_active.get('id')
db.commit() db.commit()
movie_dict = m.to_dict(self.default_dict) movie_dict = m.to_dict(self.default_dict)
fireEventAsync('searcher.single', movie_dict)
return jsonified({ return jsonified({
'success': True, 'success': True,
'added': True, 'added': True,

7
couchpotato/core/plugins/movie/static/search.css

@ -1,4 +1,7 @@
/* @override http://localhost:5000/static/movie_plugin/search.css */ /* @override
http://localhost:5000/static/movie_plugin/search.css
http://192.168.1.20:5000/static/movie_plugin/search.css
*/
.search_form { .search_form {
display: inline-block; display: inline-block;
@ -86,7 +89,7 @@
margin-right: 10px; margin-right: 10px;
} }
.search_form .results .movie .options select[name=title] { width: 180px; } .search_form .results .movie .options select[name=title] { width: 180px; }
.search_form .results .movie .options select[name=quality] { width: 90px; } .search_form .results .movie .options select[name=profile] { width: 90px; }
.search_form .results .movie .options .button { .search_form .results .movie .options .button {
vertical-align: middle; vertical-align: middle;

45
couchpotato/core/plugins/quality/main.py

@ -18,7 +18,7 @@ class QualityPlugin(Plugin):
{'identifier': '720p', 'size': (3500, 10000), 'label': '720P', 'width': 1280, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts'], 'tags': ['x264', 'h264', 'bluray']}, {'identifier': '720p', 'size': (3500, 10000), 'label': '720P', 'width': 1280, 'alternative': [], 'allow': [], 'ext':['mkv', 'm2ts'], 'tags': ['x264', 'h264', 'bluray']},
{'identifier': 'brrip', 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip'], 'allow': ['720p'], 'ext':['avi']}, {'identifier': 'brrip', 'size': (700, 7000), 'label': 'BR-Rip', 'alternative': ['bdrip'], 'allow': ['720p'], 'ext':['avi']},
{'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': [], 'allow': [], 'ext':['iso', 'img'], 'tags': ['pal', 'ntsc']}, {'identifier': 'dvdr', 'size': (3000, 10000), 'label': 'DVD-R', 'alternative': [], 'allow': [], 'ext':['iso', 'img'], 'tags': ['pal', 'ntsc']},
{'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'alternative': [], 'allow': [], 'ext':['avi', 'mpg', 'mpeg']}, {'identifier': 'dvdrip', 'size': (600, 2400), 'label': 'DVD-Rip', 'alternative': ['dvdrip'], 'allow': [], 'ext':['avi', 'mpg', 'mpeg']},
{'identifier': 'scr', 'size': (600, 1600), 'label': 'Screener', 'alternative': ['dvdscr', 'ppvrip'], 'allow': ['dvdr'], 'ext':['avi', 'mpg', 'mpeg']}, {'identifier': 'scr', 'size': (600, 1600), 'label': 'Screener', 'alternative': ['dvdscr', 'ppvrip'], 'allow': ['dvdr'], 'ext':['avi', 'mpg', 'mpeg']},
{'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': [], 'allow': ['dvdr'], 'ext':['avi', 'mpg', 'mpeg']}, {'identifier': 'r5', 'size': (600, 1000), 'label': 'R5', 'alternative': [], 'allow': ['dvdr'], 'ext':['avi', 'mpg', 'mpeg']},
{'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':['avi', 'mpg', 'mpeg']}, {'identifier': 'tc', 'size': (600, 1000), 'label': 'TeleCine', 'alternative': ['telecine'], 'allow': [], 'ext':['avi', 'mpg', 'mpeg']},
@ -113,12 +113,15 @@ class QualityPlugin(Plugin):
return True return True
def guess(self, files, extra = {}): def guess(self, files, extra = {}, loose = False):
found = False found = False
print files, extra
for file in files: for file in files:
size = (os.path.getsize(file) / 1024 / 1024) size = (os.path.getsize(file) / 1024 / 1024)
words = re.split('\W+', file.lower()) words = re.split('\W+', file.lower())
for quality in self.all(): for quality in self.all():
correctSize = False correctSize = False
@ -126,27 +129,37 @@ class QualityPlugin(Plugin):
correctSize = True correctSize = True
# Check tags # Check tags
if type in words: if quality['identifier'] in words:
log.debug('Found via identifier "%s" in %s' % (quality['identifier'], file))
found = True found = True
for alt in quality.get('alternative'): if list(set(quality.get('alternative', [])) & set(words)):
if alt in words: log.debug('Found via alt %s in %s' % (quality.get('alternative'), file))
found = True found = True
for tag in quality.get('tags', []): if list(set(quality.get('tags', [])) & set(words)):
if tag in words: log.debug('Found via tag %s in %s' % (quality.get('tags'), file))
found = True found = True
# Check extension + filesize # Check on unreliable stuff
for ext in quality.get('ext'): if loose:
if ext in words and correctSize: # Check extension + filesize
if list(set(quality.get('ext', [])) & set(words)) and correctSize:
log.debug('Found via ext %s in %s' % (quality.get('ext'), words))
found = True found = True
# Last check on resolution only # Last check on resolution only
if quality.get('width', 480) == extra.get('resolution_width', 0): if quality.get('width', 480) == extra.get('resolution_width', 0):
found = True log.debug('Found via resoludtion_width: %s == %s' % (quality.get('width', 480), extra.get('resolution_width', 0)))
found = True
if found: if found:
return quality return quality
return '' # Try again with loose testing
quality = self.guess(files, extra = extra, loose = True)
if quality:
return quality
log.error('Could not identify quality for: %s' % files)
return {}

15
couchpotato/core/plugins/renamer/__init__.py

@ -61,14 +61,21 @@ config = [{
'advanced': True, 'advanced': True,
'options': [ 'options': [
{ {
'name': 'trailer_name', 'name': 'rename_nfo',
'label': 'Trailer naming', 'label': 'Rename .NFO',
'default': '<filename>-trailer.<ext>', 'description': 'Rename original .nfo file',
'type': 'bool',
'default': True,
}, },
{ {
'name': 'nfo_name', 'name': 'nfo_name',
'label': 'NFO naming', 'label': 'NFO naming',
'default': '<filename>.<ext>', 'default': '<filename>.<ext>-orig',
},
{
'name': 'trailer_name',
'label': 'Trailer naming',
'default': '<filename>-trailer.<ext>',
}, },
{ {
'name': 'backdrop_name', 'name': 'backdrop_name',

49
couchpotato/core/plugins/renamer/main.py

@ -1,5 +1,5 @@
from couchpotato import get_session from couchpotato import get_session
from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import toUnicode 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
@ -40,7 +40,7 @@ class Renamer(Plugin):
group = groups[group_identifier] group = groups[group_identifier]
rename_files = {} rename_files = {}
# Add _UNKNOWN_ if no library is connected # Add _UNKNOWN_ if no library item is connected
if not group['library']: if not group['library']:
if group['dirname']: if group['dirname']:
rename_files[group['parentdir']] = group['parentdir'].replace(group['dirname'], '_UNKNOWN_%s' % group['dirname']) rename_files[group['parentdir']] = group['parentdir'].replace(group['dirname'], '_UNKNOWN_%s' % group['dirname'])
@ -53,6 +53,10 @@ class Renamer(Plugin):
# Rename the files using the library data # Rename the files using the library data
else: else:
group['library'] = fireEvent('library.update', identifier = group['library']['identifier'], single = True) group['library'] = fireEvent('library.update', identifier = group['library']['identifier'], single = True)
if not group['library']:
log.error('Could not rename, no library item to work with: %s' % group_identifier)
continue
library = group['library'] library = group['library']
# Find subtitle for renaming # Find subtitle for renaming
@ -85,12 +89,9 @@ class Renamer(Plugin):
for file_type in group['files']: for file_type in group['files']:
# Move DVD files (no renaming)
if group['is_dvd'] and file_type is 'movie':
continue
# Move nfo depending on settings # Move nfo depending on settings
if file_type is 'nfo' and not self.conf('rename_nfo'): if file_type is 'nfo' and not self.conf('rename_nfo'):
log.debug('Skipping, renaming of %s disabled' % file_type)
continue continue
# Subtitle extra # Subtitle extra
@ -98,7 +99,7 @@ class Renamer(Plugin):
continue continue
# Move other files # Move other files
multiple = len(group['files']['movie']) > 1 multiple = len(group['files']['movie']) > 1 and not group['is_dvd']
cd = 1 if multiple else 0 cd = 1 if multiple else 0
for file in sorted(list(group['files'][file_type])): for file in sorted(list(group['files'][file_type])):
@ -123,7 +124,7 @@ class Renamer(Plugin):
if file_type is 'trailer': if file_type is 'trailer':
final_file_name = self.doReplace(trailer_name, replacements) final_file_name = self.doReplace(trailer_name, replacements)
elif file_type is 'nfo': elif file_type is 'nfo':
final_file_name = self.doReplace(nfo_name, replacements) + '-orig' final_file_name = self.doReplace(nfo_name, replacements)
elif file_type is 'backdrop': elif file_type is 'backdrop':
final_file_name = self.doReplace(backdrop_name, replacements) final_file_name = self.doReplace(backdrop_name, replacements)
@ -131,8 +132,13 @@ class Renamer(Plugin):
if separator: if separator:
final_file_name = final_file_name.replace(' ', separator) final_file_name = final_file_name.replace(' ', separator)
# Main file # Move DVD files (no structure renaming)
rename_files[file] = os.path.join(destination, final_folder_name, final_file_name) if group['is_dvd'] and file_type is 'movie':
structure_dir = file.split(group['dirname'])[-1].lstrip(os.path.sep)
rename_files[file] = os.path.join(destination, final_folder_name, structure_dir)
# Do rename others
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':
@ -154,17 +160,13 @@ class Renamer(Plugin):
if multiple: if multiple:
cd += 1 cd += 1
# Notify on download
download_message = 'Download of %s (%s) successful.' % (group['library']['titles'][0]['title'], replacements['quality'])
fireEvent('movie.downloaded', message = download_message, data = group)
# Before renaming, remove the lower quality files # Before renaming, remove the lower quality files
db = get_session() db = get_session()
library = db.query(Library).filter_by(identifier = group['library']['identifier']).first() library = db.query(Library).filter_by(identifier = group['library']['identifier']).first()
done_status = fireEvent('status.get', 'done', single = True) done_status = fireEvent('status.get', 'done', single = True)
for movie in library.movies: for movie in library.movies:
for release in movie.releases: for release in movie.releases:
if release.quality.order < group['meta_data']['quality']['order']: 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)) log.info('Removing older release for %s, with quality %s' % (movie.library.titles[0].title, release.quality.label))
elif release.status_id is done_status.get('id'): elif release.status_id is done_status.get('id'):
if release.quality.order is group['meta_data']['quality']['order']: if release.quality.order is group['meta_data']['quality']['order']:
@ -200,21 +202,24 @@ class Renamer(Plugin):
log.info('Renaming "%s" to "%s"' % (src, dst)) log.info('Renaming "%s" to "%s"' % (src, dst))
path = os.path.dirname(dst) path = os.path.dirname(dst)
try:
if not os.path.isdir(path): os.makedirs(path) # Create dir
except: self.makeDir(path)
log.error('Failed creating dir %s: %s' % (path, traceback.format_exc()))
continue
try: try:
shutil.move(src, dst) pass
#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] #print rename_me, rename_files[rename_me]
# Search for trailers etc # Search for trailers etc
fireEvent('renamer.after', group) fireEventAsync('renamer.after', group)
# Notify on download
download_message = 'Download of %s (%s) successful.' % (group['library']['titles'][0]['title'], replacements['quality'])
fireEventAsync('movie.downloaded', message = download_message, data = group)
# Break if CP wants to shut down # Break if CP wants to shut down
if self.shuttingDown(): if self.shuttingDown():

41
couchpotato/core/plugins/scanner/main.py

@ -4,13 +4,13 @@ from couchpotato.core.helpers.encoding import toUnicode, simplifyString
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 File, Release, Movie from couchpotato.core.settings.model import File
from couchpotato.environment import Env from couchpotato.environment import Env
from flask.helpers import json from flask.helpers import json
from sqlalchemy.sql.expression import and_, or_
import os import os
import re import re
import subprocess import subprocess
import time
import traceback import traceback
log = CPLog(__name__) log = CPLog(__name__)
@ -23,7 +23,7 @@ class Scanner(Plugin):
'trailer': 1048576, # 1MB 'trailer': 1048576, # 1MB
} }
ignored_in_path = ['_unpack', '_failed_', '_unknown_', '_exists_', '.appledouble', '.appledb', '.appledesktop', os.path.sep + '._', '.ds_store', 'cp.cpnfo'] #unpacking, smb-crap, hidden files ignored_in_path = ['_unpack', '_failed_', '_unknown_', '_exists_', '.appledouble', '.appledb', '.appledesktop', os.path.sep + '._', '.ds_store', 'cp.cpnfo'] #unpacking, smb-crap, hidden files
ignore_names = ['extract', 'extracting', 'extracted', 'movie', 'movies', 'film', 'films', 'download', 'downloads'] ignore_names = ['extract', 'extracting', 'extracted', 'movie', 'movies', 'film', 'films', 'download', 'downloads', 'video_ts', 'audio_ts']
extensions = { extensions = {
'movie': ['mkv', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'm2ts', 'iso', 'img'], 'movie': ['mkv', 'wmv', 'avi', 'mpg', 'mpeg', 'mp4', 'm2ts', 'iso', 'img'],
'dvd': ['vts_*', 'vob'], 'dvd': ['vts_*', 'vob'],
@ -172,9 +172,21 @@ class Scanner(Plugin):
# Determine file types # Determine file types
delete_identifier = []
for identifier in movie_files: for identifier in movie_files:
group = movie_files[identifier] group = movie_files[identifier]
# Check if movie is fresh and maybe still unpacking, ignore files new then 1 minute
file_too_new = False
for file in group['unsorted_files']:
if os.path.getmtime(file) > time.time() - 60:
file_too_new = True
if file_too_new:
log.info('Files seem to be still unpacking or just unpacked, ignoring for now: %s' % identifier)
delete_identifier.append(identifier)
continue
# Group extra (and easy) files first # Group extra (and easy) files first
images = self.getImages(group['unsorted_files']) images = self.getImages(group['unsorted_files'])
group['files'] = { group['files'] = {
@ -199,10 +211,11 @@ class Scanner(Plugin):
group['dirname'] = None group['dirname'] = None
folders = group['parentdir'].replace(folder, '').split(os.path.sep) folders = group['parentdir'].replace(folder, '').split(os.path.sep)
folders.reverse()
# Try and get a proper dirname, so no "A", "Movie", "Download" # Try and get a proper dirname, so no "A", "Movie", "Download" etc
for folder in folders: for folder in folders:
if folder.lower() in self.ignore_names or len(folder) < 2: if folder.lower() not in self.ignore_names and len(folder) > 2:
group['dirname'] = folder group['dirname'] = folder
break break
@ -220,12 +233,16 @@ class Scanner(Plugin):
if not group['library']: if not group['library']:
log.error('Unable to determin movie: %s' % group['identifiers']) log.error('Unable to determin movie: %s' % group['identifiers'])
# Delete still (asuming) unpacking files
for identifier in delete_identifier:
del movie_files[identifier]
return movie_files return movie_files
def getMetaData(self, group): def getMetaData(self, group):
data = {} data = {}
files = group['files']['movie'] files = list(group['files']['movie'])
for file in files: for file in files:
if os.path.getsize(file) < self.minimal_filesize['media']: continue # Ignore smaller files if os.path.getsize(file) < self.minimal_filesize['media']: continue # Ignore smaller files
@ -246,10 +263,11 @@ class Scanner(Plugin):
if not data['quality']: if not data['quality']:
data['quality'] = fireEvent('quality.single', 'dvdr' if group['is_dvd'] else 'dvdrip', single = True) data['quality'] = fireEvent('quality.single', 'dvdr' if group['is_dvd'] else 'dvdrip', single = True)
data['quality_type'] = 'HD' if data.get('resolution_width', 0) >= 720 else 'SD' data['quality_type'] = 'HD' if data.get('resolution_width', 0) >= 1280 else 'SD'
data['group'] = self.getGroup(file[0]) file = re.sub('(.cp\(tt[0-9{7}]+\))', '', files[0])
data['source'] = self.getSourceMedia(file[0]) data['group'] = self.getGroup(file)
data['source'] = self.getSourceMedia(file)
return data return data
@ -365,7 +383,6 @@ class Scanner(Plugin):
return set(filter(test, files)) return set(filter(test, files))
def getDVDFiles(self, files): def getDVDFiles(self, files):
def test(s): def test(s):
return self.isDVDFile(s) return self.isDVDFile(s)
@ -510,8 +527,8 @@ class Scanner(Plugin):
def getGroup(self, file): def getGroup(self, file):
try: try:
group = re.search('-(?P<group>[A-Z0-9]+)$', file, re.I) match = re.search('-(?P<group>[A-Z0-9]+).', file, re.I)
return group.group('group') or '' return match.group('group') or ''
except: except:
return '' return ''

Loading…
Cancel
Save