More nosql

This commit is contained in:
Ruud
2014-02-02 20:41:14 +01:00
parent 63743dd2b6
commit 99252074be
82 changed files with 643 additions and 715 deletions
+2 -2
View File
@@ -42,11 +42,11 @@ class Core(Plugin):
addEvent('app.shutdown', self.shutdown) addEvent('app.shutdown', self.shutdown)
addEvent('app.restart', self.restart) addEvent('app.restart', self.restart)
addEvent('app.load2', self.launchBrowser, priority = 1) addEvent('app.load', self.launchBrowser, priority = 1)
addEvent('app.base_url', self.createBaseUrl) addEvent('app.base_url', self.createBaseUrl)
addEvent('app.api_url', self.createApiUrl) addEvent('app.api_url', self.createApiUrl)
addEvent('app.version', self.version) addEvent('app.version', self.version)
addEvent('app.load2', self.checkDataDir) addEvent('app.load', self.checkDataDir)
addEvent('setting.save.core.password', self.md5Password) addEvent('setting.save.core.password', self.md5Password)
addEvent('setting.save.core.api_key', self.checkApikey) addEvent('setting.save.core.api_key', self.checkApikey)
+1 -1
View File
@@ -74,7 +74,7 @@ class ClientScript(Plugin):
addEvent('clientscript.get_scripts', self.getScripts) addEvent('clientscript.get_scripts', self.getScripts)
if not Env.get('dev'): if not Env.get('dev'):
addEvent('app.load2', self.minify) addEvent('app.load', self.minify)
self.addCore() self.addCore()
+1 -1
View File
@@ -25,7 +25,7 @@ if Env.get('desktop'):
# Events to desktop # Events to desktop
addEvent('app.after_shutdown', desktop.afterShutdown) addEvent('app.after_shutdown', desktop.afterShutdown)
addEvent('app.load2', desktop.onAppLoad, priority = 110) addEvent('app.load', desktop.onAppLoad, priority = 110)
def onClose(self, event): def onClose(self, event):
return fireEvent('app.shutdown', single = True) return fireEvent('app.shutdown', single = True)
+2 -2
View File
@@ -33,8 +33,8 @@ class Updater(Plugin):
else: else:
self.updater = SourceUpdater() self.updater = SourceUpdater()
addEvent('app.load2', self.logVersion, priority = 10000) addEvent('app.load', self.logVersion, priority = 10000)
addEvent('app.load2', self.setCrons) addEvent('app.load', self.setCrons)
addEvent('updater.info', self.info) addEvent('updater.info', self.info)
addApiView('updater.info', self.info, docs = { addApiView('updater.info', self.info, docs = {
@@ -23,7 +23,7 @@ class rTorrent(Downloader):
def __init__(self): def __init__(self):
super(rTorrent, self).__init__() super(rTorrent, self).__init__()
addEvent('app.load2', self.migrate) addEvent('app.load', self.migrate)
def migrate(self): def migrate(self):
+7 -9
View File
@@ -216,26 +216,24 @@ def toIterable(value):
return [value] return [value]
def getTitle(library_dict): def getTitle(media_dict):
try: try:
try: try:
return library_dict['titles'][0]['title'] return media_dict['title']
except: except:
try: try:
for title in library_dict.titles: return media_dict['titles'][0]
if title.default:
return title.title
except: except:
try: try:
return library_dict['info']['titles'][0] return media_dict['info']['titles'][0]
except: except:
log.error('Could not get title for %s', library_dict.identifier) log.error('Could not get title for %s', media_dict.get('identifier'))
return None return None
log.error('Could not get title for %s', library_dict['identifier']) log.error('Could not get title for %s', media_dict['identifier'])
return None return None
except: except:
log.error('Could not get title for library item: %s', library_dict) log.error('Could not get title for library item: %s', media_dict)
return None return None
+3 -8
View File
@@ -1,8 +1,7 @@
import traceback import traceback
from couchpotato import get_session, get_db, CPLog from couchpotato import get_db, CPLog
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Media
log = CPLog(__name__) log = CPLog(__name__)
@@ -34,11 +33,9 @@ class MediaBase(Plugin):
media = db.get('id', media_id) media = db.get('id', media_id)
event_name = '%s.searcher.single' % media.get('type') event_name = '%s.searcher.single' % media.get('type')
fireEvent(event_name, media, on_complete = self.createNotifyFront(media_id)) fireEventAsync(event_name, media, on_complete = self.createNotifyFront(media_id))
except: except:
log.error('Failed creating onComplete: %s', traceback.format_exc()) log.error('Failed creating onComplete: %s', traceback.format_exc())
finally:
pass #db.close()
return onComplete return onComplete
@@ -53,7 +50,5 @@ class MediaBase(Plugin):
fireEvent('notify.frontend', type = event_name, data = media) fireEvent('notify.frontend', type = event_name, data = media)
except: except:
log.error('Failed creating onComplete: %s', traceback.format_exc()) log.error('Failed creating onComplete: %s', traceback.format_exc())
finally:
pass #db.close()
return notifyFront return notifyFront
@@ -1,13 +0,0 @@
from couchpotato.core.event import addEvent
from couchpotato.core.plugins.base import Plugin
class LibraryBase(Plugin):
_type = None
def initType(self):
addEvent('library.types', self.getType)
def getType(self):
return self._type
+12 -7
View File
@@ -14,9 +14,14 @@ class MediaIMDBIndex(HashIndex):
return int(key.strip('t')) return int(key.strip('t'))
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'media' and data.get('identifier'): if data.get('_t') == 'media' and data.get('identifier'):
return int(data['identifier'].strip('t')), None return int(data['identifier'].strip('t')), None
def run_to_dict(self, db, media_id, dict = None):
if not dict: dict = {}
return db.get('id', media_id)
def run_with_status(self, db, status = []): def run_with_status(self, db, status = []):
status = list(status if isinstance(status, (list, tuple)) else [status]) status = list(status if isinstance(status, (list, tuple)) else [status])
@@ -29,15 +34,15 @@ class MediaIMDBIndex(HashIndex):
class MediaStatusIndex(TreeBasedIndex): class MediaStatusIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = '32s'
super(MediaStatusIndex, self).__init__(*args, **kwargs) super(MediaStatusIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return md5(key).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'media' and data.get('status'): if data.get('_t') == 'media' and data.get('status'):
return md5(data.get('status')).digest(), None return md5(data.get('status')).hexdigest(), None
class TitleIndex(MultiTreeBasedIndex): class TitleIndex(MultiTreeBasedIndex):
@@ -52,7 +57,7 @@ from itertools import izip"""
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'title' and len(data.get('title', '')) > 0: if data.get('_t') == 'title' and len(data.get('title', '')) > 0:
out = set() out = set()
title = data.get('title').lower() title = data.get('title').lower()
@@ -80,5 +85,5 @@ class YearIndex(TreeBasedIndex):
return key return key
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'media' and data.get('year') is not None: if data.get('_t') == 'media' and data.get('year') is not None:
return data['year'], None return data['year'], None
+100 -99
View File
@@ -1,16 +1,14 @@
import traceback import traceback
import time
from couchpotato import get_session, tryInt, get_db from couchpotato import get_session, tryInt, get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import mergeDicts, splitString, getImdb, getTitle from couchpotato.core.helpers.variable import mergeDicts, splitString, getImdb, getTitle
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media import MediaBase from couchpotato.core.media import MediaBase
from .index import MediaIMDBIndex, TitleIndex, MediaStatusIndex, YearIndex from .index import MediaIMDBIndex, TitleIndex, MediaStatusIndex, YearIndex
from couchpotato.core.settings.model import Library, LibraryTitle, Release, \ from couchpotato.core.settings.model import Library, LibraryTitle, Release, \
Media Media
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import or_, asc, not_, desc
from string import ascii_lowercase from string import ascii_lowercase
log = CPLog(__name__) log = CPLog(__name__)
@@ -63,10 +61,10 @@ class MediaPlugin(MediaBase):
addEvent('database.setup', self.databaseSetup) addEvent('database.setup', self.databaseSetup)
addEvent('app.load2', self.addSingleRefreshView) addEvent('app.load', self.addSingleRefreshView)
addEvent('app.load2', self.addSingleListView) addEvent('app.load', self.addSingleListView)
addEvent('app.load2', self.addSingleCharView) addEvent('app.load', self.addSingleCharView)
addEvent('app.load2', self.addSingleDeleteView) addEvent('app.load', self.addSingleDeleteView)
addEvent('media.get', self.get) addEvent('media.get', self.get)
addEvent('media.list', self.list) addEvent('media.list', self.list)
@@ -126,7 +124,7 @@ class MediaPlugin(MediaBase):
try: try:
media = get_db().get('id', media_id) media = get_db().get('id', media_id)
default_title = getTitle(media_id) default_title = getTitle(media)
event = 'library.update.%s' % media.get('type') event = 'library.update.%s' % media.get('type')
def handler(): def handler():
@@ -157,7 +155,7 @@ class MediaPlugin(MediaBase):
results = None results = None
if m: if m:
results = db.run('media', 'to_dict', m, self.default_dict) results = db.run('media', 'to_dict', m['_id'])
return results return results
@@ -172,7 +170,9 @@ class MediaPlugin(MediaBase):
def list(self, types = None, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None): def list(self, types = None, status = None, release_status = None, limit_offset = None, starts_with = None, search = None, order = None):
db = get_session() db = get_db()
start = time.time()
# Make a list from string # Make a list from string
if status and not isinstance(status, (list, tuple)): if status and not isinstance(status, (list, tuple)):
@@ -182,120 +182,128 @@ class MediaPlugin(MediaBase):
if types and not isinstance(types, (list, tuple)): if types and not isinstance(types, (list, tuple)):
types = [types] types = [types]
# query movie ids # query media ids
q = db.query(Media) \ all_media_ids = set([x['_id'] for x in db.all('media')])
.with_entities(Media.id) \ media_ids = all_media_ids
.group_by(Media.id) filter_by = {}
# Filter on movie status # Filter on movie status
if status and len(status) > 0: if status and len(status) > 0:
statuses = fireEvent('status.get', status, single = len(status) > 1) filter_by['media_status'] = set()
statuses = [s.get('id') for s in statuses] for media_status in db.run('media', 'with_status', status):
filter_by['media_status'].add(media_status.get('_id'))
q = q.filter(Media.status_id.in_(statuses))
# Filter on release status # Filter on release status
if release_status and len(release_status) > 0: if release_status and len(release_status) > 0:
q = q.join(Media.releases) filter_by['release_status'] = set()
for release_status in db.run('release', 'with_status', release_status):
filter_by['release_status'].add(release_status.get('media_id'))
statuses = fireEvent('status.get', release_status, single = len(release_status) > 1) # Filter by combining ids
statuses = [s.get('id') for s in statuses] for x in filter_by:
media_ids = media_ids & filter_by[x]
q = q.filter(Release.status_id.in_(statuses))
# Filter on type # Filter on type
if types and len(types) > 0: # if types and len(types) > 0:
try: q = q.filter(Media.type.in_(types)) # try: q = q.filter(Media.type.in_(types))
except: pass # except: pass
# Only join when searching / ordering # Only join when searching / ordering
if starts_with or search or order != 'release_order': # if starts_with or search or order != 'release_order':
q = q.join(Media.library, Library.titles) \ # q = q.join(Media.library, Library.titles) \
.filter(LibraryTitle.default == True) # .filter(LibraryTitle.default == True)
# Add search filters # Add search filters
filter_or = [] # filter_or = []
if starts_with: # if starts_with:
starts_with = toUnicode(starts_with.lower()) # starts_with = toUnicode(starts_with.lower())
if starts_with in ascii_lowercase: # if starts_with in ascii_lowercase:
filter_or.append(LibraryTitle.simple_title.startswith(starts_with)) # filter_or.append(LibraryTitle.simple_title.startswith(starts_with))
else: # else:
ignore = [] # ignore = []
for letter in ascii_lowercase: # for letter in ascii_lowercase:
ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter))) # ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter)))
filter_or.append(not_(or_(*ignore))) # filter_or.append(not_(or_(*ignore)))
if search: if search:
filter_or.append(LibraryTitle.simple_title.like('%%' + search + '%%')) search_ids = db.get_many('media_title', search)
for search_id in search_ids:
print search_id
if len(filter_or) > 0: #if len(filter_or) > 0:
q = q.filter(or_(*filter_or)) # pass #q = q.filter(or_(*filter_or))
total_count = q.count() total_count = len(media_ids)
if total_count == 0: if total_count == 0:
return 0, [] return 0, []
if order == 'release_order': # if order == 'release_order':
q = q.order_by(desc(Release.last_edit)) # q = q.order_by(desc(Release.last_edit))
else: # else:
q = q.order_by(asc(LibraryTitle.simple_title)) # q = q.order_by(asc(LibraryTitle.simple_title))
if limit_offset: # if limit_offset:
splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset # splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset
limit = splt[0] # limit = splt[0]
offset = 0 if len(splt) is 1 else splt[1] # offset = 0 if len(splt) is 1 else splt[1]
q = q.limit(limit).offset(offset) # q = q.limit(limit).offset(offset)
# Get all media_ids in sorted order # Get all media_ids in sorted order
media_ids = [m.id for m in q.all()] # media_ids = [m.id for m in q.all()]
# List release statuses # List release statuses
releases = db.query(Release) \ # releases = db.query(Release) \
.filter(Release.movie_id.in_(media_ids)) \ # .filter(Release.movie_id.in_(media_ids)) \
.all() # .all()
release_statuses = dict((m, set()) for m in media_ids) # release_statuses = dict((m, set()) for m in media_ids)
releases_count = dict((m, 0) for m in media_ids) # releases_count = dict((m, 0) for m in media_ids)
for release in releases: # for release in releases:
release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id)) # release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id))
releases_count[release.movie_id] += 1 # releases_count[release.movie_id] += 1
# Get main movie data # Get main movie data
q2 = db.query(Media) \ # q2 = db.query(Media) \
.options(joinedload_all('library.titles')) \ # .options(joinedload_all('library.titles')) \
.options(joinedload_all('library.files')) \ # .options(joinedload_all('library.files')) \
.options(joinedload_all('status')) \ # .options(joinedload_all('status')) \
.options(joinedload_all('files')) # .options(joinedload_all('files'))
q2 = q2.filter(Media.id.in_(media_ids)) # q2 = q2.filter(Media.id.in_(media_ids))
results = q2.all() # results = q2.all()
# Create dict by movie id # Create dict by movie id
movie_dict = {} # medias = {}
for movie in results: # for media in media_ids:
movie_dict[movie.id] = movie # movie_dict[movie.id] = movie
# List movies based on media_ids order # List movies based on media_ids order
movies = [] medias = []
for media_id in media_ids: for media_id in media_ids:
releases = [] media = db.run('media', 'to_dict', media_id, {
for r in release_statuses.get(media_id):
x = splitString(r)
releases.append({'status_id': x[0], 'quality_id': x[1]})
# Merge releases with movie dict
movies.append(mergeDicts(movie_dict[media_id].to_dict({
'library': {'titles': {}, 'files': {}}, 'library': {'titles': {}, 'files': {}},
'files': {}, 'files': {},
}), { })
'releases': releases,
'releases_count': releases_count.get(media_id),
}))
pass #db.close() media['releases'] = []
return total_count, movies for r in db.get_many('release', media_id, with_doc = True):
media['releases'].append(r)
# Merge releases with movie dict
medias.append(media)
# medias.append(mergeDicts(movie_dict[media_id].to_dict({
# 'library': {'titles': {}, 'files': {}},
# 'files': {},
# }), {
# 'releases': releases,
# 'releases_count': releases_count.get(media_id),
# }))
print time.time() - start
return total_count, medias
def listView(self, **kwargs): def listView(self, **kwargs):
@@ -424,19 +432,18 @@ class MediaPlugin(MediaBase):
db.commit() db.commit()
deleted = True deleted = True
else: else:
done_status = fireEvent('status.get', 'done', single = True)
total_releases = len(media.releases) total_releases = len(media.releases)
total_deleted = 0 total_deleted = 0
new_movie_status = None new_movie_status = None
for release in media.releases: for release in media.releases:
if delete_from in ['wanted', 'snatched', 'late']: if delete_from in ['wanted', 'snatched', 'late']:
if release.status_id != done_status.get('id'): if release.get('status') != 'done':
db.delete(release) db.delete(release)
total_deleted += 1 total_deleted += 1
new_movie_status = 'done' new_movie_status = 'done'
elif delete_from == 'manage': elif delete_from == 'manage':
if release.status_id == done_status.get('id'): if release.get('status') == 'done':
db.delete(release) db.delete(release)
total_deleted += 1 total_deleted += 1
new_movie_status = 'active' new_movie_status = 'active'
@@ -447,9 +454,8 @@ class MediaPlugin(MediaBase):
db.commit() db.commit()
deleted = True deleted = True
elif new_movie_status: elif new_movie_status:
new_status = fireEvent('status.get', new_movie_status, single = True)
media.profile_id = None media.profile_id = None
media.status_id = new_status.get('id') media['status'] = new_status
db.commit() db.commit()
else: else:
fireEvent('media.restatus', media.id, single = True) fireEvent('media.restatus', media.id, single = True)
@@ -458,9 +464,6 @@ class MediaPlugin(MediaBase):
fireEvent('notify.frontend', type = 'movie.deleted', data = media.to_dict()) fireEvent('notify.frontend', type = 'movie.deleted', data = media.to_dict())
except: except:
log.error('Failed deleting media: %s', traceback.format_exc()) log.error('Failed deleting media: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return True return True
@@ -483,8 +486,6 @@ class MediaPlugin(MediaBase):
def restatus(self, media_id): def restatus(self, media_id):
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
try: try:
db = get_session() db = get_session()
@@ -494,17 +495,17 @@ class MediaPlugin(MediaBase):
return False return False
log.debug('Changing status for %s', m.library.titles[0].title) log.debug('Changing status for %s', m.library.titles[0].title)
if not m.profile: if not m['profile_id']:
m.status_id = done_status.get('id') m['status'] = 'done'
else: else:
move_to_wanted = True move_to_wanted = True
for t in m.profile.types: for t in m.profile.types:
for release in m.releases: for release in m.releases:
if t.quality.identifier is release.quality.identifier and (release.status_id is done_status.get('id') and t.finish): if t.quality.identifier is release.quality.identifier and (release.get('status') == 'done' and t.finish):
move_to_wanted = False move_to_wanted = False
m.status_id = active_status.get('id') if move_to_wanted else done_status.get('id') m['status'] = 'active' if move_to_wanted else 'done'
db.commit() db.commit()
+1 -1
View File
@@ -25,7 +25,7 @@ class Search(Plugin):
}"""} }"""}
}) })
addEvent('app.load2', self.addSingleSearches) addEvent('app.load', self.addSingleSearches)
def search(self, q = '', types = None, **kwargs): def search(self, q = '', types = None, **kwargs):
@@ -28,7 +28,7 @@ class SearcherBase(Plugin):
fireEvent('schedule.cron', '%s.searcher.all' % _type, self.searchAll, fireEvent('schedule.cron', '%s.searcher.all' % _type, self.searchAll,
day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute')) day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
addEvent('app.load2', setCrons) addEvent('app.load', setCrons)
addEvent('setting.save.%s_searcher.cron_day.after' % _type, 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_hour.after' % _type, setCrons)
addEvent('setting.save.%s_searcher.cron_minute.after' % _type, setCrons) addEvent('setting.save.%s_searcher.cron_minute.after' % _type, setCrons)
@@ -48,7 +48,7 @@ class Searcher(SearcherBase):
results = [] results = []
for search_protocol in protocols: for search_protocol in protocols:
protocol_results = fireEvent('provider.search.%s.%s' % (search_protocol, media['type']), media, quality, merge = True) protocol_results = fireEvent('provider.search.%s.%s' % (search_protocol, media.get('type')), media, quality, merge = True)
if protocol_results: if protocol_results:
results += protocol_results results += protocol_results
+174 -19
View File
@@ -1,13 +1,13 @@
import traceback import traceback
from couchpotato import get_session, get_db from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import splitString, tryInt, getTitle from couchpotato.core.helpers.variable import splitString, tryInt, getTitle
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Media
import time import time
import six
log = CPLog(__name__) log = CPLog(__name__)
@@ -42,8 +42,10 @@ class MovieBase(MovieTypeBase):
}) })
addEvent('movie.add', self.add) addEvent('movie.add', self.add)
addEvent('movie.update_info', self.updateInfo)
addEvent('movie.update_release_dates', self.updateReleaseDate)
def add(self, params = None, force_readd = True, search_after = True, update_library = False, status_id = None): def add(self, params = None, force_readd = True, search_after = True, update_library = False, status = None):
if not params: params = {} if not params: params = {}
if not params.get('identifier'): if not params.get('identifier'):
@@ -62,27 +64,55 @@ class MovieBase(MovieTypeBase):
except: except:
pass pass
# library = fireEvent('library.add.movie', single = True, attrs = params, update_after = update_library)
info = fireEvent('movie.info', merge = True, extended = False, identifier = params.get('identifier')) info = fireEvent('movie.info', merge = True, extended = False, identifier = params.get('identifier'))
# Set default title
default_title = toUnicode(info.get('title'))
titles = info.get('titles', [])
counter = 0
def_title = None
for title in titles:
if (len(default_title) == 0 and counter == 0) or len(titles) == 1 or title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
def_title = toUnicode(title)
break
counter += 1
if not def_title:
def_title = toUnicode(titles[0])
# Default profile and category
default_profile = fireEvent('profile.default', single = True) default_profile = fireEvent('profile.default', single = True)
cat_id = params.get('category_id') cat_id = params.get('category_id')
try: try:
db = get_db() db = get_db()
media = {
'_t': 'media',
'type': 'movie',
'title': def_title,
'identifier': params.get('identifier'),
'status': status if status else 'active',
'profile_id': params.get('profile_id', default_profile.get('_id')),
'category_id': tryInt(cat_id) if cat_id is not None and tryInt(cat_id) > 0 else None,
}
new = False new = False
try: try:
m = db.get('movie', params.get('identifier'), with_doc = True)['doc'] m = db.get('media', params.get('identifier'), with_doc = True)['doc']
except: except:
new = True new = True
m = db.insert({ m = db.insert(media)
'type': 'movie',
'identifier': params.get('identifier'), # Update dict to be usable
'status': status_id if status_id else 'active', m.update(media)
'profile_id': params.get('profile_id', default_profile.get('id')),
'category_id': tryInt(cat_id) if cat_id is not None and tryInt(cat_id) > 0 else None, # Update movie info
}) try: del info['in_wanted']
except: pass
try: del info['in_library']
except: pass
m['info'] = info
added = True added = True
do_search = False do_search = False
@@ -92,7 +122,7 @@ class MovieBase(MovieTypeBase):
if search_after: if search_after:
onComplete = self.createOnComplete(m['_id']) onComplete = self.createOnComplete(m['_id'])
# fireEventAsync('library.update.movie', params.get('identifier'), default_title = params.get('title', ''), on_complete = onComplete) fireEventAsync('movie.update_info', m['_id'], default_title = params.get('title', ''), on_complete = onComplete)
search_after = False search_after = False
elif force_readd: elif force_readd:
@@ -106,24 +136,24 @@ class MovieBase(MovieTypeBase):
fireEvent('release.delete', release['_id'], single = True) fireEvent('release.delete', release['_id'], single = True)
m['profile_id'] = params.get('profile_id', default_profile.get('id')) m['profile_id'] = params.get('profile_id', default_profile.get('id'))
m['category_id'] = tryInt(cat_id) if cat_id is not None and tryInt(cat_id) > 0 else (m['category_id'] or None) m['category_id'] = tryInt(cat_id) if cat_id is not None and tryInt(cat_id) > 0 else (m.get('category_id') or None)
else: else:
log.debug('Movie already exists, not updating: %s', params) log.debug('Movie already exists, not updating: %s', params)
added = False added = False
if force_readd: if force_readd:
m['status'] = status_id if status_id else 'active'
m['last_edit'] = int(time.time()) m['last_edit'] = int(time.time())
do_search = True do_search = True
db.update(m) if added:
db.update(m)
# Remove releases # Remove releases
for rel in db.run('release', 'for_media', m['_id']): for rel in db.run('release', 'for_media', m['_id']):
if rel['status'] is 'available': if rel['status'] is 'available':
db.delete(rel) db.delete(rel)
movie_dict = db.run('movie', 'to_dict', m['_id']) movie_dict = db.run('media', 'to_dict', m['_id'])
if do_search and search_after: if do_search and search_after:
onComplete = self.createOnComplete(m['_id']) onComplete = self.createOnComplete(m['_id'])
@@ -137,7 +167,7 @@ class MovieBase(MovieTypeBase):
if title: if title:
message = 'Successfully added "%s" to your wanted list.' % title message = 'Successfully added "%s" to your wanted list.' % title
else: else:
message = 'Succesfully added to your wanted list.' message = 'Successfully added to your wanted list.'
fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = message) fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = message)
return movie_dict return movie_dict
@@ -161,7 +191,7 @@ class MovieBase(MovieTypeBase):
for media_id in ids: for media_id in ids:
try: try:
m = db.get('media', media_id) m = db.get('id', media_id)
m['profile_id'] = kwargs.get('profile_id') m['profile_id'] = kwargs.get('profile_id')
cat_id = kwargs.get('category_id') cat_id = kwargs.get('category_id')
@@ -197,3 +227,128 @@ class MovieBase(MovieTypeBase):
return { return {
'success': False, 'success': False,
} }
def updateInfo(self, media_id = None, identifier = None, default_title = None, extended = False):
"""
Update movie information inside media['doc']['info']
@param media_id: document id
@param default_title: default title, if empty, use first one or existing one
@param extended: update with extended info (parses more info, actors, images from some info providers)
@return: dict, with media
"""
if self.shuttingDown():
return
try:
db = get_db()
if media_id:
media = db.get('id', media_id)
else:
media = db.get('media', identifier, with_doc = True)['doc']
info = fireEvent('movie.info', merge = True, extended = extended, identifier = media.get('identifier'))
# Don't need those here
try: del info['in_wanted']
except: pass
try: del info['in_library']
except: pass
if not info or len(info) == 0:
log.error('Could not update, no movie info to work with: %s', media.get('identifier'))
return False
# Update basic info
media['info'] = info
titles = info.get('titles', [])
log.debug('Adding titles: %s', titles)
counter = 0
def_title = None
for title in titles:
if (len(default_title) == 0 and counter == 0) or len(titles) == 1 or title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
def_title = toUnicode(title)
break
counter += 1
if not def_title:
def_title = toUnicode(titles[0])
media = {
'title': def_title,
}
# Files
images = info.get('images', [])
media['files'] = media.get('filed', [])
for image_type in ['poster']:
for image in images.get(image_type, []):
if not isinstance(image, (str, unicode)):
continue
file_path = fireEvent('file.download', url = image, single = True)
media['files'].append({
'type': 'image_%s' % image_type,
'path': file_path
})
db.update(media)
return media
except:
log.error('Failed update media: %s', traceback.format_exc())
return {}
def updateReleaseDate(self, media_id):
"""
Update releasedate (eta) info only
@param media_id: document id
@return: dict, with dates dvd, theater, bluray, expires
"""
try:
db = get_db()
media = db.get('id', media_id)
if not media.get('info'):
info_dict = self.updateInfo(media_id)
dates = info_dict.get('info', {}).get('release_date')
else:
dates = media.get('info').get('release_date')
if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates:
dates = fireEvent('movie.info.release_date', identifier = media['identifier'], merge = True)
media['info'].update({'release_date': dates})
db.update(media)
return dates
except:
log.error('Failed updating release dates: %s', traceback.format_exc())
return {}
def simplifyTitle(self, title):
"""
Removes all special chars from a title so it's easier to make sortable
@param title: media title
@return: string, simplified title
"""
title = toUnicode(title)
nr_prefix = '' if title[0] in ascii_letters else '#'
title = simplifyString(title)
for prefix in ['the ']:
if prefix == title[:len(prefix)]:
title = title[len(prefix):]
break
return nr_prefix + title
@@ -191,11 +191,9 @@ MA.Release = new Class({
self.releases.each(function(release){ self.releases.each(function(release){
var status = Status.get(release.status_id), var quality = Quality.getProfile(release.quality_id) || {},
quality = Quality.getProfile(release.quality_id) || {},
info = release.info, info = release.info,
provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : ''); provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : '');
release.status = status;
var release_name = self.get(release, 'name'); var release_name = self.get(release, 'name');
if(release.files && release.files.length > 0){ if(release.files && release.files.length > 0){
@@ -215,7 +213,7 @@ MA.Release = new Class({
'id': 'release_'+release.id 'id': 'release_'+release.id
}).adopt( }).adopt(
new Element('span.name', {'text': release_name, 'title': release_name}), new Element('span.name', {'text': release_name, 'title': release_name}),
new Element('span.status', {'text': status.identifier, 'class': 'release_status '+status.identifier}), new Element('span.status', {'text': status.identifier, 'class': 'release_status '+release.status}),
new Element('span.quality', {'text': quality.get('label') || 'n/a'}), new Element('span.quality', {'text': quality.get('label') || 'n/a'}),
new Element('span.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}), new Element('span.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}),
new Element('span.age', {'text': self.get(release, 'age')}), new Element('span.age', {'text': self.get(release, 'age')}),
@@ -257,22 +255,20 @@ MA.Release = new Class({
if(notification.data.id != release.id) return; if(notification.data.id != release.id) return;
var q = self.movie.quality.getElement('.q_id' + release.quality_id), var q = self.movie.quality.getElement('.q_id' + release.quality_id),
status = Status.get(release.status_id), new_status = notification.data.status;
new_status = Status.get(notification.data.status_id);
release.status_id = new_status.id release.el.set('class', 'item ' + new_status);
release.el.set('class', 'item ' + new_status.identifier);
var status_el = release.el.getElement('.release_status'); var status_el = release.el.getElement('.release_status');
status_el.set('class', 'release_status ' + new_status.identifier); status_el.set('class', 'release_status ' + new_status);
status_el.set('text', new_status.identifier); status_el.set('text', new_status.identifier);
if(!q && (new_status.identifier == 'snatched' || new_status.identifier == 'seeding' || new_status.identifier == 'done')) if(!q && (new_status == 'snatched' || new_status == 'seeding' || new_status == 'done'))
var q = self.addQuality(release.quality_id); var q = self.addQuality(release.quality_id);
if(new_status && q && !q.hasClass(new_status.identifier)) { if(q && !q.hasClass(new_status)) {
q.removeClass(status.identifier).addClass(new_status.identifier); q.removeClass(release.status).addClass(new_status);
q.set('title', q.get('title').replace(status.label, new_status.label)); q.set('title', q.get('title').replace(status, new_status));
} }
} }
@@ -344,12 +340,10 @@ MA.Release = new Class({
self.movie.data.releases.each(function(release){ self.movie.data.releases.each(function(release){
if(has_available && has_snatched) return; if(has_available && has_snatched) return;
var status = Status.get(release.status_id); if(['snatched', 'downloaded', 'seeding'].contains(release.status))
if(['snatched', 'downloaded', 'seeding'].contains(status.identifier))
has_snatched = true; has_snatched = true;
if(['available'].contains(status.identifier)) if(['available'].contains(release.status))
has_available = true; has_available = true;
}); });
@@ -726,10 +720,10 @@ MA.Readd = new Class({
create: function(){ create: function(){
var self = this; var self = this;
var movie_done = Status.get(self.movie.data.status_id).identifier == 'done'; var movie_done = self.movie.data.status == 'done';
if(!movie_done) if(!movie_done)
var snatched = self.movie.data.releases.filter(function(release){ var snatched = self.movie.data.releases.filter(function(release){
return release.status && (release.status.identifier == 'snatched' || release.status.identifier == 'downloaded' || release.status.identifier == 'done'); return release.status && (release.status == 'snatched' || release.status == 'downloaded' || release.status == 'done');
}).length; }).length;
if(movie_done || snatched && snatched > 0) if(movie_done || snatched && snatched > 0)
@@ -924,4 +918,4 @@ MA.Files = new Class({
self.movie.slide('in', self.options_container); self.movie.slide('in', self.options_container);
}, },
}); });
@@ -59,7 +59,7 @@ var Movie = new Class({
if(!self.data.releases) if(!self.data.releases)
self.data.releases = []; self.data.releases = [];
self.data.releases.push({'quality_id': data.quality_id, 'status_id': data.status_id}); self.data.releases.push({'quality_id': data.quality_id, 'status': data.status});
self.updateReleases(); self.updateReleases();
} }
} }
@@ -146,8 +146,7 @@ var Movie = new Class({
create: function(){ create: function(){
var self = this; var self = this;
var s = Status.get(self.get('status_id')); self.el.addClass('status_'+self.get('status'));
self.el.addClass('status_'+s.identifier);
self.el.adopt( self.el.adopt(
self.select_checkbox = new Element('input[type=checkbox].inlay', { self.select_checkbox = new Element('input[type=checkbox].inlay', {
@@ -157,7 +156,7 @@ var Movie = new Class({
} }
} }
}), }),
self.thumbnail = File.Select.single('poster', self.data.library.files), self.thumbnail = File.Select.single('poster', self.data.files || []),
self.data_container = new Element('div.data.inlay.light').adopt( self.data_container = new Element('div.data.inlay.light').adopt(
self.info_container = new Element('div.info').adopt( self.info_container = new Element('div.info').adopt(
new Element('div.title').adopt( new Element('div.title').adopt(
@@ -165,11 +164,11 @@ var Movie = new Class({
'text': self.getTitle() || 'n/a' 'text': self.getTitle() || 'n/a'
}), }),
self.year = new Element('div.year', { self.year = new Element('div.year', {
'text': self.data.library.year || 'n/a' 'text': self.data.info.year || 'n/a'
}) })
), ),
self.description = new Element('div.description', { self.description = new Element('div.description', {
'text': self.data.library.plot 'text': self.data.info.plot
}), }),
self.quality = new Element('div.quality', { self.quality = new Element('div.quality', {
'events': { 'events': {
@@ -221,14 +220,14 @@ var Movie = new Class({
self.data.releases.each(function(release){ self.data.releases.each(function(release){
var q = self.quality.getElement('.q_id'+ release.quality_id), var q = self.quality.getElement('.q_id'+ release.quality_id),
status = Status.get(release.status_id); status = release.status;
if(!q && (status.identifier == 'snatched' || status.identifier == 'seeding' || status.identifier == 'done')) if(!q && (status == 'snatched' || status == 'seeding' || status == 'done'))
var q = self.addQuality(release.quality_id) var q = self.addQuality(release.quality_id)
if (status && q && !q.hasClass(status.identifier)){ if (q && !q.hasClass(status)){
q.addClass(status.identifier); q.addClass(status);
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status.label) q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status)
} }
}); });
@@ -249,16 +248,10 @@ var Movie = new Class({
getTitle: function(){ getTitle: function(){
var self = this; var self = this;
var titles = self.data.library.titles; if(self.data.title)
return self.getUnprefixedTitle(self.data.title)
var title = titles.filter(function(title){ else if(self.data.info.titles.length > 0)
return title['default'] return self.getUnprefixedTitle(self.data.info.titles[0])
}).pop()
if(title)
return self.getUnprefixedTitle(title.title)
else if(titles.length > 0)
return self.getUnprefixedTitle(titles[0].title)
return 'Unknown movie' return 'Unknown movie'
}, },
@@ -313,7 +306,7 @@ var Movie = new Class({
}, },
get: function(attr){ get: function(attr){
return this.data[attr] || this.data.library[attr] return this.data[attr] || this.data.info[attr]
}, },
select: function(bool){ select: function(bool){
@@ -197,8 +197,8 @@ Block.Search.MovieItem = new Class({
profiles.each(function(profile){ profiles.each(function(profile){
new Element('option', { new Element('option', {
'value': profile.id ? profile.id : profile.data.id, 'value': profile.get('_id'),
'text': profile.label ? profile.label : profile.data.label 'text': profile.get('label')
}).inject(self.profile_select) }).inject(self.profile_select)
}); });
@@ -1,7 +0,0 @@
from .main import MovieLibraryPlugin
def start():
return MovieLibraryPlugin()
config = []
@@ -1,193 +0,0 @@
from couchpotato import get_session
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
from couchpotato.core.helpers.encoding import toUnicode, simplifyString
from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.library import LibraryBase
from couchpotato.core.settings.model import Library, LibraryTitle, File
from string import ascii_letters
import time
import traceback
import six
log = CPLog(__name__)
class MovieLibraryPlugin(LibraryBase):
default_dict = {'titles': {}, 'files': {}}
def __init__(self):
addEvent('library.add.movie', self.add)
addEvent('library.update.movie', self.update)
addEvent('library.update.movie.release_date', self.updateReleaseDate)
def add(self, attrs = None, update_after = True):
if not attrs: attrs = {}
primary_provider = attrs.get('primary_provider', 'imdb')
try:
db = get_session()
l = db.query(Library).filter_by(identifier = attrs.get('identifier')).first()
if not l:
status = fireEvent('status.get', 'needs_update', single = True)
l = Library(
year = attrs.get('year'),
identifier = attrs.get('identifier'),
plot = toUnicode(attrs.get('plot')),
tagline = toUnicode(attrs.get('tagline')),
status_id = status.get('id'),
info = {}
)
title = LibraryTitle(
title = toUnicode(attrs.get('title')),
simple_title = self.simplifyTitle(attrs.get('title')),
)
l.titles.append(title)
db.add(l)
db.commit()
# Update library info
if update_after is not False:
handle = fireEventAsync if update_after is 'async' else fireEvent
handle('library.update.movie', identifier = l.identifier, default_title = toUnicode(attrs.get('title', '')))
library_dict = l.to_dict(self.default_dict)
return library_dict
except:
log.error('Failed adding media: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return {}
def update(self, identifier, default_title = '', extended = False):
if self.shuttingDown():
return
try:
db = get_session()
library = db.query(Library).filter_by(identifier = identifier).first()
done_status = fireEvent('status.get', 'done', single = True)
info = fireEvent('movie.info', merge = True, extended = extended, identifier = identifier)
# Don't need those here
try: del info['in_wanted']
except: pass
try: del info['in_library']
except: pass
if not info or len(info) == 0:
log.error('Could not update, no movie info to work with: %s', identifier)
return False
# Main info
library.plot = toUnicode(info.get('plot', ''))
library.tagline = toUnicode(info.get('tagline', ''))
library.year = info.get('year', 0)
library.status_id = done_status.get('id')
library.info.update(info)
db.commit()
# Titles
[db.delete(title) for title in library.titles]
db.commit()
titles = info.get('titles', [])
log.debug('Adding titles: %s', titles)
counter = 0
def_title = None
for title in titles:
if (len(default_title) == 0 and counter == 0) or len(titles) == 1 or title.lower() == toUnicode(default_title.lower()) or (toUnicode(default_title) == six.u('') and toUnicode(titles[0]) == title):
def_title = toUnicode(title)
break
counter += 1
if not def_title:
def_title = toUnicode(titles[0])
for title in titles:
if not title:
continue
title = toUnicode(title)
t = LibraryTitle(
title = title,
simple_title = self.simplifyTitle(title),
default = title == def_title
)
library.titles.append(t)
db.commit()
# Files
images = info.get('images', [])
library['files'] = []
for image_type in ['poster']:
for image in images.get(image_type, []):
if not isinstance(image, (str, unicode)):
continue
file_path = fireEvent('file.download', url = image, single = True)
# TODO: save in movie doc
library['files'].append({
'type': 'image_%s' % image_type,
'path': file_path
})
library_dict = library.to_dict(self.default_dict)
return library_dict
except:
log.error('Failed update media: %s', traceback.format_exc())
return {}
def updateReleaseDate(self, identifier):
try:
db = get_session()
library = db.query(Library).filter_by(identifier = identifier).first()
if not library.info:
library_dict = self.update(identifier)
dates = library_dict.get('info', {}).get('release_date')
else:
dates = library.info.get('release_date')
if dates and (dates.get('expires', 0) < time.time() or dates.get('expires', 0) > time.time() + (604800 * 4)) or not dates:
dates = fireEvent('movie.release_date', identifier = identifier, merge = True)
library.info.update({'release_date': dates})
db.commit()
return dates
except:
log.error('Failed updating release dates: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return {}
def simplifyTitle(self, title):
title = toUnicode(title)
nr_prefix = '' if title[0] in ascii_letters else '#'
title = simplifyString(title)
for prefix in ['the ']:
if prefix == title[:len(prefix)]:
title = title[len(prefix):]
break
return nr_prefix + title
+34 -28
View File
@@ -1,4 +1,4 @@
from couchpotato import get_session, get_db from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.helpers.encoding import simplifyString from couchpotato.core.helpers.encoding import simplifyString
@@ -6,7 +6,6 @@ from couchpotato.core.helpers.variable import getTitle, possibleTitles, getImdb
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media._base.searcher.base import SearcherBase from couchpotato.core.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie import MovieTypeBase from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Media, Release
from couchpotato.environment import Env from couchpotato.environment import Env
from datetime import date from datetime import date
import random import random
@@ -51,7 +50,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
}) })
if self.conf('run_on_launch'): if self.conf('run_on_launch'):
addEvent('app.load2', self.searchAll) addEvent('app.load', self.searchAll)
def searchAllView(self, **kwargs): def searchAllView(self, **kwargs):
@@ -94,7 +93,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
self.single(movie_dict, search_protocols) self.single(movie_dict, search_protocols)
except IndexError: except IndexError:
log.error('Forcing library update for %s, if you see this often, please report: %s', (movie['identifier'], traceback.format_exc())) log.error('Forcing library update for %s, if you see this often, please report: %s', (movie['identifier'], traceback.format_exc()))
fireEvent('library.update.movie', movie['identifier']) fireEvent('movie.update_info', movie['_id'])
except: except:
log.error('Search failed for %s: %s', (movie['identifier'], traceback.format_exc())) log.error('Search failed for %s: %s', (movie['identifier'], traceback.format_exc()))
@@ -111,10 +110,6 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
def single(self, movie, search_protocols = None, manual = False): def single(self, movie, search_protocols = None, manual = False):
# movies don't contain 'type' yet, so just set to default here
if 'type' not in movie:
movie['type'] = 'movie'
# Find out search type # Find out search type
try: try:
if not search_protocols: if not search_protocols:
@@ -127,7 +122,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return return
pre_releases = fireEvent('quality.pre_releases', single = True) pre_releases = fireEvent('quality.pre_releases', single = True)
release_dates = fireEvent('library.update.movie.release_date', identifier = movie['library']['identifier'], merge = True) release_dates = fireEvent('movie.update_release_date', media_id = movie['_id'], merge = True)
found_releases = [] found_releases = []
too_early_to_search = [] too_early_to_search = []
@@ -142,39 +137,50 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
db = get_db() db = get_db()
profile = db.get('id', movie['profile_id'])
quality_order = fireEvent('quality.order', single = True)
media_releases = db.get_many('release', movie['_id'])
ret = False ret = False
for quality_type in movie['profile']['types']: for q_identifier in profile.get('qualities'):
if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['year']): index = profile['qualities'].index(q_identifier)
too_early_to_search.append(quality_type['quality']['identifier']) quality_custom = {
'quality': q_identifier,
'finish': profile['finish'][index],
'wait_for': profile['wait_for'][index]
}
if not self.conf('always_search') and not self.couldBeReleased(q_identifier in pre_releases, release_dates, movie['info']['year']):
too_early_to_search.append(q_identifier)
continue continue
has_better_quality = 0 has_better_quality = 0
# See if better quality is available # See if better quality is available
for release in movie['releases']: for release in media_releases:
if release['quality']['order'] <= quality_type['quality']['order'] and release['status'] not in ['available', 'ignored', 'failed']: if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']:
has_better_quality += 1 has_better_quality += 1
# Don't search for quality lower then already available. # Don't search for quality lower then already available.
if has_better_quality is 0: if has_better_quality is 0:
log.info('Search for %s in %s', (default_title, quality_type['quality']['label'])) quality = fireEvent('quality.single', identifier = q_identifier, single = True)
quality = fireEvent('quality.single', identifier = quality_type['quality']['identifier'], single = True) log.info('Search for %s in %s', (default_title, quality['label']))
results = fireEvent('searcher.search', search_protocols, movie, quality, single = True) or [] results = fireEvent('searcher.search', search_protocols, movie, quality, single = True) or []
if len(results) == 0: if len(results) == 0:
log.debug('Nothing found for %s in %s', (default_title, quality_type['quality']['label'])) log.debug('Nothing found for %s in %s', (default_title, quality['label']))
# Check if movie isn't deleted while searching # Check if movie isn't deleted while searching
if not fireEvent('media.get', movie.get('_id'), single = True): if not fireEvent('media.get', movie.get('_id'), single = True):
break break
# Add them to this movie releases list # Add them to this movie releases list
found_releases += fireEvent('release.create_from_search', results, movie, quality_type, single = True) found_releases += fireEvent('release.create_from_search', results, movie, quality, single = True)
# Try find a valid result and download it # Try find a valid result and download it
if fireEvent('release.try_download_result', results, movie, quality_type, manual, single = True): if fireEvent('release.try_download_result', results, movie, quality_custom, manual, single = True):
ret = True ret = True
# Remove releases that aren't found anymore # Remove releases that aren't found anymore
@@ -183,7 +189,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
fireEvent('release.delete', release.get('_id'), single = True) fireEvent('release.delete', release.get('_id'), single = True)
else: else:
log.info('Better quality (%s) already available or snatched for %s', (quality_type['quality']['label'], default_title)) log.info('Better quality (%s) already available or snatched for %s', (quality['label'], default_title))
fireEvent('media.restatus', movie['_id']) fireEvent('media.restatus', movie['_id'])
break break
@@ -219,7 +225,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
preferred_quality = fireEvent('quality.single', identifier = quality['identifier'], single = True) preferred_quality = fireEvent('quality.single', identifier = quality['identifier'], single = True)
# Contains lower quality string # Contains lower quality string
if fireEvent('searcher.contains_other_quality', nzb, movie_year = media['library']['year'], preferred_quality = preferred_quality, single = True): if fireEvent('searcher.contains_other_quality', nzb, movie_year = media['info']['year'], preferred_quality = preferred_quality, single = True):
log.info2('Wrong: %s, looking for %s', (nzb['name'], quality['label'])) log.info2('Wrong: %s, looking for %s', (nzb['name'], quality['label']))
return False return False
@@ -249,23 +255,23 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return True return True
# Check if nzb contains imdb link # Check if nzb contains imdb link
if getImdb(nzb.get('description', '')) == media['library']['identifier']: if getImdb(nzb.get('description', '')) == media['identifier']:
return True return True
for raw_title in media['library']['titles']: for raw_title in media['info']['titles']:
for movie_title in possibleTitles(raw_title['title']): for movie_title in possibleTitles(raw_title):
movie_words = re.split('\W+', simplifyString(movie_title)) movie_words = re.split('\W+', simplifyString(movie_title))
if fireEvent('searcher.correct_name', nzb['name'], movie_title, single = True): if fireEvent('searcher.correct_name', nzb['name'], movie_title, single = True):
# if no IMDB link, at least check year range 1 # if no IMDB link, at least check year range 1
if len(movie_words) > 2 and fireEvent('searcher.correct_year', nzb['name'], media['library']['year'], 1, single = True): if len(movie_words) > 2 and fireEvent('searcher.correct_year', nzb['name'], media['info']['year'], 1, single = True):
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 fireEvent('searcher.correct_year', nzb['name'], media['library']['year'], 0, single = True): if len(movie_words) <= 2 and fireEvent('searcher.correct_year', nzb['name'], media['info']['year'], 0, single = True):
return True return True
log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'", (nzb['name'], media_title, media['library']['year'])) log.info("Wrong: %s, undetermined naming. Looking for '%s (%s)'", (nzb['name'], media_title, media['info']['year']))
return False return False
def couldBeReleased(self, is_pre_release, dates, year = None): def couldBeReleased(self, is_pre_release, dates, year = None):
@@ -337,7 +343,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
def getSearchTitle(self, media): def getSearchTitle(self, media):
if media['type'] == 'movie': if media['type'] == 'movie':
return getTitle(media['library']) return getTitle(media)
class SearchSetupError(Exception): class SearchSetupError(Exception):
pass pass
@@ -89,8 +89,6 @@ class Suggestion(Plugin):
# Get new results and add them # Get new results and add them
if len(new_suggestions) - 1 < limit: if len(new_suggestions) - 1 < limit:
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
db = get_session() db = get_session()
active_movies = db.query(Media) \ active_movies = db.query(Media) \
.join(Library) \ .join(Library) \
+2 -2
View File
@@ -15,7 +15,7 @@ import time"""
return key return key
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'notification': if data.get('_t') == 'notification':
added = data.get('added', time.time()) added = data.get('added', time.time())
data['added'] = added data['added'] = added
@@ -35,7 +35,7 @@ import time"""
return key return key
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'notification' and not data.get('read'): if data.get('_t') == 'notification' and not data.get('read'):
added = data.get('added', time.time()) added = data.get('added', time.time())
data['added'] = added data['added'] = added
+3 -3
View File
@@ -57,8 +57,8 @@ class CoreNotifier(Notification):
fireEvent('schedule.interval', 'core.check_messages', self.checkMessages, hours = 12, single = True) fireEvent('schedule.interval', 'core.check_messages', self.checkMessages, hours = 12, single = True)
fireEvent('schedule.interval', 'core.clean_messages', self.cleanMessages, seconds = 15, single = True) fireEvent('schedule.interval', 'core.clean_messages', self.cleanMessages, seconds = 15, single = True)
addEvent('app.load2', self.clean) addEvent('app.load', self.clean)
addEvent('app.load2', self.checkMessages) addEvent('app.load', self.checkMessages)
addEvent('database.setup', self.databaseSetup) addEvent('database.setup', self.databaseSetup)
@@ -161,7 +161,7 @@ class CoreNotifier(Notification):
data['notification_type'] = listener if listener else 'unknown' data['notification_type'] = listener if listener else 'unknown'
n = { n = {
'type': 'notification', '_t': 'notification',
'time': int(time.time()), 'time': int(time.time()),
'message': toUnicode(message), 'message': toUnicode(message),
'data': data 'data': data
+1 -1
View File
@@ -16,7 +16,7 @@ class Growl(Notification):
super(Growl, self).__init__() super(Growl, self).__init__()
if self.isEnabled(): if self.isEnabled():
addEvent('app.load2', self.register) addEvent('app.load', self.register)
def register(self): def register(self):
if self.registered: return if self.registered: return
@@ -23,16 +23,16 @@ class Pushover(Notification):
'priority': self.conf('priority'), 'priority': self.conf('priority'),
} }
if data and data.get('library'): if data and data.get('identifier'):
api_data.update({ api_data.update({
'url': toUnicode('http://www.imdb.com/title/%s/' % data['library']['identifier']), 'url': toUnicode('http://www.imdb.com/title/%s/' % data['identifier']),
'url_title': toUnicode('%s on IMDb' % getTitle(data['library'])), 'url_title': toUnicode('%s on IMDb' % getTitle(data)),
}) })
http_handler.request('POST', http_handler.request('POST',
"/1/messages.json", "/1/messages.json",
headers = {'Content-type': 'application/x-www-form-urlencoded'}, headers = {'Content-type': 'application/x-www-form-urlencoded'},
body = tryUrlencode(api_data) body = tryUrlencode(api_data)
) )
response = http_handler.getresponse() response = http_handler.getresponse()
+4 -3
View File
@@ -1,3 +1,4 @@
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification from couchpotato.core.notifications.base import Notification
@@ -21,9 +22,9 @@ class Trakt(Notification):
'username': self.conf('automation_username'), 'username': self.conf('automation_username'),
'password' : self.conf('automation_password'), 'password' : self.conf('automation_password'),
'movies': [{ 'movies': [{
'imdb_id': data['library']['identifier'], 'imdb_id': data['identifier'],
'title': data['library']['titles'][0]['title'], 'title': getTitle(data),
'year': data['library']['year'] 'year': data['info']['year']
}] if data else [] }] if data else []
} }
+2 -2
View File
@@ -1,4 +1,4 @@
from couchpotato.core.helpers.variable import splitString from couchpotato.core.helpers.variable import splitString, getTitle
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification from couchpotato.core.notifications.base import Notification
import base64 import base64
@@ -131,7 +131,7 @@ class XBMC(Notification):
server = 'http://%s/xbmcCmds/' % host server = 'http://%s/xbmcCmds/' % host
# Notification(title, message [, timeout , image]) # Notification(title, message [, timeout , image])
cmd = "xbmcHttp?command=ExecBuiltIn(Notification(%s,%s,'',%s))" % (urllib.quote(data['title']), urllib.quote(data['message']), urllib.quote(self.getNotificationImage('medium'))) cmd = "xbmcHttp?command=ExecBuiltIn(Notification(%s,%s,'',%s))" % (urllib.quote(getTitle(data)), urllib.quote(data['message']), urllib.quote(self.getNotificationImage('medium')))
server += cmd server += cmd
# I have no idea what to set to, just tried text/plain and seems to be working :) # I have no idea what to set to, just tried text/plain and seems to be working :)
+2 -2
View File
@@ -10,10 +10,10 @@ class Automation(Plugin):
def __init__(self): def __init__(self):
addEvent('app.load2', self.setCrons) addEvent('app.load', self.setCrons)
if not Env.get('dev'): if not Env.get('dev'):
addEvent('app.load2', self.addMovies) addEvent('app.load', self.addMovies)
addEvent('setting.save.automation.hour.after', self.setCrons) addEvent('setting.save.automation.hour.after', self.setCrons)
+1 -1
View File
@@ -291,7 +291,7 @@ class Plugin(object):
def cpTag(self, media): def cpTag(self, media):
if Env.setting('enabled', 'renamer'): if Env.setting('enabled', 'renamer'):
return '.cp(' + media['library'].get('identifier') + ')' if media['library'].get('identifier') else '' return '.cp(' + media.get('identifier') + ')' if media.get('identifier') else ''
return '' return ''
+4 -4
View File
@@ -5,12 +5,12 @@ from CodernityDB.tree_index import TreeBasedIndex
class CategoryIndex(TreeBasedIndex): class CategoryIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = '32s'
super(CategoryIndex, self).__init__(*args, **kwargs) super(CategoryIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return md5(key).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'category': if data.get('_t') == 'category':
return md5(data['media_id']).digest(), None return md5(data['media_id']).hexdigest(), None
+1 -1
View File
@@ -10,7 +10,7 @@ log = CPLog(__name__)
class Custom(Plugin): class Custom(Plugin):
def __init__(self): def __init__(self):
addEvent('app.load2', self.createStructure) addEvent('app.load', self.createStructure)
def createStructure(self): def createStructure(self):
@@ -49,7 +49,6 @@ class Dashboard(Plugin):
limit = tryInt(splt[0]) limit = tryInt(splt[0])
# Get all active movies # Get all active movies
active_status, ignored_status = fireEvent('status.get', ['active', 'ignored'], single = True)
q = db.query(Media) \ q = db.query(Media) \
.join(Library) \ .join(Library) \
.outerjoin(Media.releases) \ .outerjoin(Media.releases) \
+1 -2
View File
@@ -5,8 +5,7 @@ from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import md5, getExt from couchpotato.core.helpers.variable import md5, 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.plugins.scanner.main import Scanner from couchpotato.core.settings.model import File
from couchpotato.core.settings.model import FileType, File
from couchpotato.environment import Env from couchpotato.environment import Env
from tornado.web import StaticFileHandler from tornado.web import StaticFileHandler
import os.path import os.path
+7 -7
View File
@@ -47,7 +47,7 @@ class Manage(Plugin):
}) })
if not Env.get('dev') and self.conf('startup_scan'): if not Env.get('dev') and self.conf('startup_scan'):
addEvent('app.load2', self.updateLibraryQuick) addEvent('app.load', self.updateLibraryQuick)
def getProgress(self, **kwargs): def getProgress(self, **kwargs):
return { return {
@@ -120,7 +120,7 @@ class Manage(Plugin):
total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True) total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True)
for done_movie in done_movies: for done_movie in done_movies:
if done_movie['library']['identifier'] not in added_identifiers: if done_movie['identifier'] not in added_identifiers:
fireEvent('media.delete', media_id = done_movie['id'], delete_from = 'all') fireEvent('media.delete', media_id = done_movie['id'], delete_from = 'all')
else: else:
@@ -184,13 +184,13 @@ class Manage(Plugin):
'to_go': total_found, 'to_go': total_found,
}) })
if group['library'] and group['library'].get('identifier'): if group['media'] and group['media'].get('identifier'):
identifier = group['library'].get('identifier') identifier = group['media'].get('identifier')
added_identifiers.append(identifier) added_identifiers.append(identifier)
# Add it to release and update the info # Add it to release and update the info
fireEvent('release.add', group = group) fireEvent('release.add', group = group)
fireEvent('library.update.movie', identifier = identifier, on_complete = self.createAfterUpdate(folder, identifier)) fireEvent('movie.update_info', identifier = identifier, on_complete = self.createAfterUpdate(folder, identifier))
else: else:
self.updateProgress(folder) self.updateProgress(folder)
@@ -207,7 +207,7 @@ class Manage(Plugin):
total = self.in_progress[folder]['total'] total = self.in_progress[folder]['total']
movie_dict = fireEvent('media.get', identifier, single = True) movie_dict = fireEvent('media.get', identifier, single = True)
fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = None if total > 5 else 'Added "%s" to manage.' % getTitle(movie_dict['library'])) fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = None if total > 5 else 'Added "%s" to manage.' % getTitle(movie_dict))
return afterUpdate return afterUpdate
@@ -237,7 +237,7 @@ class Manage(Plugin):
if groups: if groups:
for group in groups.values(): for group in groups.values():
if group['library'] and group['library'].get('identifier'): if group.get('info'):
fireEvent('release.add', group = group) fireEvent('release.add', group = group)
def getDiskSpace(self): def getDiskSpace(self):
+1 -1
View File
@@ -12,6 +12,6 @@ class NameIndex(TreeBasedIndex):
return key return key
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'media' and data.get('title') is not None: if data.get('_t') == 'media' and data.get('title') is not None:
return data.get('title'), None return data.get('title'), None
+3 -3
View File
@@ -2,7 +2,6 @@ import time
from couchpotato import CPLog, get_db from couchpotato import CPLog, get_db
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.plugins.base import Plugin from couchpotato.core.plugins.base import Plugin
from .index import ReleaseIndex, NameIndex
log = CPLog(__name__) log = CPLog(__name__)
@@ -13,7 +12,7 @@ class NoSQL(Plugin):
def __init__(self): def __init__(self):
pass #addEvent('app.load2', self.test) pass #addEvent('app.load', self.test)
def test(self): def test(self):
@@ -31,7 +30,8 @@ class NoSQL(Plugin):
for id in range(10): for id in range(10):
media = db.insert({ media = db.insert({
'type': 'media', '_t': 'media',
'type': 'movie',
'tmdb': id, 'tmdb': id,
'imdb': 'tt%s' % id, 'imdb': 'tt%s' % id,
'last_edit': 0, 'last_edit': 0,
+6 -7
View File
@@ -1,16 +1,15 @@
from CodernityDB.hash_index import HashIndex from CodernityDB.tree_index import TreeBasedIndex
from hashlib import md5
class ProfileIndex(HashIndex): class ProfileIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = 'i'
super(ProfileIndex, self).__init__(*args, **kwargs) super(ProfileIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return key
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'profile' and data.get('identifier'): if data.get('_t') == 'profile':
return md5(data.get('identifier')).digest(), None return data.get('order', 99), None
+7 -13
View File
@@ -1,13 +1,12 @@
import traceback import traceback
from couchpotato import get_session, get_db from couchpotato import get_session, get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
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 .index import ProfileIndex from .index import ProfileIndex
from couchpotato.core.settings.model import Profile, ProfileType, Media from couchpotato.core.settings.model import Profile, ProfileType
from sqlalchemy.orm import joinedload_all
log = CPLog(__name__) log = CPLog(__name__)
@@ -34,7 +33,7 @@ class ProfilePlugin(Plugin):
addEvent('database.setup', self.databaseSetup) addEvent('database.setup', self.databaseSetup)
addEvent('app.initialize', self.fill, priority = 90) addEvent('app.initialize', self.fill, priority = 90)
addEvent('app.load2', self.forceDefaults) addEvent('app.load', self.forceDefaults)
def databaseSetup(self): def databaseSetup(self):
@@ -46,7 +45,6 @@ class ProfilePlugin(Plugin):
log.debug('Index already exists') log.debug('Index already exists')
db.edit_index(ProfileIndex(db.path, 'profile')) db.edit_index(ProfileIndex(db.path, 'profile'))
def forceDefaults(self): def forceDefaults(self):
# Get all active movies without profile # Get all active movies without profile
@@ -57,7 +55,7 @@ class ProfilePlugin(Plugin):
profile_ids = [x.get('_id') for x in self.all()] profile_ids = [x.get('_id') for x in self.all()]
for media in medias: for media in medias:
if media['profile_id'] not in profile_ids: if media.get('profile_id') not in profile_ids:
default_profile = self.default() default_profile = self.default()
media['profile_id'] = default_profile.get('id') media['profile_id'] = default_profile.get('id')
db.update(media) db.update(media)
@@ -76,7 +74,7 @@ class ProfilePlugin(Plugin):
db = get_db() db = get_db()
profiles = db.all('profile', with_doc = True) profiles = db.all('profile', with_doc = True)
return list(profiles) return [x['doc'] for x in profiles]
def save(self, **kwargs): def save(self, **kwargs):
@@ -127,7 +125,7 @@ class ProfilePlugin(Plugin):
def default(self): def default(self):
db = get_db() db = get_db()
return db.get_many('profile', limit = 1, with_doc = True)[0] return list(db.all('profile', limit = 1, with_doc = True))[0]['doc']
def saveOrder(self, **kwargs): def saveOrder(self, **kwargs):
@@ -213,8 +211,7 @@ class ProfilePlugin(Plugin):
log.info('Creating default profile: %s', profile.get('label')) log.info('Creating default profile: %s', profile.get('label'))
pro = { pro = {
'type': 'profile', '_t': 'profile',
'identifier': profile.get('label').lower(),
'label': toUnicode(profile.get('label')), 'label': toUnicode(profile.get('label')),
'order': order, 'order': order,
'qualities': profile.get('qualities'), 'qualities': profile.get('qualities'),
@@ -229,9 +226,6 @@ class ProfilePlugin(Plugin):
db.insert(pro) db.insert(pro)
order += 1 order += 1
for x in db.all('profile', with_doc = True):
log.info(x)
return True return True
except: except:
log.error('Failed: %s', traceback.format_exc()) log.error('Failed: %s', traceback.format_exc())
@@ -324,4 +324,4 @@ Profile.Type = new Class({
return this.el; return this.el;
} }
}) })
+16
View File
@@ -0,0 +1,16 @@
from CodernityDB.hash_index import HashIndex
from hashlib import md5
class QualityIndex(HashIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '32s'
super(QualityIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('_t') == 'quality' and data.get('identifier'):
return md5(data.get('identifier')).hexdigest(), None
+51 -55
View File
@@ -1,15 +1,14 @@
import traceback import traceback
from couchpotato import get_session from couchpotato import get_session, get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import addEvent from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import toUnicode, ss from couchpotato.core.helpers.encoding import toUnicode, ss
from couchpotato.core.helpers.variable import mergeDicts, getExt from couchpotato.core.helpers.variable import mergeDicts, 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 Quality, Profile, ProfileType from couchpotato.core.plugins.quality.index import QualityIndex
from sqlalchemy.sql.expression import or_ from couchpotato.core.settings.model import Quality
import re import re
import time
log = CPLog(__name__) log = CPLog(__name__)
@@ -39,6 +38,7 @@ class QualityPlugin(Plugin):
addEvent('quality.single', self.single) addEvent('quality.single', self.single)
addEvent('quality.guess', self.guess) addEvent('quality.guess', self.guess)
addEvent('quality.pre_releases', self.preReleases) addEvent('quality.pre_releases', self.preReleases)
addEvent('quality.order', self.getOrder)
addApiView('quality.size.save', self.saveSize) addApiView('quality.size.save', self.saveSize)
addApiView('quality.list', self.allView, docs = { addApiView('quality.list', self.allView, docs = {
@@ -50,9 +50,31 @@ class QualityPlugin(Plugin):
}) })
addEvent('app.initialize', self.fill, priority = 10) addEvent('app.initialize', self.fill, priority = 10)
addEvent('database.setup', self.databaseSetup)
addEvent('app.test', self.doTest) addEvent('app.test', self.doTest)
self.addOrder()
def addOrder(self):
self.order = []
for q in self.qualities:
self.order.append(q.get('identifier'))
def getOrder(self):
return self.order
def databaseSetup(self):
db = get_db()
# Quality index
try:
db.add_index(QualityIndex(db.path, 'quality'))
except:
log.debug('Index already exists')
db.edit_index(QualityIndex(db.path, 'quality'))
def preReleases(self): def preReleases(self):
return self.pre_releases return self.pre_releases
@@ -68,30 +90,29 @@ class QualityPlugin(Plugin):
if self.cached_qualities: if self.cached_qualities:
return self.cached_qualities return self.cached_qualities
db = get_session() db = get_db()
qualities = db.query(Quality).all() qualities = db.all('quality', with_doc = True)
temp = [] temp = []
for quality in qualities: for quality in qualities:
q = mergeDicts(self.getQuality(quality.identifier), quality.to_dict()) quality = quality['doc']
q = mergeDicts(self.getQuality(quality.get('identifier')), quality)
temp.append(q) temp.append(q)
self.cached_qualities = temp self.cached_qualities = temp
pass #db.close()
return temp return temp
def single(self, identifier = ''): def single(self, identifier = ''):
db = get_session() db = get_db()
quality_dict = {} quality_dict = {}
quality = db.query(Quality).filter(or_(Quality.identifier == identifier, Quality.id == identifier)).first() quality = db.get('quality', identifier, with_doc = True)['doc']
if quality: if quality:
quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict()) quality_dict = mergeDicts(self.getQuality(quality['identifier']), quality)
pass #db.close()
return quality_dict return quality_dict
def getQuality(self, identifier): def getQuality(self, identifier):
@@ -128,60 +149,35 @@ class QualityPlugin(Plugin):
def fill(self): def fill(self):
try: try:
db = get_session() db = get_db()
order = 0 order = 0
for q in self.qualities: for q in self.qualities:
# Create quality db.insert({
qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first() '_t': 'quality',
'order': order,
'identifier': q.get('identifier'),
'size_min': q.get('size')[0],
'size_max': q.get('size')[1]
})
if not qual: log.info('Creating profile: %s', q.get('label'))
log.info('Creating quality: %s', q.get('label')) db.insert({
qual = Quality() '_t': 'profile',
qual.order = order 'order': order + 20, # Make sure it goes behind other profiles
qual.identifier = q.get('identifier') 'core': True,
qual.label = toUnicode(q.get('label')) 'qualities': [q.get('identifier')],
qual.size_min, qual.size_max = q.get('size') 'label': toUnicode(q.get('label')),
'finish': [True],
db.add(qual) 'wait_for': [0],
})
# Create single quality profile
prof = db.query(Profile).filter(
Profile.core == True
).filter(
Profile.types.any(quality = qual)
).all()
if not prof:
log.info('Creating profile: %s', q.get('label'))
prof = Profile(
core = True,
label = toUnicode(qual.label),
order = order
)
db.add(prof)
profile_type = ProfileType(
quality = qual,
profile = prof,
finish = True,
order = 0
)
prof.types.append(profile_type)
order += 1 order += 1
db.commit()
time.sleep(0.3) # Wait a moment
return True return True
except: except:
log.error('Failed: %s', traceback.format_exc()) log.error('Failed: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return False return False
+22 -8
View File
@@ -5,15 +5,15 @@ from CodernityDB.tree_index import TreeBasedIndex
class ReleaseIndex(TreeBasedIndex): class ReleaseIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = '32s'
super(ReleaseIndex, self).__init__(*args, **kwargs) super(ReleaseIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return md5(key).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'release' and data.get('media_id'): if data.get('_t') == 'release' and data.get('media_id'):
return md5(data['media_id']).digest(), {'media_id': data.get('media_id')} return md5(data['media_id']).hexdigest(), {'media_id': data.get('media_id')}
def run_for_media(self, db, media_id): def run_for_media(self, db, media_id):
for release in db.get_many('release', media_id, with_doc = True): for release in db.get_many('release', media_id, with_doc = True):
@@ -31,12 +31,26 @@ class ReleaseIndex(TreeBasedIndex):
class ReleaseStatusIndex(TreeBasedIndex): class ReleaseStatusIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = '32s'
super(ReleaseStatusIndex, self).__init__(*args, **kwargs) super(ReleaseStatusIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return md5(key).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'release' and data.get('status'): if data.get('_t') == 'release' and data.get('status'):
return md5(data.get('status')).digest(), None return md5(data.get('status')).hexdigest(), None
class ReleaseIDIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '32s'
super(ReleaseIDIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('_t') == 'release' and data.get('identifier'):
return md5(data.get('identifier')).hexdigest(), None
+41 -54
View File
@@ -5,7 +5,7 @@ from couchpotato.core.helpers.encoding import ss, toUnicode
from couchpotato.core.helpers.variable import getTitle from couchpotato.core.helpers.variable import getTitle
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 .index import ReleaseIndex, ReleaseStatusIndex from .index import ReleaseIndex, ReleaseStatusIndex, ReleaseIDIndex
from couchpotato.core.plugins.scanner.main import Scanner from couchpotato.core.plugins.scanner.main import Scanner
from couchpotato.core.settings.model import Release as Relea, Media, \ from couchpotato.core.settings.model import Release as Relea, Media, \
ReleaseInfo ReleaseInfo
@@ -61,7 +61,7 @@ class Release(Plugin):
addEvent('database.setup', self.databaseSetup) addEvent('database.setup', self.databaseSetup)
# Clean releases that didn't have activity in the last week # Clean releases that didn't have activity in the last week
addEvent('app.load2', self.cleanDone) addEvent('app.load', self.cleanDone)
fireEvent('schedule.interval', 'movie.clean_releases', self.cleanDone, hours = 4) fireEvent('schedule.interval', 'movie.clean_releases', self.cleanDone, hours = 4)
def databaseSetup(self): def databaseSetup(self):
@@ -82,6 +82,13 @@ class Release(Plugin):
log.debug('Index already exists') log.debug('Index already exists')
db.edit_index(ReleaseStatusIndex(db.path, 'release_status')) db.edit_index(ReleaseStatusIndex(db.path, 'release_status'))
# Release identifier index
try:
db.add_index(ReleaseIDIndex(db.path, 'release_identifier'))
except:
log.debug('Index already exists')
db.edit_index(ReleaseIDIndex(db.path, 'release_identifier'))
def cleanDone(self): def cleanDone(self):
log.debug('Removing releases from dashboard') log.debug('Removing releases from dashboard')
@@ -112,7 +119,7 @@ class Release(Plugin):
try: try:
db = get_session() db = get_session()
identifier = '%s.%s.%s' % (group['library']['identifier'], group['meta_data'].get('audio', 'unknown'), group['meta_data']['quality']['identifier']) identifier = '%s.%s.%s' % (group['identifier'], group['meta_data'].get('audio', 'unknown'), group['meta_data']['quality']['identifier'])
# Add movie # Add movie
media = db.query(Media).filter_by(library_id = group['library'].get('id')).first() media = db.query(Media).filter_by(library_id = group['library'].get('id')).first()
@@ -120,7 +127,7 @@ class Release(Plugin):
media = Media( media = Media(
library_id = group['library'].get('id'), library_id = group['library'].get('id'),
profile_id = 0, profile_id = 0,
status_id = done_status.get('id') status = 'done'
) )
db.add(media) db.add(media)
db.commit() db.commit()
@@ -129,7 +136,7 @@ class Release(Plugin):
rel = db.query(Relea).filter( rel = db.query(Relea).filter(
or_( or_(
Relea.identifier == identifier, Relea.identifier == identifier,
and_(Relea.identifier.startswith(group['library']['identifier']), Relea.status_id == snatched_status.get('id')) and_(Relea.identifier.startswith(group['identifier']), Relea.status == 'snatched')
) )
).first() ).first()
if not rel: if not rel:
@@ -137,7 +144,7 @@ class Release(Plugin):
identifier = identifier, identifier = identifier,
movie = media, movie = media,
quality_id = group['meta_data']['quality'].get('id'), quality_id = group['meta_data']['quality'].get('id'),
status_id = done_status.get('id') status = 'done'
) )
db.add(rel) db.add(rel)
db.commit() db.commit()
@@ -246,11 +253,6 @@ class Release(Plugin):
# Get matching provider # Get matching provider
provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True) provider = fireEvent('provider.belongs_to', item['url'], provider = item.get('provider'), single = True)
# Backwards compatibility code
if not item.get('protocol'):
item['protocol'] = item['type']
item['type'] = 'movie'
if item.get('protocol') != 'torrent_magnet': if item.get('protocol') != 'torrent_magnet':
item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download item['download'] = provider.loginDownload if provider.urls.get('login') else provider.download
@@ -271,11 +273,6 @@ class Release(Plugin):
def download(self, data, media, manual = False): def download(self, data, media, manual = False):
# Backwards compatibility code
if not data.get('protocol'):
data['protocol'] = data['type']
data['type'] = 'movie'
# Test to see if any downloaders are enabled for this type # Test to see if any downloaders are enabled for this type
downloader_enabled = fireEvent('download.enabled', manual, data, single = True) downloader_enabled = fireEvent('download.enabled', manual, data, single = True)
if not downloader_enabled: if not downloader_enabled:
@@ -303,8 +300,6 @@ class Release(Plugin):
return False return False
log.debug('Downloader result: %s', download_result) log.debug('Downloader result: %s', download_result)
snatched_status, done_status, downloaded_status, active_status = fireEvent('status.get', ['snatched', 'done', 'downloaded', 'active'], single = True)
try: try:
db = get_session() db = get_session()
rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first() rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first()
@@ -324,7 +319,7 @@ class Release(Plugin):
rls.info.append(rls_info) rls.info.append(rls_info)
db.commit() db.commit()
log_movie = '%s (%s) in %s' % (getTitle(media['library']), media['library']['year'], rls.quality.label) log_movie = '%s (%s) in %s' % (getTitle(media), media['info']['year'], rls.quality.label)
snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie) snatch_message = 'Snatched "%s": %s' % (data.get('name'), log_movie)
log.info(snatch_message) log.info(snatch_message)
fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict()) fireEvent('%s.snatched' % data['type'], message = snatch_message, data = rls.to_dict())
@@ -335,7 +330,7 @@ class Release(Plugin):
# If renamer isn't used, mark media done if finished or release downloaded # If renamer isn't used, mark media done if finished or release downloaded
else: else:
if media['status_id'] == active_status.get('id'): if media['status'] == 'active':
finished = next((True for profile_type in media['profile']['types'] finished = next((True for profile_type in media['profile']['types']
if profile_type['quality_id'] == rls.quality.id and profile_type['finish']), False) if profile_type['quality_id'] == rls.quality.id and profile_type['finish']), False)
if finished: if finished:
@@ -346,7 +341,7 @@ class Release(Plugin):
# Mark media done # Mark media done
mdia = db.query(Media).filter_by(id = media['id']).first() mdia = db.query(Media).filter_by(id = media['id']).first()
mdia.status_id = done_status.get('id') mdia.status = 'done'
mdia.last_edit = int(time.time()) mdia.last_edit = int(time.time())
db.commit() db.commit()
@@ -364,15 +359,14 @@ class Release(Plugin):
return True return True
def tryDownloadResult(self, results, media, quality_type, manual = False): def tryDownloadResult(self, results, media, quality_custom, manual = False):
ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True)
for rel in results: for rel in results:
if not quality_type.get('finish', False) and quality_type.get('wait_for', 0) > 0 and rel.get('age') <= quality_type.get('wait_for', 0): if not quality_custom.get('finish', False) and quality_custom.get('wait_for', 0) > 0 and rel.get('age') <= quality_custom.get('wait_for', 0):
log.info('Ignored, waiting %s days: %s', (quality_type.get('wait_for'), rel['name'])) log.info('Ignored, waiting %s days: %s', (quality_custom.get('wait_for'), rel['name']))
continue continue
if rel['status_id'] in [ignored_status.get('id'), failed_status.get('id')]: if rel['status'] in ['ignored', 'failed']:
log.info('Ignored: %s', rel['name']) log.info('Ignored: %s', rel['name'])
continue continue
@@ -388,12 +382,10 @@ class Release(Plugin):
return False return False
def createFromSearch(self, search_results, media, quality_type): def createFromSearch(self, search_results, media, quality):
available_status = fireEvent('status.get', ['available'], single = True)
try: try:
db = get_session() db = get_db()
found_releases = [] found_releases = []
@@ -402,45 +394,40 @@ class Release(Plugin):
rel_identifier = md5(rel['url']) rel_identifier = md5(rel['url'])
found_releases.append(rel_identifier) found_releases.append(rel_identifier)
rls = db.query(Relea).filter_by(identifier = rel_identifier).first() release = {
if not rls: '_t': 'release',
rls = Relea( 'identifier': rel_identifier,
identifier = rel_identifier, 'media_id': media.get('_id'),
movie_id = media.get('id'), 'quality': quality.get('identifier'),
#media_id = media.get('id'), 'status': 'available',
quality_id = quality_type.get('quality_id'), 'last_edit': int(time.time()),
status_id = available_status.get('id') 'info': {}
) }
db.add(rls)
else:
[db.delete(old_info) for old_info in rls.info]
rls.last_edit = int(time.time())
db.commit() try:
rls = db.get('release_identifier', rel_identifier, with_doc = True)['doc']
except:
rls = db.insert(release)
rls.update(release)
# Update info, but filter out functions
for info in rel: for info in rel:
try: try:
if not isinstance(rel[info], (str, unicode, int, long, float)): if not isinstance(rel[info], (str, unicode, int, long, float)):
continue continue
rls_info = ReleaseInfo( rls['info'][info] = toUnicode(rel[info])
identifier = info,
value = toUnicode(rel[info])
)
rls.info.append(rls_info)
except InterfaceError: except InterfaceError:
log.debug('Couldn\'t add %s to ReleaseInfo: %s', (info, traceback.format_exc())) log.debug('Couldn\'t add %s to ReleaseInfo: %s', (info, traceback.format_exc()))
db.commit() db.update(rls)
rel['status_id'] = rls.status_id # Update release in search_results
rel['status'] = rls.get('status')
return found_releases return found_releases
except: except:
log.error('Failed: %s', traceback.format_exc()) log.error('Failed: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return [] return []
+15 -18
View File
@@ -45,7 +45,7 @@ class Renamer(Plugin):
addEvent('renamer.scan', self.scan) addEvent('renamer.scan', self.scan)
addEvent('renamer.check_snatched', self.checkSnatched) addEvent('renamer.check_snatched', self.checkSnatched)
addEvent('app.load2', self.scan) addEvent('app.load', self.scan)
addEvent('app.load', self.setCrons) addEvent('app.load', self.setCrons)
# Enable / disable interval # Enable / disable interval
@@ -222,23 +222,20 @@ class Renamer(Plugin):
remove_files = [] remove_files = []
remove_releases = [] remove_releases = []
movie_title = getTitle(group['library']) movie_title = getTitle(group)
# Add _UNKNOWN_ if no library item is connected # Add _UNKNOWN_ if no library item is connected
if not group['library'] or not movie_title: if not group.get('info') or not movie_title:
self.tagRelease(group = group, tag = 'unknown') self.tagRelease(group = group, tag = 'unknown')
continue continue
# Rename the files using the library data # Rename the files using the library data
else: else:
group['library'] = fireEvent('library.update.movie', identifier = group['library']['identifier'], single = True) group['media'] = fireEvent('movie.update_info', identifier = group['media']['identifier'], single = True)
if not group['library']: if not group['media']:
log.error('Could not rename, no library item to work with: %s', group_identifier) log.error('Could not rename, no library item to work with: %s', group_identifier)
continue continue
library = group['library'] movie_title = getTitle(group['media'])
library_ent = db.query(Library).filter_by(identifier = group['library']['identifier']).first()
movie_title = getTitle(library)
# Overwrite destination when set in category # Overwrite destination when set in category
destination = to_folder destination = to_folder
@@ -419,19 +416,19 @@ class Renamer(Plugin):
# Add it to the wanted list before we continue # Add it to the wanted list before we continue
if len(library_ent.movies) == 0: if len(library_ent.movies) == 0:
profile = db.query(Profile).filter_by(core = True, label = group['meta_data']['quality']['label']).first() profile = db.query(Profile).filter_by(core = True, label = group['meta_data']['quality']['label']).first()
fireEvent('movie.add', params = {'identifier': group['library']['identifier'], 'profile_id': profile.id}, search_after = False) fireEvent('movie.add', params = {'identifier': group['identifier'], 'profile_id': profile.id}, search_after = False)
db.expire_all() db.expire_all()
library_ent = db.query(Library).filter_by(identifier = group['library']['identifier']).first() library_ent = db.query(Library).filter_by(identifier = group['identifier']).first()
for movie in library_ent.movies: for movie in library_ent.movies:
# Mark movie "done" once it's found the quality with the finish check # Mark movie "done" once it's found the quality with the finish check
try: try:
if movie.status_id == active_status.get('id') and movie.profile: if movie.get('status') == 'active' and movie.get('profile_id'):
for profile_type in movie.profile.types: for profile_type in movie.profile.types:
if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish: if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish:
movie.status_id = done_status.get('id') movie['status'] = 'done'
movie.last_edit = int(time.time()) movie['last_edit'] = int(time.time())
db.commit() db.commit()
except Exception as e: except Exception as e:
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc())) log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
@@ -441,7 +438,7 @@ class Renamer(Plugin):
for release in movie.releases: for release in movie.releases:
# When a release already exists # When a release already exists
if release.status_id is done_status.get('id'): if release.get('status') == 'done':
# This is where CP removes older, lesser quality releases # This is where CP removes older, lesser quality releases
if release.quality.order > group['meta_data']['quality']['order']: if release.quality.order > group['meta_data']['quality']['order']:
@@ -470,7 +467,7 @@ class Renamer(Plugin):
break break
elif release.status_id in [snatched_status.get('id'), seeding_status.get('id')]: elif release.get('status') in ['snatched', 'seeding']:
if release_download and release_download.get('rls_id'): if release_download and release_download.get('rls_id'):
if release_download['rls_id'] == release.id: if release_download['rls_id'] == release.id:
if release_download['status'] == 'completed': if release_download['status'] == 'completed':
@@ -917,7 +914,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
found_release = True found_release = True
break break
else: else:
if release_download['name'] == nzbname or rel['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['library']['identifier']: if release_download['name'] == nzbname or rel['info']['name'] in release_download['name'] or getImdb(release_download['name']) == movie_dict['identifier']:
log.debug('Found release by release name or imdb ID: %s', release_download['name']) log.debug('Found release by release name or imdb ID: %s', release_download['name'])
found_release = True found_release = True
break break
@@ -951,7 +948,7 @@ Remove it if you want it to be renamed (again, or at least let it try again)
elif release_download['status'] == 'seeding': elif release_download['status'] == 'seeding':
#If linking setting is enabled, process release #If linking setting is enabled, process release
if self.conf('file_action') != 'move' and not rel.status_id == 'seeding' and self.statusInfoComplete(release_download): if self.conf('file_action') != 'move' and not rel.get('status') == 'seeding' and self.statusInfoComplete(release_download):
log.info('Download of %s completed! It is now being processed while leaving the original files alone for seeding. Current ratio: %s.', (release_download['name'], release_download['seed_ratio'])) log.info('Download of %s completed! It is now being processed while leaving the original files alone for seeding. Current ratio: %s.', (release_download['name'], release_download['seed_ratio']))
# Remove the downloading tag # Remove the downloading tag
+6 -8
View File
@@ -5,7 +5,7 @@ from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \
splitString splitString
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, Media from couchpotato.core.settings.model import File
from enzyme.exceptions import NoParserError, ParseError from enzyme.exceptions import NoParserError, ParseError
from guessit import guess_movie_info from guessit import guess_movie_info
from subliminal.videos import Video from subliminal.videos import Video
@@ -417,13 +417,11 @@ class Scanner(Plugin):
del group['unsorted_files'] del group['unsorted_files']
# Determine movie # Determine movie
group['library'] = self.determineMovie(group, release_download = release_download) group['media'] = self.determineMedia(group, release_download = release_download)
if not group['library']: if not group['media']:
log.error('Unable to determine movie: %s', group['identifiers']) log.error('Unable to determine media: %s', group['identifiers'])
else: else:
movie = db.query(Media).filter_by(library_id = group['library']['id']).first() group['identifier'] = group['media']['identifier']
group['movie_id'] = None if not movie else movie.id
db.expire_all()
processed_movies[identifier] = group processed_movies[identifier] = group
@@ -554,7 +552,7 @@ class Scanner(Plugin):
return detected_languages return detected_languages
def determineMovie(self, group, release_download = None): def determineMedia(self, group, release_download = None):
# Get imdb id from downloader # Get imdb id from downloader
imdb_id = release_download and release_download.get('imdb_id') imdb_id = release_download and release_download.get('imdb_id')
+6 -6
View File
@@ -24,11 +24,11 @@ class Score(Plugin):
try: preferred_words = removeDuplicate(preferred_words + splitString(movie['category']['preferred'].lower())) try: preferred_words = removeDuplicate(preferred_words + splitString(movie['category']['preferred'].lower()))
except: pass except: pass
score = nameScore(toUnicode(nzb['name']), movie['library']['year'], preferred_words) score = nameScore(toUnicode(nzb['name']), movie['info']['year'], preferred_words)
for movie_title in movie['library']['titles']: for movie_title in movie['info']['titles']:
score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title['title'])) score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title))
score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title['title'])) score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title))
score += sizeScore(nzb['size']) score += sizeScore(nzb['size'])
@@ -44,7 +44,7 @@ class Score(Plugin):
score += providerScore(nzb['provider']) score += providerScore(nzb['provider'])
# Duplicates in name # Duplicates in name
score += duplicateScore(nzb['name'], getTitle(movie['library'])) score += duplicateScore(nzb['name'], getTitle(movie))
# Merge global and category # Merge global and category
ignored_words = splitString(Env.setting('ignored_words', section = 'searcher').lower()) ignored_words = splitString(Env.setting('ignored_words', section = 'searcher').lower())
@@ -52,7 +52,7 @@ class Score(Plugin):
except: pass except: pass
# Partial ignored words # Partial ignored words
score += partialIgnoredScore(nzb['name'], getTitle(movie['library']), ignored_words) score += partialIgnoredScore(nzb['name'], getTitle(movie), ignored_words)
# Ignore single downloads from multipart # Ignore single downloads from multipart
score += halfMultipartScore(nzb['name']) score += halfMultipartScore(nzb['name'])
+1 -2
View File
@@ -25,14 +25,13 @@ class Subtitle(Plugin):
db = get_session() db = get_session()
library = db.query(Library).all() library = db.query(Library).all()
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:
# get releases and their movie files # get releases and their movie files
if release.status_id is done_status.get('id'): if release.get('status') == 'done':
files = [] files = []
for file in release.files.filter(FileType.status.has(identifier = 'movie')).all(): for file in release.files.filter(FileType.status.has(identifier = 'movie')).all():
+1 -1
View File
@@ -18,7 +18,7 @@ class Trailer(Plugin):
trailers = fireEvent('trailer.search', group = group, merge = True) trailers = fireEvent('trailer.search', group = group, merge = True)
if not trailers or trailers == []: if not trailers or trailers == []:
log.info('No trailers found for: %s', getTitle(group['library'])) log.info('No trailers found for: %s', getTitle(group))
return False return False
for trailer in trailers.get(self.conf('quality'), []): for trailer in trailers.get(self.conf('quality'), []):
+1 -1
View File
@@ -199,7 +199,7 @@ class YarrProvider(Provider):
self._search(movie, quality, results) self._search(movie, quality, results)
# Search possible titles # Search possible titles
else: else:
for title in possibleTitles(getTitle(movie['library'])): for title in possibleTitles(getTitle(movie)):
self._searchOnTitle(title, movie, quality, results) self._searchOnTitle(title, movie, quality, results)
return results return results
@@ -1,9 +1,9 @@
from couchpotato import get_session from CodernityDB.database import RecordNotFound
from couchpotato.core.event import addEvent, fireEvent from couchpotato import get_db
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.variable import mergeDicts, randomString from couchpotato.core.helpers.variable import mergeDicts, randomString
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
import copy import copy
import traceback import traceback
@@ -86,25 +86,26 @@ class MovieResultModifier(Plugin):
} }
# Add release info from current library # Add release info from current library
db = get_session() db = get_db()
try: try:
l = db.query(Library).filter_by(identifier = imdb).first()
if l:
# Statuses media = None
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True) try:
media = db.get('media', imdb, with_doc = True)['doc']
except RecordNotFound:
pass
for movie in l.movies: if media:
if movie.status_id == active_status['id']:
temp['in_wanted'] = fireEvent('media.get', movie.id, single = True)
for release in movie.releases: if media.get('status') == 'active':
if release.status_id == done_status['id']: temp['in_wanted'] = media
temp['in_library'] = fireEvent('media.get', movie.id, single = True)
for release in db.get_many('release', media.get('_id'), with_doc = True):
if release.get('status') == 'done':
temp['in_library'] = media
except: except:
log.error('Tried getting more info on searched movies: %s', traceback.format_exc()) log.error('Tried getting more info on searched movies: %s', traceback.format_exc())
pass #db.close()
return temp return temp
def checkLibrary(self, result): def checkLibrary(self, result):
@@ -26,9 +26,11 @@ class CouchPotatoApi(MovieProvider):
def __init__(self): def __init__(self):
addEvent('movie.info', self.getInfo, priority = 1) addEvent('movie.info', self.getInfo, priority = 1)
addEvent('movie.info.release_date', self.getReleaseDate)
addEvent('info.search', self.search, priority = 1) addEvent('info.search', self.search, priority = 1)
addEvent('movie.search', self.search, priority = 1) addEvent('movie.search', self.search, priority = 1)
addEvent('movie.release_date', self.getReleaseDate)
addEvent('movie.suggest', self.getSuggestions) addEvent('movie.suggest', self.getSuggestions)
addEvent('movie.is_movie', self.isMovie) addEvent('movie.is_movie', self.isMovie)
@@ -12,8 +12,6 @@ log = CPLog(__name__)
class TheMovieDb(MovieProvider): class TheMovieDb(MovieProvider):
def __init__(self): def __init__(self):
#addEvent('info.search', self.search, priority = 2)
#addEvent('movie.search', self.search, priority = 2)
addEvent('movie.info', self.getInfo, priority = 2) addEvent('movie.info', self.getInfo, priority = 2)
addEvent('movie.info_by_tmdb', self.getInfo) addEvent('movie.info_by_tmdb', self.getInfo)
+4 -5
View File
@@ -25,8 +25,7 @@ class MetaDataBase(Plugin):
# Update library to get latest info # Update library to get latest info
try: try:
updated_library = fireEvent('library.update.movie', group['library']['identifier'], extended = True, single = True) group['media'] = fireEvent('movie.update_info', group['media']['identifier'], extended = True, single = True)
group['library'] = mergeDicts(group['library'], updated_library)
except: except:
log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc()) log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc())
@@ -34,7 +33,7 @@ class MetaDataBase(Plugin):
meta_name = os.path.basename(root_name) meta_name = os.path.basename(root_name)
root = os.path.dirname(root_name) root = os.path.dirname(root_name)
movie_info = group['library'].get('info') movie_info = group['media'].get('info')
for file_type in ['nfo', 'thumbnail', 'fanart']: for file_type in ['nfo', 'thumbnail', 'fanart']:
try: try:
@@ -96,13 +95,13 @@ class MetaDataBase(Plugin):
break break
# See if it is in current files # See if it is in current files
for cur_file in data['library'].get('files', []): for cur_file in data.get('files', []):
if cur_file.get('type_id') is file_type.get('id') and os.path.isfile(cur_file.get('path')): if cur_file.get('type_id') is file_type.get('id') and os.path.isfile(cur_file.get('path')):
return cur_file.get('path') return cur_file.get('path')
# Download using existing info # Download using existing info
try: try:
images = data['library']['info']['images'][wanted_file_type] images = data['info']['images'][wanted_file_type]
file_path = fireEvent('file.download', url = images[0], single = True) file_path = fireEvent('file.download', url = images[0], single = True)
return file_path return file_path
except: except:
@@ -30,21 +30,21 @@ class XBMC(MetaDataBase):
# return imdb url only # return imdb url only
if self.conf('meta_url_only'): if self.conf('meta_url_only'):
return 'http://www.imdb.com/title/%s/' % toUnicode(data['library']['identifier']) return 'http://www.imdb.com/title/%s/' % toUnicode(data['identifier'])
nfoxml = Element('movie') nfoxml = Element('movie')
# Title # Title
try: try:
el = SubElement(nfoxml, 'title') el = SubElement(nfoxml, 'title')
el.text = toUnicode(getTitle(data['library'])) el.text = toUnicode(getTitle(data))
except: except:
pass pass
# IMDB id # IMDB id
try: try:
el = SubElement(nfoxml, 'id') el = SubElement(nfoxml, 'id')
el.text = toUnicode(data['library']['identifier']) el.text = toUnicode(data['identifier'])
except: except:
pass pass
@@ -23,7 +23,7 @@ class BinSearch(NZBProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
arguments = tryUrlencode({ arguments = tryUrlencode({
'q': movie['library']['identifier'], 'q': movie['identifier'],
'm': 'n', 'm': 'n',
'max': 400, 'max': 400,
'adv_age': Env.setting('retention', 'nzb'), 'adv_age': Env.setting('retention', 'nzb'),
@@ -43,7 +43,7 @@ class Newznab(NZBProvider, RSS):
def _searchOnHost(self, host, movie, quality, results): def _searchOnHost(self, host, movie, quality, results):
arguments = tryUrlencode({ arguments = tryUrlencode({
'imdbid': movie['library']['identifier'].replace('tt', ''), 'imdbid': movie['identifier'].replace('tt', ''),
'apikey': host['api_key'], 'apikey': host['api_key'],
'extended': 1 'extended': 1
}) + ('&%s' % host['custom_tag'] if host.get('custom_tag') else '') }) + ('&%s' % host['custom_tag'] if host.get('custom_tag') else '')
@@ -20,7 +20,7 @@ class NZBClub(NZBProvider, RSS):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s"' % (title, movie['library']['year']) q = '"%s %s"' % (title, movie['info']['year'])
params = tryUrlencode({ params = tryUrlencode({
'q': q, 'q': q,
@@ -23,7 +23,7 @@ class NzbIndex(NZBProvider, RSS):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s" | "%s (%s)"' % (title, movie['library']['year'], title, movie['library']['year']) q = '"%s %s" | "%s (%s)"' % (title, movie['info']['year'], title, movie['info']['year'])
arguments = tryUrlencode({ arguments = tryUrlencode({
'q': q, 'q': q,
'age': Env.setting('retention', 'nzb'), 'age': Env.setting('retention', 'nzb'),
@@ -37,7 +37,7 @@ class OMGWTFNZBs(NZBProvider, RSS):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
q = '%s %s' % (title, movie['library']['year']) q = '%s %s' % (title, movie['info']['year'])
params = tryUrlencode({ params = tryUrlencode({
'search': q, 'search': q,
'catid': ','.join([str(x) for x in self.getCatId(quality['identifier'])]), 'catid': ','.join([str(x) for x in self.getCatId(quality['identifier'])]),
@@ -20,7 +20,7 @@ class AwesomeHD(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
data = self.getHTMLData(self.urls['search'] % (self.conf('passkey'), movie['library']['identifier'], self.conf('only_internal'))) data = self.getHTMLData(self.urls['search'] % (self.conf('passkey'), movie['identifier'], self.conf('only_internal')))
if data: if data:
try: try:
@@ -26,7 +26,7 @@ class BiTHDTV(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
arguments = tryUrlencode({ arguments = tryUrlencode({
'search': '%s %s' % (title.replace(':', ''), movie['library']['year']), 'search': '%s %s' % (title.replace(':', ''), movie['info']['year']),
'cat': self.cat_id_movies 'cat': self.cat_id_movies
}) })
@@ -22,7 +22,7 @@ class Bitsoup(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
q = '"%s" %s' % (simplifyString(title), movie['library']['year']) q = '"%s" %s' % (simplifyString(title), movie['info']['year'])
arguments = tryUrlencode({ arguments = tryUrlencode({
'search': q, 'search': q,
}) })
@@ -43,7 +43,7 @@ class HDBits(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
match = re.match(r'tt(\d{7})', movie['library']['identifier']) match = re.match(r'tt(\d{7})', movie['identifier'])
data = self._post_query(imdb = {'id': match.group(1)}) data = self._post_query(imdb = {'id': match.group(1)})
@@ -38,7 +38,7 @@ class ILoveTorrents(TorrentProvider):
while page < total_pages: while page < total_pages:
movieTitle = tryUrlencode('"%s" %s' % (title, movie['library']['year'])) movieTitle = tryUrlencode('"%s" %s' % (title, movie['info']['year']))
search_url = self.urls['search'] % (movieTitle, page, cats[0]) search_url = self.urls['search'] % (movieTitle, page, cats[0])
page += 1 page += 1
@@ -36,7 +36,7 @@ class IPTorrents(TorrentProvider):
current_page = 1 current_page = 1
while current_page <= pages and not self.shuttingDown(): while current_page <= pages and not self.shuttingDown():
url = self.urls['search'] % (self.getCatId(quality['identifier'])[0], freeleech, tryUrlencode('%s %s' % (title.replace(':', ''), movie['library']['year'])), current_page) url = self.urls['search'] % (self.getCatId(quality['identifier'])[0], freeleech, tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), current_page)
data = self.getHTMLData(url) data = self.getHTMLData(url)
if data: if data:
@@ -36,7 +36,7 @@ class KickAssTorrents(TorrentMagnetProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', movie['library']['identifier'].replace('tt', ''))) data = self.getHTMLData(self.urls['search'] % (self.getDomain(), 'm', movie['identifier'].replace('tt', '')))
if data: if data:
@@ -56,13 +56,13 @@ class PassThePopcorn(TorrentProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
movie_title = getTitle(movie['library']) movie_title = getTitle(movie)
quality_id = quality['identifier'] quality_id = quality['identifier']
params = mergeDicts(self.quality_search_params[quality_id].copy(), { params = mergeDicts(self.quality_search_params[quality_id].copy(), {
'order_by': 'relevance', 'order_by': 'relevance',
'order_way': 'descending', 'order_way': 'descending',
'searchstr': movie['library']['identifier'] 'searchstr': movie['identifier']
}) })
url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params)) url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params))
@@ -30,7 +30,7 @@ class PublicHD(TorrentMagnetProvider):
params = tryUrlencode({ params = tryUrlencode({
'page':'torrents', 'page':'torrents',
'search': '%s %s' % (title, movie['library']['year']), 'search': '%s %s' % (title, movie['info']['year']),
'active': 1, 'active': 1,
}) })
@@ -39,7 +39,7 @@ class SceneAccess(TorrentProvider):
) )
arguments = tryUrlencode({ arguments = tryUrlencode({
'search': movie['library']['identifier'], 'search': movie['identifier'],
'method': 1, 'method': 1,
}) })
url = "%s&%s" % (url, arguments) url = "%s&%s" % (url, arguments)
@@ -50,7 +50,7 @@ class ThePirateBay(TorrentMagnetProvider):
while page < total_pages: while page < total_pages:
search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['library']['year'])), page, ','.join(str(x) for x in cats)) search_url = self.urls['search'] % (self.getDomain(), tryUrlencode('"%s" %s' % (title, movie['info']['year'])), page, ','.join(str(x) for x in cats))
page += 1 page += 1
data = self.getHTMLData(search_url) data = self.getHTMLData(search_url)
@@ -34,7 +34,7 @@ class TorrentBytes(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['library']['year'])), self.getCatId(quality['identifier'])[0]) url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), self.getCatId(quality['identifier'])[0])
data = self.getHTMLData(url) data = self.getHTMLData(url)
if data: if data:
@@ -27,7 +27,7 @@ class TorrentDay(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s"' % (title, movie['library']['year']) q = '"%s %s"' % (title, movie['info']['year'])
data = { data = {
'/browse.php?': None, '/browse.php?': None,
@@ -35,7 +35,7 @@ class TorrentLeech(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results): def _searchOnTitle(self, title, movie, quality, results):
url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['library']['year'])), self.getCatId(quality['identifier'])[0]) url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), self.getCatId(quality['identifier'])[0])
data = self.getHTMLData(url) data = self.getHTMLData(url)
if data: if data:
@@ -35,7 +35,7 @@ class TorrentPotato(TorrentProvider):
arguments = tryUrlencode({ arguments = tryUrlencode({
'user': host['name'], 'user': host['name'],
'passkey': host['pass_key'], 'passkey': host['pass_key'],
'imdbid': movie['library']['identifier'] 'imdbid': movie['identifier']
}) })
url = '%s?%s' % (host['host'], arguments) url = '%s?%s' % (host['host'], arguments)
@@ -34,7 +34,7 @@ class TorrentShack(TorrentProvider):
scene_only = '1' if self.conf('scene_only') else '' scene_only = '1' if self.conf('scene_only') else ''
url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['library']['year'])), scene_only, self.getCatId(quality['identifier'])[0]) url = self.urls['search'] % (tryUrlencode('%s %s' % (title.replace(':', ''), movie['info']['year'])), scene_only, self.getCatId(quality['identifier'])[0])
data = self.getHTMLData(url) data = self.getHTMLData(url)
if data: if data:
@@ -33,7 +33,7 @@ class Yify(TorrentMagnetProvider):
def _search(self, movie, quality, results): def _search(self, movie, quality, results):
search_url = self.urls['search'] % (self.getDomain(), movie['library']['identifier'], quality['identifier']) search_url = self.urls['search'] % (self.getDomain(), movie['identifier'], quality['identifier'])
data = self.getJsonData(search_url) data = self.getJsonData(search_url)
@@ -20,11 +20,11 @@ class HDTrailers(TrailerProvider):
def search(self, group): def search(self, group):
movie_name = getTitle(group['library']) movie_name = getTitle(group)
url = self.urls['api'] % self.movieUrlName(movie_name) url = self.urls['api'] % self.movieUrlName(movie_name)
try: try:
data = self.getCache('hdtrailers.%s' % group['library']['identifier'], url, show_error = False) data = self.getCache('hdtrailers.%s' % group['identifier'], url, show_error = False)
except HTTPError: except HTTPError:
log.debug('No page found for: %s', movie_name) log.debug('No page found for: %s', movie_name)
data = None data = None
@@ -50,11 +50,11 @@ class HDTrailers(TrailerProvider):
def findViaAlternative(self, group): def findViaAlternative(self, group):
results = {'480p':[], '720p':[], '1080p':[]} results = {'480p':[], '720p':[], '1080p':[]}
movie_name = getTitle(group['library']) movie_name = getTitle(group)
url = "%s?%s" % (self.urls['backup'], tryUrlencode({'s':movie_name})) url = "%s?%s" % (self.urls['backup'], tryUrlencode({'s':movie_name}))
try: try:
data = self.getCache('hdtrailers.alt.%s' % group['library']['identifier'], url, show_error = False) data = self.getCache('hdtrailers.alt.%s' % group['identifier'], url, show_error = False)
except HTTPError: except HTTPError:
log.debug('No alternative page found for: %s', movie_name) log.debug('No alternative page found for: %s', movie_name)
data = None data = None
+1 -2
View File
@@ -5,7 +5,6 @@ from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat
from couchpotato.core.settings.index import PropertyIndex from couchpotato.core.settings.index import PropertyIndex
from couchpotato.core.settings.model import Properties
import ConfigParser import ConfigParser
@@ -247,7 +246,7 @@ class Settings(object):
db.update(p['doc']) db.update(p['doc'])
except: except:
db.insert({ db.insert({
'type': 'property', '_t': 'property',
'identifier': identifier, 'identifier': identifier,
'value': toUnicode(value), 'value': toUnicode(value),
}) })
+4 -4
View File
@@ -5,12 +5,12 @@ from hashlib import md5
class PropertyIndex(HashIndex): class PropertyIndex(HashIndex):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s' kwargs['key_format'] = '32s'
super(PropertyIndex, self).__init__(*args, **kwargs) super(PropertyIndex, self).__init__(*args, **kwargs)
def make_key(self, key): def make_key(self, key):
return md5(key).digest() return md5(key).hexdigest()
def make_key_value(self, data): def make_key_value(self, data):
if data.get('type') == 'property': if data.get('_t') == 'property':
return md5(data['identifier']).digest(), None return md5(data['identifier']).hexdigest(), None
+2 -2
View File
@@ -223,9 +223,9 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
loader.run() loader.run()
# Fill database with needed stuff # Fill database with needed stuff
fireEvent('database.setup')
if not db_exists: if not db_exists:
fireEvent('app.initialize', in_order = True) fireEvent('app.initialize', in_order = True)
fireEvent('database.setup')
# Go go go! # Go go go!
from tornado.ioloop import IOLoop from tornado.ioloop import IOLoop
@@ -234,7 +234,7 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
# Some logging and fire load event # Some logging and fire load event
try: log.info('Starting server on port %(port)s', config) try: log.info('Starting server on port %(port)s', config)
except: pass except: pass
fireEventAsync('app.load2') fireEventAsync('app.load')
if config['ssl_cert'] and config['ssl_key']: if config['ssl_cert'] and config['ssl_key']:
server = HTTPServer(application, no_keep_alive = True, ssl_options = { server = HTTPServer(application, no_keep_alive = True, ssl_options = {
-2
View File
@@ -69,8 +69,6 @@
'qualities': {{ json_encode(fireEvent('quality.all', single = True)) }} 'qualities': {{ json_encode(fireEvent('quality.all', single = True)) }}
}); });
Status.setup({{ json_encode(fireEvent('status.all', single = True)) }});
CategoryList.setup({{ json_encode(fireEvent('category.all', single = True)) }}); CategoryList.setup({{ json_encode(fireEvent('category.all', single = True)) }});
App.setup({ App.setup({