Browse Source

Merge branch 'tv' of https://github.com/RuudBurger/CouchPotatoServer into tv_database

pull/2038/head
Jason Mehring 12 years ago
parent
commit
8fcc246f25
  1. 7
      couchpotato/core/loader.py
  2. 17
      couchpotato/core/media/__init__.py
  3. 0
      couchpotato/core/media/_base/__init__.py
  4. 52
      couchpotato/core/media/_base/searcher/__init__.py
  5. 207
      couchpotato/core/media/_base/searcher/main.py
  6. 0
      couchpotato/core/media/movie/__init__.py
  7. 6
      couchpotato/core/media/movie/_base/__init__.py
  8. 12
      couchpotato/core/media/movie/_base/main.py
  9. 0
      couchpotato/core/media/movie/_base/static/list.js
  10. 0
      couchpotato/core/media/movie/_base/static/movie.actions.js
  11. 0
      couchpotato/core/media/movie/_base/static/movie.css
  12. 6
      couchpotato/core/media/movie/_base/static/movie.js
  13. 0
      couchpotato/core/media/movie/_base/static/search.css
  14. 0
      couchpotato/core/media/movie/_base/static/search.js
  15. 60
      couchpotato/core/media/movie/searcher/__init__.py
  16. 202
      couchpotato/core/media/movie/searcher/main.py
  17. 0
      couchpotato/core/media/tv/__init__.py
  18. 6
      couchpotato/core/media/tv/_base/__init__.py
  19. 13
      couchpotato/core/media/tv/_base/main.py
  20. 7
      couchpotato/core/media/tv/searcher/__init__.py
  21. 12
      couchpotato/core/media/tv/searcher/main.py
  22. 2
      couchpotato/core/plugins/automation/main.py
  23. 1
      couchpotato/core/plugins/category/static/category.js
  24. 4
      couchpotato/core/plugins/dashboard/main.py
  25. 6
      couchpotato/core/plugins/movie/__init__.py
  26. 2
      couchpotato/core/plugins/renamer/main.py
  27. 2
      couchpotato/core/providers/base.py
  28. 4
      couchpotato/static/scripts/page/wanted.js

7
couchpotato/core/loader.py

@ -31,6 +31,13 @@ class Loader(object):
if os.path.isdir(path) and provider[:2] != '__':
self.paths[provider + '_provider'] = (25, 'couchpotato.core.providers.' + provider, path)
# Add media to loader
media_dir = os.path.join(root, 'couchpotato', 'core', 'media')
for media in os.listdir(media_dir):
path = os.path.join(media_dir, media)
if os.path.isdir(path) and media[:2] != '__':
self.paths[media + '_media'] = (25, 'couchpotato.core.media.' + media, path)
for plugin_type, plugin_tuple in self.paths.iteritems():
priority, module, dir_name = plugin_tuple

17
couchpotato/core/media/__init__.py

@ -0,0 +1,17 @@
from couchpotato.core.event import addEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
log = CPLog(__name__)
class MediaBase(Plugin):
identifier = None
def __init__(self):
addEvent('media.types', self.getType)
def getType(self):
return self.identifier

0
couchpotato/core/media/_base/__init__.py

52
couchpotato/core/plugins/searcher/__init__.py → couchpotato/core/media/_base/searcher/__init__.py

