Merge branch 'refs/heads/develop' into tv

Conflicts:
	couchpotato/core/media/__init__.py
	couchpotato/core/media/_base/searcher/main.py
	couchpotato/core/media/movie/_base/main.py
	couchpotato/core/media/movie/searcher/__init__.py
	couchpotato/core/media/movie/searcher/main.py
This commit is contained in:
Ruud
2013-08-16 21:07:59 +02:00
10 changed files with 127 additions and 96 deletions
+3 -6
View File
@@ -2,16 +2,13 @@ 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):
_type = None
def initType(self):
addEvent('media.types', self.getType)
def getType(self):
return self.identifier
return self._type
@@ -0,0 +1,51 @@
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
log = CPLog(__name__)
class SearcherBase(Plugin):
in_progress = False
def __init__(self):
super(SearcherBase, self).__init__()
addEvent('searcher.progress', self.getProgress)
addEvent('%s.searcher.progress' % self.getType(), self.getProgress)
self.initCron()
""" Set the searcher cronjob
Make sure to reset cronjob after setting has changed
"""
def initCron(self):
_type = self.getType()
def setCrons():
fireEvent('schedule.cron', '%s.searcher.all' % _type, self.searchAll,
day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
addEvent('app.load', setCrons)
addEvent('setting.save.%s_searcher.cron_day.after' % _type, setCrons)
addEvent('setting.save.%s_searcher.cron_hour.after' % _type, setCrons)
addEvent('setting.save.%s_searcher.cron_minute.after' % _type, setCrons)
""" Return progress of current searcher
"""
def getProgress(self, **kwargs):
progress = {}
progress[self.getType()] = self.in_progress
return progress
+27 -2
View File
@@ -1,9 +1,10 @@
from couchpotato import get_session
from couchpotato.api import addApiView
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.media._base.searcher.base import SearcherBase
from couchpotato.core.settings.model import Movie, Release, ReleaseInfo
from couchpotato.environment import Env
from inspect import ismethod, isfunction
@@ -15,7 +16,7 @@ import traceback
log = CPLog(__name__)
class Searcher(Plugin):
class Searcher(SearcherBase):
def __init__(self):
addEvent('searcher.get_types', self.getSearchTypes)
@@ -24,6 +25,30 @@ class Searcher(Plugin):
addEvent('searcher.correct_name', self.correctName)
addEvent('searcher.download', self.download)
addApiView('searcher.full_search', self.searchAllView, docs = {
'desc': 'Starts a full search for all media',
})
addApiView('searcher.progress', self.getProgressForAll, docs = {
'desc': 'Get the progress of all media searches',
'return': {'type': 'object', 'example': """{
'movie': False || object, total & to_go,
'show': False || object, total & to_go,
}"""},
})
def searchAllView(self):
results = {}
for _type in fireEvent('media.types'):
results[_type] = fireEvent('%s.searcher.all_view' % _type)
return results
def getProgressForAll(self):
progress = fireEvent('searcher.progress', merge = True)
return progress
def download(self, data, movie, manual = False):
# Test to see if any downloaders are enabled for this type
+6
View File
@@ -0,0 +1,6 @@
from couchpotato.core.media import MediaBase
class MovieTypeBase(MediaBase):
_type = 'movie'
+5 -4
View File
@@ -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.media import MediaBase
from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Library, LibraryTitle, Movie, \
Release
from couchpotato.environment import Env
@@ -16,9 +16,7 @@ import time
log = CPLog(__name__)
class MovieBase(MediaBase):
identifier = 'movie'
class MovieBase(MovieTypeBase):
default_dict = {
'profile': {'types': {'quality': {}}},
@@ -29,7 +27,10 @@ class MovieBase(MediaBase):
}
def __init__(self):
# Initialize this type
super(MovieBase, self).__init__()
self.initType()
addApiView('movie.search', self.search, docs = {
'desc': 'Search the movie providers for a movie',
@@ -5,7 +5,7 @@ def start():
return MovieSearcher()
config = [{
'name': 'searcher',
'name': 'moviesearcher',
'order': 20,
'groups': [
{
@@ -18,12 +18,14 @@ config = [{
{
'name': 'always_search',
'default': False,
'migrate_from': 'searcher',
'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',
'migrate_from': 'searcher',
'label': 'Run on launch',
'advanced': True,
'default': 0,
@@ -32,6 +34,7 @@ config = [{
},
{
'name': 'cron_day',
'migrate_from': 'searcher',
'label': 'Day',
'advanced': True,
'default': '*',
@@ -40,6 +43,7 @@ config = [{
},
{
'name': 'cron_hour',
'migrate_from': 'searcher',
'label': 'Hour',
'advanced': True,
'default': random.randint(0, 23),
@@ -48,6 +52,7 @@ config = [{
},
{
'name': 'cron_minute',
'migrate_from': 'searcher',
'label': 'Minute',
'advanced': True,
'default': random.randint(0, 59),
+12 -76
View File
@@ -5,12 +5,12 @@ from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato.core.helpers.variable import md5, getTitle, splitString, \
possibleTitles, getImdb
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Movie, Release, ReleaseInfo
from couchpotato.environment import Env
from datetime import date
from sqlalchemy.exc import InterfaceError
import datetime
import random
import re
import time
@@ -19,12 +19,15 @@ import traceback
log = CPLog(__name__)
class MovieSearcher(Plugin):
class MovieSearcher(SearcherBase, MovieTypeBase):
in_progress = False
def __init__(self):
super(MovieSearcher, self).__init__()
addEvent('movie.searcher.all', self.searchAll)
addEvent('movie.searcher.all_view', self.searchAllView)
addEvent('movie.searcher.single', self.single)
addEvent('movie.searcher.correct_movie', self.correctMovie)
addEvent('movie.searcher.try_next_release', self.tryNextRelease)
@@ -48,45 +51,26 @@ class MovieSearcher(Plugin):
}"""},
})
if self.conf('run_on_launch', section = 'searcher'):
if self.conf('run_on_launch'):
addEvent('app.load', self.searchAll)
addEvent('app.load', self.setCrons)
addEvent('setting.save.searcher.cron_day.after', self.setCrons)
addEvent('setting.save.searcher.cron_hour.after', self.setCrons)
addEvent('setting.save.searcher.cron_minute.after', self.setCrons)
def setCrons(self):
fireEvent('schedule.cron', 'movie.searcher.all', self.searchAll,
day = self.conf('cron_day', section = 'searcher'), hour = self.conf('cron_hour', section = 'searcher'), minute = self.conf('cron_minute', section = 'searcher'))
def searchAllView(self, **kwargs):
in_progress = self.in_progress
if not in_progress:
fireEventAsync('movie.searcher.all')
fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started')
else:
fireEvent('notify.frontend', type = 'movie.searcher.already_started', data = True, message = 'Full search already in progress')
fireEventAsync('movie.searcher.all')
return {
'success': not in_progress
}
def getProgress(self, **kwargs):
return {
'progress': self.in_progress
'success': not self.in_progress
}
def searchAll(self):
if self.in_progress:
log.info('Search already in progress')
fireEvent('notify.frontend', type = 'movie.searcher.already_started', data = True, message = 'Full search already in progress')
return
self.in_progress = True
fireEvent('notify.frontend', type = 'movie.searcher.started', data = True, message = 'Full search started')
db = get_session()
@@ -166,7 +150,7 @@ class MovieSearcher(Plugin):
ret = False
for quality_type in movie['profile']['types']:
if not self.conf('always_search', section = 'searcher') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']):
if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['library']['year']):
too_early_to_search.append(quality_type['quality']['identifier'])
continue
@@ -382,54 +366,6 @@ class MovieSearcher(Plugin):
log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'", (nzb['name'], movie_name, movie['library']['year']))
return False
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 checkIMDB(self, haystack, imdbId):
for string in haystack:
if 'imdb.com/title/' + imdbId in string:
return True
return False
def couldBeReleased(self, is_pre_release, dates, year = None):
now = int(time.time())
@@ -15,12 +15,13 @@ class ThePirateBay(TorrentMagnetProvider):
urls = {
'detail': '%s/torrent/%s',
'search': '%s/search/%s/%s/7/%d'
'search': '%s/search/%s/%s/7/%s'
}
cat_ids = [
([207], ['720p', '1080p']),
([201], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr', 'brrip']),
([201], ['cam', 'ts', 'dvdrip', 'tc', 'r5', 'scr']),
([201, 207], ['brrip']),
([202], ['dvdr'])
]
@@ -50,10 +51,11 @@ class ThePirateBay(TorrentMagnetProvider):
page = 0
total_pages = 1
cats = self.getCatId(quality['identifier'])
while page < total_pages:
search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['library']['year'])), page, self.getCatId(quality['identifier'])[0])
search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['library']['year'])), page, ','.join(str(x) for x in cats))
page += 1
data = self.getHTMLData(search_url)
+10 -2
View File
@@ -2,7 +2,7 @@ from __future__ import with_statement
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import isInt, toUnicode
from couchpotato.core.helpers.variable import mergeDicts, tryInt
from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat
from couchpotato.core.settings.model import Properties
import ConfigParser
import os.path
@@ -77,9 +77,17 @@ class Settings(object):
def registerDefaults(self, section_name, options = {}, save = True):
self.addSection(section_name)
for option_name, option in options.iteritems():
self.setDefault(section_name, option_name, option.get('default', ''))
# Migrate old settings from old location to the new location
if option.get('migrate_from'):
if self.p.has_option(option.get('migrate_from'), option_name):
previous_value = self.p.get(option.get('migrate_from'), option_name)
self.p.set(section_name, option_name, previous_value)
self.p.remove_option(option.get('migrate_from'), option_name)
if option.get('type'):
self.setType(section_name, option_name, option.get('type'))
@@ -122,7 +130,7 @@ class Settings(object):
try:
return self.p.getfloat(section, option)
except:
return tryInt(self.p.get(section, option))
return tryFloat(self.p.get(section, option))
def getUnicode(self, section, option):
value = self.p.get(section, option).decode('unicode_escape')
+2 -2
View File
@@ -56,13 +56,13 @@ Page.Wanted = new Class({
self.search_progress = Api.request('movie.searcher.progress', {
'onComplete': function(json){
self.search_in_progress = true;
if(!json.progress){
if(!json.movie){
clearInterval(self.progress_interval);
self.search_in_progress = false;
self.manual_search.set('text', start_text);
}
else {
var progress = json.progress;
var progress = json.movie;
self.manual_search.set('text', 'Searching.. (' + (((progress.total-progress.to_go)/progress.total)*100).round() + '%)');
}
}