@ -11,8 +11,8 @@ config = [{
{
'tab': 'searcher',
'name': 'searcher',
'label': 'Search',
'description': 'Options for the searchers',
'label': 'Basics',
'description': 'General search options',
'options': [
{
'name': 'preferred_method',
@ -22,14 +22,6 @@ config = [{
'type': 'dropdown',
'values': [('usenet & torrents', 'both'), ('usenet', 'nzb'), ('torrents', 'torrent')],
},
{
'name': 'always_search',
'default': False,
'advanced': True,
'type': 'bool',
'label': 'Always search',
'description': 'Search for movies even before there is a ETA. Enabling this will probably get you a lot of fakes.',
},
],
}, {
'tab': 'searcher',
@ -60,46 +52,6 @@ config = [{
'description': 'Ignores releases that match any of these sets. (Works like explained above)'
},
],
}, {
'tab': 'searcher',
'name': 'cronjob',
'label': 'Cronjob',
'advanced': True,
'description': 'Cron settings for the searcher see: <a href="http://packages.python.org/APScheduler/cronschedule.html">APScheduler</a> for details.',
'options': [
{
'name': 'run_on_launch',
'label': 'Run on launch',
'advanced': True,
'default': 0,
'type': 'bool',
'description': 'Force run the searcher after (re)start.',
},
{
'name': 'cron_day',
'label': 'Day',
'advanced': True,
'default': '*',
'type': 'string',
'description': '<strong>*</strong>: Every day, <strong>*/2</strong>: Every 2 days, <strong>1</strong>: Every first of the month.',
},
{
'name': 'cron_hour',
'label': 'Hour',
'advanced': True,
'default': random.randint(0, 23),
'type': 'string',
'description': '<strong>*</strong>: Every hour, <strong>*/8</strong>: Every 8 hours, <strong>3</strong>: At 3, midnight.',
},
{
'name': 'cron_minute',
'label': 'Minute',
'advanced': True,
'default': random.randint(0, 59),
'type': 'string',
'description': "Just keep it random, so the providers don't get DDOSed by every CP user on a 'full' hour."
},
],
},
],
}, {

207
couchpotato/core/media/_base/searcher/main.py

@ -0,0 +1,207 @@
from couchpotato import get_session
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato.core.helpers.variable import md5, getTitle
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Movie, Release, ReleaseInfo
from couchpotato.environment import Env
from inspect import ismethod, isfunction
import datetime
import re
import time
import traceback
log = CPLog(__name__)
class Searcher(Plugin):
def __init__(self):
addEvent('searcher.get_types', self.getSearchTypes)
addEvent('searcher.contains_other_quality', self.containsOtherQuality)
addEvent('searcher.correct_year', self.correctYear)
addEvent('searcher.correct_name', self.correctName)
addEvent('searcher.download', self.download)
def download(self, data, movie, manual = False):
# Test to see if any downloaders are enabled for this type
downloader_enabled = fireEvent('download.enabled', manual, data, single = True)
if downloader_enabled:
snatched_status = fireEvent('status.get', 'snatched', single = True)
# Download movie to temp
filedata = None
if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))):
filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id'))
if filedata == 'try_next':
return filedata
download_result = fireEvent('download', data = data, movie = movie, manual = manual, filedata = filedata, single = True)
log.debug('Downloader result: %s', download_result)
if download_result:
try:
# Mark release as snatched
db = get_session()
rls = db.query(Release).filter_by(identifier = md5(data['url'])).first()
if rls:
renamer_enabled = Env.setting('enabled', 'renamer')
done_status = fireEvent('status.get', 'done', single = True)
rls.status_id = done_status.get('id') if not renamer_enabled else snatched_status.get('id')
# Save download-id info if returned
if isinstance(download_result, dict):
for key in download_result:
rls_info = ReleaseInfo(
identifier = 'download_%s' % key,
value = toUnicode(download_result.get(key))
)
rls.info.append(rls_info)
db.commit()
log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label)
snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie)
log.info(snatch_message)
fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict())
# If renamer isn't used, mark movie done
if not renamer_enabled:
active_status = fireEvent('status.get', 'active', single = True)
done_status = fireEvent('status.get', 'done', single = True)
try:
if movie['status_id'] == active_status.get('id'):
for profile_type in movie['profile']['types']:
if profile_type['quality_id'] == rls.quality.id and profile_type['finish']:
log.info('Renamer disabled, marking movie as finished: %s', log_movie)
# Mark release done
rls.status_id = done_status.get('id')
rls.last_edit = int(time.time())
db.commit()
# Mark movie done
mvie = db.query(Movie).filter_by(id = movie['id']).first()
mvie.status_id = done_status.get('id')
mvie.last_edit = int(time.time())
db.commit()
except:
log.error('Failed marking movie finished, renamer disabled: %s', traceback.format_exc())
except:
log.error('Failed marking movie finished: %s', traceback.format_exc())
return True
log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('type', '')))
return False
def getSearchTypes(self):
download_types = fireEvent('download.enabled_types', merge = True)
provider_types = fireEvent('provider.enabled_types', merge = True)
if download_types and len(list(set(provider_types) & set(download_types))) == 0:
log.error('There aren\'t any providers enabled for your downloader (%s). Check your settings.', ','.join(download_types))
return []
for useless_provider in list(set(provider_types) - set(download_types)):
log.debug('Provider for "%s" enabled, but no downloader.', useless_provider)
search_types = download_types
if len(search_types) == 0:
log.error('There aren\'t any downloaders enabled. Please pick one in settings.')
return []
return search_types
def containsOtherQuality(self, nzb, movie_year = None, preferred_quality = {}):
name = nzb['name']
size = nzb.get('size', 0)
nzb_words = re.split('\W+', simplifyString(name))
qualities = fireEvent('quality.all', single = True)
found = {}
for quality in qualities:
# Main in words
if quality['identifier'] in nzb_words:
found[quality['identifier']] = True
# Alt in words
if list(set(nzb_words) & set(quality['alternative'])):
found[quality['identifier']] = True
# Try guessing via quality tags
guess = fireEvent('quality.guess', [nzb.get('name')], single = True)
if guess:
found[guess['identifier']] = True
# Hack for older movies that don't contain quality tag
year_name = fireEvent('scanner.name_year', name, single = True)
if len(found) == 0 and movie_year < datetime.datetime.now().year - 3 and not year_name.get('year', None):
if size > 3000: # Assume dvdr
log.info('Quality was missing in name, assuming it\'s a DVD-R based on the size: %s', (size))
found['dvdr'] = True
else: # Assume dvdrip
log.info('Quality was missing in name, assuming it\'s a DVD-Rip based on the size: %s', (size))
found['dvdrip'] = True
# Allow other qualities
for allowed in preferred_quality.get('allow'):
if found.get(allowed):
del found[allowed]
return not (found.get(preferred_quality['identifier']) and len(found) == 1)
def correctYear(self, haystack, year, year_range):
if not isinstance(haystack, (list, tuple, set)):
haystack = [haystack]
for string in haystack:
year_name = fireEvent('scanner.name_year', string, single = True)
if year_name and ((year - year_range) <= year_name.get('year') <= (year + year_range)):
log.debug('Movie year matches range: %s looking for %s', (year_name.get('year'), year))
return True
log.debug('Movie year doesn\'t matche range: %s looking for %s', (year_name.get('year'), year))
return False
def correctName(self, check_name, movie_name):
check_names = [check_name]
# Match names between "
try: check_names.append(re.search(r'([\'"])[^\1]*\1', check_name).group(0))
except: pass
# Match longest name between []
try: check_names.append(max(check_name.split('['), key = len))
except: pass
for check_name in list(set(check_names)):
check_movie = fireEvent('scanner.name_year', check_name, single = True)
try:
check_words = filter(None, re.split('\W+', check_movie.get('name', '')))
movie_words = filter(None, re.split('\W+', simplifyString(movie_name)))
if len(check_words) > 0 and len(movie_words) > 0 and len(list(set(check_words) - set(movie_words))) == 0:
return True
except:
pass
return False
class SearchSetupError(Exception):
pass

0
couchpotato/core/media/movie/__init__.py

6
couchpotato/core/media/movie/_base/__init__.py

@ -0,0 +1,6 @@
from .main import MovieBase
def start():
return MovieBase()
config = []

12
couchpotato/core/plugins/movie/main.py → couchpotato/core/media/movie/_base/main.py

@ -4,7 +4,7 @@ from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode, simplifyString
from couchpotato.core.helpers.variable import getImdb, splitString, tryInt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.media import MediaBase
from couchpotato.core.settings.model import Library, LibraryTitle, Movie, \
Release
from couchpotato.environment import Env
@ -16,7 +16,9 @@ import time
log = CPLog(__name__)
class MoviePlugin(Plugin):
class MovieBase(MediaBase):
identifier = 'movie'
default_dict = {
'profile': {'types': {'quality': {}}},
@ -27,6 +29,8 @@ class MoviePlugin(Plugin):
}
def __init__(self):
super(MovieBase, self).__init__()
addApiView('movie.search', self.search, docs = {
'desc': 'Search the movie providers for a movie',
'params': {
@ -476,7 +480,7 @@ class MoviePlugin(Plugin):
fireEvent('movie.restatus', m.id)
movie_dict = m.to_dict(self.default_dict)
fireEventAsync('searcher.single', movie_dict, on_complete = self.createNotifyFront(movie_id))
fireEventAsync('movie.searcher.single', movie_dict, on_complete = self.createNotifyFront(movie_id))
db.expire_all()
return {
@ -574,7 +578,7 @@ class MoviePlugin(Plugin):
def onComplete():
db = get_session()
movie = db.query(Movie).filter_by(id = movie_id).first()
fireEventAsync('searcher.single', movie.to_dict(self.default_dict), on_complete = self.createNotifyFront(movie_id))
fireEventAsync('movie.searcher.single', movie.to_dict(self.default_dict), on_complete = self.createNotifyFront(movie_id))
db.expire_all()
return onComplete

0
couchpotato/core/plugins/movie/static/list.js → couchpotato/core/media/movie/_base/static/list.js

0
couchpotato/core/plugins/movie/static/movie.actions.js → couchpotato/core/media/movie/_base/static/movie.actions.js

0
couchpotato/core/plugins/movie/static/movie.css → couchpotato/core/media/movie/_base/static/movie.css

6
couchpotato/core/plugins/movie/static/movie.js → couchpotato/core/media/movie/_base/static/movie.js

@ -29,14 +29,14 @@ var Movie = new Class({
self.update.delay(2000, self, notification);
});
['movie.busy', 'searcher.started'].each(function(listener){
['movie.busy', 'movie.searcher.started'].each(function(listener){
App.addEvent(listener+'.'+self.data.id, function(notification){
if(notification.data)
self.busy(true)
});
})
App.addEvent('searcher.ended.'+self.data.id, function(notification){
App.addEvent('movie.searcher.ended.'+self.data.id, function(notification){
if(notification.data)
self.busy(false)
});
@ -53,7 +53,7 @@ var Movie = new Class({
// Remove events
App.removeEvents('movie.update.'+self.data.id);
['movie.busy', 'searcher.started'].each(function(listener){
['movie.busy', 'movie.searcher.started'].each(function(listener){
App.removeEvents(listener+'.'+self.data.id);
})
},

0
couchpotato/core/plugins/movie/static/search.css → couchpotato/core/media/movie/_base/static/search.css

0
couchpotato/core/plugins/movie/static/search.js → couchpotato/core/media/movie/_base/static/search.js

60
couchpotato/core/media/movie/searcher/__init__.py

@ -0,0 +1,60 @@
from .main import MovieSearcher
import random
def start():
return MovieSearcher()
config = [{
'name': 'searcher',
'order': 20,
'groups': [
{
'tab': 'searcher',
'name': 'movie_searcher',
'label': 'Movie search',
'description': 'Search options for movies',
'advanced': True,
'options': [
{
'name': 'always_search',
'default': False,
'type': 'bool',
'label': 'Always search',
'description': 'Search for movies even before there is a ETA. Enabling this will probably get you a lot of fakes.',
},
{
'name': 'run_on_launch',
'label': 'Run on launch',
'advanced': True,
'default': 0,
'type': 'bool',
'description': 'Force run the searcher after (re)start.',
},
{
'name': 'cron_day',
'label': 'Day',
'advanced': True,
'default': '*',
'type': 'string',
'description': '<strong>*</strong>: Every day, <strong>*/2</strong>: Every 2 days, <strong>1</strong>: Every first of the month. See <a href="http://packages.python.org/APScheduler/cronschedule.html">APScheduler</a> for details.',
},
{
'name': 'cron_hour',
'label': 'Hour',
'advanced': True,
'default': random.randint(0, 23),
'type': 'string',
'description': '<strong>*</strong>: Every hour, <strong>*/8</strong>: Every 8 hours, <strong>3</strong>: At 3, midnight.',
},
{
'name': 'cron_minute',
'label': 'Minute',
'advanced': True,
'default': random.randint(0, 59),
'type': 'string',
'description': "Just keep it random, so the providers don't get DDOSed by every CP user on a 'full' hour."
},
],
},
],
}]

202
couchpotato/core/plugins/searcher/main.py → couchpotato/core/media/movie/searcher/main.py

@ -3,13 +3,12 @@ from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato.core.helpers.variable import md5, getTitle, splitString, \
possibleTitles
possibleTitles, getImdb
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Movie, Release, ReleaseInfo
from couchpotato.environment import Env
from datetime import date
from inspect import ismethod, isfunction
from sqlalchemy.exc import InterfaceError
import datetime
import random
@ -20,30 +19,29 @@ import traceback
log = CPLog(__name__)
class Searcher(Plugin):
class MovieSearcher(Plugin):
in_progress = False
def __init__(self):
addEvent('searcher.all', self.allMovies)
addEvent('searcher.single', self.single)
addEvent('searcher.correct_movie', self.correctMovie)
addEvent('searcher.download', self.download)
addEvent('searcher.try_next_release', self.tryNextRelease)
addEvent('searcher.could_be_released', self.couldBeReleased)
addApiView('searcher.try_next', self.tryNextReleaseView, docs = {
addEvent('movie.searcher.all', self.searchAll)
addEvent('movie.searcher.single', self.single)
addEvent('movie.searcher.correct_movie', self.correctMovie)
addEvent('movie.searcher.try_next_release', self.tryNextRelease)
addEvent('movie.searcher.could_be_released', self.couldBeReleased)
addApiView('movie.searcher.try_next', self.tryNextReleaseView, docs = {
'desc': 'Marks the snatched results as ignored and try the next best release',
'params': {
'id': {'desc': 'The id of the movie'},
},
})
addApiView('searcher.full_search', self.allMoviesView, docs = {
addApiView('movie.searcher.full_search', self.searchAllView, docs = {
'desc': 'Starts a full search for all wanted movies',
})
addApiView('searcher.progress', self.getProgress, docs = {
addApiView('movie.searcher.progress', self.getProgress, docs = {
'desc': 'Get the progress of current full search',
'return': {'type': 'object', 'example': """{
'progress': False || object, total & to_go,
@ -51,7 +49,7 @@ class Searcher(Plugin):
})
if self.conf('run_on_launch'):
addEvent('app.load', self.allMovies)
addEvent('app.load', self.searchAll)
addEvent('app.load', self.setCrons)
addEvent('setting.save.searcher.cron_day.after', self.setCrons)
@ -59,16 +57,16 @@ class Searcher(Plugin):
addEvent('setting.save.searcher.cron_minute.after', self.setCrons)
def setCrons(self):
fireEvent('schedule.cron', 'searcher.all', self.allMovies, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
fireEvent('schedule.cron', 'movie.searcher.all', self.searchAll, day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
def allMoviesView(self, **kwargs):
def searchAllView(self, **kwargs):
in_progress = self.in_progress
if not in_progress:
fireEventAsync('searcher.all')
fireEvent('notify.frontend', type = 'searcher.started', data = True, message = 'Full search started')
fireEventAsync('movie.searcher.all')
fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started')
else:
fireEvent('notify.frontend', type = 'searcher.already_started', data = True, message = 'Full search already in progress')
fireEvent('notify.frontend', type = 'movie.searcher.already_started', data = True, message = 'Full search already in progress')
return {
'success': not in_progress
@ -80,7 +78,7 @@ class Searcher(Plugin):
'progress': self.in_progress
}
def allMovies(self):
def searchAll(self):
if self.in_progress:
log.info('Search already in progress')
@ -101,7 +99,7 @@ class Searcher(Plugin):
}
try:
search_types = self.getSearchTypes()
search_types = fireEvent('searcher.get_types', single = True)
for movie in movies:
movie_dict = movie.to_dict({
@ -136,7 +134,7 @@ class Searcher(Plugin):
# Find out search type
try:
if not search_types:
search_types = self.getSearchTypes()
search_types = fireEvent('searcher.get_types', single = True)
except SearchSetupError:
return
@ -161,7 +159,7 @@ class Searcher(Plugin):
fireEvent('movie.delete', movie['id'], single = True)
return
fireEvent('notify.frontend', type = 'searcher.started.%s' % movie['id'], data = True, message = 'Searching for "%s"' % default_title)
fireEvent('notify.frontend', type = 'movie.searcher.started.%s' % movie['id'], data = True, message = 'Searching for "%s"' % default_title)
ret = False
@ -253,7 +251,7 @@ class Searcher(Plugin):
log.info('Ignored, score to low: %s', nzb['name'])
continue
downloaded = self.download(data = nzb, movie = movie)
downloaded = fireEvent('searcher.download', data = nzb, movie = movie, single = True)
if downloaded is True:
ret = True
break
@ -277,107 +275,10 @@ class Searcher(Plugin):
if len(too_early_to_search) > 0:
log.info2('Too early to search for %s, %s', (too_early_to_search, default_title))
fireEvent('notify.frontend', type = 'searcher.ended.%s' % movie['id'], data = True)
fireEvent('notify.frontend', type = 'movie.searcher.ended.%s' % movie['id'], data = True)
return ret
def download(self, data, movie, manual = False):
# Test to see if any downloaders are enabled for this type
downloader_enabled = fireEvent('download.enabled', manual, data, single = True)
if downloader_enabled:
snatched_status = fireEvent('status.get', 'snatched', single = True)
# Download movie to temp
filedata = None
if data.get('download') and (ismethod(data.get('download')) or isfunction(data.get('download'))):
filedata = data.get('download')(url = data.get('url'), nzb_id = data.get('id'))
if filedata == 'try_next':
return filedata
download_result = fireEvent('download', data = data, movie = movie, manual = manual, filedata = filedata, single = True)
log.debug('Downloader result: %s', download_result)
if download_result:
try:
# Mark release as snatched
db = get_session()
rls = db.query(Release).filter_by(identifier = md5(data['url'])).first()
if rls:
renamer_enabled = Env.setting('enabled', 'renamer')
done_status = fireEvent('status.get', 'done', single = True)
rls.status_id = done_status.get('id') if not renamer_enabled else snatched_status.get('id')
# Save download-id info if returned
if isinstance(download_result, dict):
for key in download_result:
rls_info = ReleaseInfo(
identifier = 'download_%s' % key,
value = toUnicode(download_result.get(key))
)
rls.info.append(rls_info)
db.commit()
log_movie = '%s (%s) in %s' % (getTitle(movie['library']), movie['library']['year'], rls.quality.label)
snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie)
log.info(snatch_message)
fireEvent('movie.snatched', message = snatch_message, data = rls.to_dict())
# If renamer isn't used, mark movie done
if not renamer_enabled:
active_status = fireEvent('status.get', 'active', single = True)
done_status = fireEvent('status.get', 'done', single = True)
try:
if movie['status_id'] == active_status.get('id'):
for profile_type in movie['profile']['types']:
if profile_type['quality_id'] == rls.quality.id and profile_type['finish']:
log.info('Renamer disabled, marking movie as finished: %s', log_movie)
# Mark release done
rls.status_id = done_status.get('id')
rls.last_edit = int(time.time())
db.commit()
# Mark movie done
mvie = db.query(Movie).filter_by(id = movie['id']).first()
mvie.status_id = done_status.get('id')
mvie.last_edit = int(time.time())
db.commit()
except:
log.error('Failed marking movie finished, renamer disabled: %s', traceback.format_exc())
except:
log.error('Failed marking movie finished: %s', traceback.format_exc())
return True
log.info('Tried to download, but none of the "%s" downloaders are enabled or gave an error', (data.get('type', '')))
return False
def getSearchTypes(self):
download_types = fireEvent('download.enabled_types', merge = True)
provider_types = fireEvent('provider.enabled_types', merge = True)
if download_types and len(list(set(provider_types) & set(download_types))) == 0:
log.error('There aren\'t any providers enabled for your downloader (%s). Check your settings.', ','.join(download_types))
raise NoProviders
for useless_provider in list(set(provider_types) - set(download_types)):
log.debug('Provider for "%s" enabled, but no downloader.', useless_provider)
search_types = download_types
if len(search_types) == 0:
log.error('There aren\'t any downloaders enabled. Please pick one in settings.')
raise NoDownloaders
return search_types
def correctMovie(self, nzb = None, movie = None, quality = None, **kwargs):
imdb_results = kwargs.get('imdb_results', False)
@ -430,7 +331,7 @@ class Searcher(Plugin):
preferred_quality = fireEvent('quality.single', identifier = quality['identifier'], single = True)
# Contains lower quality string
if self.containsOtherQuality(nzb, movie_year = movie['library']['year'], preferred_quality = preferred_quality):
if fireEvent('searcher.contains_other_quality', nzb, movie_year = movie['library']['year'], preferred_quality = preferred_quality, single = True):
log.info2('Wrong: %s, looking for %s', (nzb['name'], quality['label']))
return False
@ -460,20 +361,20 @@ class Searcher(Plugin):
return True
# Check if nzb contains imdb link
if self.checkIMDB([nzb.get('description', '')], movie['library']['identifier']):
if getImdb(nzb.get('description', '')) == movie['library']['identifier']:
return True
for raw_title in movie['library']['titles']:
for movie_title in possibleTitles(raw_title['title']):
movie_words = re.split('\W+', simplifyString(movie_title))
if self.correctName(nzb['name'], movie_title):
if fireEvent('searcher.correct_name', nzb['name'], movie_title, single = True):
# if no IMDB link, at least check year range 1
if len(movie_words) > 2 and self.correctYear([nzb['name']], movie['library']['year'], 1):
if len(movie_words) > 2 and fireEvent('searcher.correct_year', nzb['name'], movie['library']['year'], 1, single = True):
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 fireEvent('searcher.correct_year', nzb['name'], movie['library']['year'], 0, single = True):
return True
log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'", (nzb['name'], movie_name, movie['library']['year']))
@ -527,45 +428,6 @@ class Searcher(Plugin):
return False
def correctYear(self, haystack, year, year_range):
for string in haystack:
year_name = fireEvent('scanner.name_year', string, single = True)
if year_name and ((year - year_range) <= year_name.get('year') <= (year + year_range)):
log.debug('Movie year matches range: %s looking for %s', (year_name.get('year'), year))
return True
log.debug('Movie year doesn\'t matche range: %s looking for %s', (year_name.get('year'), year))
return False
def correctName(self, check_name, movie_name):
check_names = [check_name]
# Match names between "
try: check_names.append(re.search(r'([\'"])[^\1]*\1', check_name).group(0))
except: pass
# Match longest name between []
try: check_names.append(max(check_name.split('['), key = len))
except: pass
for check_name in list(set(check_names)):
check_movie = fireEvent('scanner.name_year', check_name, single = True)
try:
check_words = filter(None, re.split('\W+', check_movie.get('name', '')))
movie_words = filter(None, re.split('\W+', simplifyString(movie_name)))
if len(check_words) > 0 and len(movie_words) > 0 and len(list(set(check_words) - set(movie_words))) == 0:
return True
except:
pass
return False
def couldBeReleased(self, is_pre_release, dates, year = None):
now = int(time.time())
@ -626,7 +488,7 @@ class Searcher(Plugin):
movie_dict = fireEvent('movie.get', movie_id, single = True)
log.info('Trying next release for: %s', getTitle(movie_dict['library']))
fireEvent('searcher.single', movie_dict)
fireEvent('movie.searcher.single', movie_dict)
return True
@ -636,9 +498,3 @@ class Searcher(Plugin):
class SearchSetupError(Exception):
pass
class NoDownloaders(SearchSetupError):
pass
class NoProviders(SearchSetupError):
pass

0
couchpotato/core/media/tv/__init__.py

6
couchpotato/core/media/tv/_base/__init__.py

@ -0,0 +1,6 @@
from .main import TVBase
def start():
return TVBase()
config = []

13
couchpotato/core/media/tv/_base/main.py

@ -0,0 +1,13 @@
from couchpotato.core.logger import CPLog
from couchpotato.core.media import MediaBase
log = CPLog(__name__)
class TVBase(MediaBase):
identifier = 'tv'
def __init__(self):
super(TVBase, self).__init__()

7
couchpotato/core/media/tv/searcher/__init__.py

@ -0,0 +1,7 @@
from .main import TVSearcher
import random
def start():
return TVSearcher()
config = []

12
couchpotato/core/media/tv/searcher/main.py

@ -0,0 +1,12 @@
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
log = CPLog(__name__)
class TVSearcher(Plugin):
in_progress = False
def __init__(self):
pass

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

@ -36,4 +36,4 @@ class Automation(Plugin):
for movie_id in movie_ids:
movie_dict = fireEvent('movie.get', movie_id, single = True)
fireEvent('searcher.single', movie_dict)
fireEvent('movie.searcher.single', movie_dict)

1
couchpotato/core/plugins/category/static/category.js

@ -37,7 +37,6 @@ var CategoryListBase = new Class({
self.settings.addEvent('create', function(){
var renamer_group = self.settings.tabs.renamer.groups.renamer;
p(renamer_group.getElement('.renamer_to'))
self.categories.each(function(category){
var input = new Option.Directory('section_name', 'option.name', category.get('destination'), {

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

@ -70,9 +70,9 @@ class Dashboard(Plugin):
coming_soon = False
# Theater quality
if pp.get('theater') and fireEvent('searcher.could_be_released', True, eta, movie.library.year, single = True):
if pp.get('theater') and fireEvent('movie.searcher.could_be_released', True, eta, movie.library.year, single = True):
coming_soon = True
if pp.get('dvd') and fireEvent('searcher.could_be_released', False, eta, movie.library.year, single = True):
if pp.get('dvd') and fireEvent('movie.searcher.could_be_released', False, eta, movie.library.year, single = True):
coming_soon = True
# Skip if movie is snatched/downloaded/available

6
couchpotato/core/plugins/movie/__init__.py

@ -1,6 +0,0 @@
from .main import MoviePlugin
def start():
return MoviePlugin()
config = []

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

@ -715,7 +715,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
db.commit()
if self.conf('next_on_failed'):
fireEvent('searcher.try_next_release', movie_id = rel.movie_id)
fireEvent('movie.searcher.try_next_release', movie_id = rel.movie_id)
elif item['status'] == 'completed':
log.info('Download of %s completed!', item['name'])
if self.statusInfoComplete(item):

2
couchpotato/core/providers/base.py

@ -257,7 +257,7 @@ class ResultList(list):
new_result = self.fillResult(result)
is_correct_movie = fireEvent('searcher.correct_movie',
is_correct_movie = fireEvent('movie.searcher.correct_movie',
nzb = new_result, movie = self.movie, quality = self.quality,
imdb_results = self.kwargs.get('imdb_results', False), single = True)

4
couchpotato/static/scripts/page/wanted.js

@ -40,7 +40,7 @@ Page.Wanted = new Class({
if(!self.search_in_progress){
Api.request('searcher.full_search');
Api.request('movie.searcher.full_search');
self.startProgressInterval();
}
@ -53,7 +53,7 @@ Page.Wanted = new Class({
var start_text = self.manual_search.get('text');
self.progress_interval = setInterval(function(){
if(self.search_progress && self.search_progress.running) return;
self.search_progress = Api.request('searcher.progress', {
self.search_progress = Api.request('movie.searcher.progress', {
'onComplete': function(json){
self.search_in_progress = true;
if(!json.progress){

Loading…
Cancel
Save