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

View File

@@ -42,11 +42,11 @@ class Core(Plugin):
addEvent('app.shutdown', self.shutdown)
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.api_url', self.createApiUrl)
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.api_key', self.checkApikey)

View File

@@ -74,7 +74,7 @@ class ClientScript(Plugin):
addEvent('clientscript.get_scripts', self.getScripts)
if not Env.get('dev'):
addEvent('app.load2', self.minify)
addEvent('app.load', self.minify)
self.addCore()

View File

@@ -25,7 +25,7 @@ if Env.get('desktop'):
# Events to desktop
addEvent('app.after_shutdown', desktop.afterShutdown)
addEvent('app.load2', desktop.onAppLoad, priority = 110)
addEvent('app.load', desktop.onAppLoad, priority = 110)
def onClose(self, event):
return fireEvent('app.shutdown', single = True)

View File

@@ -33,8 +33,8 @@ class Updater(Plugin):
else:
self.updater = SourceUpdater()
addEvent('app.load2', self.logVersion, priority = 10000)
addEvent('app.load2', self.setCrons)
addEvent('app.load', self.logVersion, priority = 10000)
addEvent('app.load', self.setCrons)
addEvent('updater.info', self.info)
addApiView('updater.info', self.info, docs = {

View File

@@ -23,7 +23,7 @@ class rTorrent(Downloader):
def __init__(self):
super(rTorrent, self).__init__()
addEvent('app.load2', self.migrate)
addEvent('app.load', self.migrate)
def migrate(self):

View File

@@ -216,26 +216,24 @@ def toIterable(value):
return [value]
def getTitle(library_dict):
def getTitle(media_dict):
try:
try:
return library_dict['titles'][0]['title']
return media_dict['title']
except:
try:
for title in library_dict.titles:
if title.default:
return title.title
return media_dict['titles'][0]
except:
try:
return library_dict['info']['titles'][0]
return media_dict['info']['titles'][0]
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
log.error('Could not get title for %s', library_dict['identifier'])
log.error('Could not get title for %s', media_dict['identifier'])
return None
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

View File

@@ -1,8 +1,7 @@
import traceback
from couchpotato import get_session, get_db, CPLog
from couchpotato.core.event import addEvent, fireEventAsync, fireEvent
from couchpotato import get_db, CPLog
from couchpotato.core.event import addEvent, fireEvent, fireEventAsync
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Media
log = CPLog(__name__)
@@ -34,11 +33,9 @@ class MediaBase(Plugin):
media = db.get('id', media_id)
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:
log.error('Failed creating onComplete: %s', traceback.format_exc())
finally:
pass #db.close()
return onComplete
@@ -53,7 +50,5 @@ class MediaBase(Plugin):
fireEvent('notify.frontend', type = event_name, data = media)
except:
log.error('Failed creating onComplete: %s', traceback.format_exc())
finally:
pass #db.close()
return notifyFront

View File

@@ -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

View File

@@ -14,9 +14,14 @@ class MediaIMDBIndex(HashIndex):
return int(key.strip('t'))
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
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 = []):
status = list(status if isinstance(status, (list, tuple)) else [status])
@@ -29,15 +34,15 @@ class MediaIMDBIndex(HashIndex):
class MediaStatusIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = '32s'
super(MediaStatusIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('type') == 'media' and data.get('status'):
return md5(data.get('status')).digest(), None
if data.get('_t') == 'media' and data.get('status'):
return md5(data.get('status')).hexdigest(), None
class TitleIndex(MultiTreeBasedIndex):
@@ -52,7 +57,7 @@ from itertools import izip"""
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()
title = data.get('title').lower()
@@ -80,5 +85,5 @@ class YearIndex(TreeBasedIndex):
return key
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

View File

@@ -1,16 +1,14 @@
import traceback
import time
from couchpotato import get_session, tryInt, get_db
from couchpotato.api import addApiView
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.logger import CPLog
from couchpotato.core.media import MediaBase
from .index import MediaIMDBIndex, TitleIndex, MediaStatusIndex, YearIndex
from couchpotato.core.settings.model import Library, LibraryTitle, Release, \
Media
from sqlalchemy.orm import joinedload_all
from sqlalchemy.sql.expression import or_, asc, not_, desc
from string import ascii_lowercase
log = CPLog(__name__)
@@ -63,10 +61,10 @@ class MediaPlugin(MediaBase):
addEvent('database.setup', self.databaseSetup)
addEvent('app.load2', self.addSingleRefreshView)
addEvent('app.load2', self.addSingleListView)
addEvent('app.load2', self.addSingleCharView)
addEvent('app.load2', self.addSingleDeleteView)
addEvent('app.load', self.addSingleRefreshView)
addEvent('app.load', self.addSingleListView)
addEvent('app.load', self.addSingleCharView)
addEvent('app.load', self.addSingleDeleteView)
addEvent('media.get', self.get)
addEvent('media.list', self.list)
@@ -126,7 +124,7 @@ class MediaPlugin(MediaBase):
try:
media = get_db().get('id', media_id)
default_title = getTitle(media_id)
default_title = getTitle(media)
event = 'library.update.%s' % media.get('type')
def handler():
@@ -157,7 +155,7 @@ class MediaPlugin(MediaBase):
results = None
if m:
results = db.run('media', 'to_dict', m, self.default_dict)
results = db.run('media', 'to_dict', m['_id'])
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):
db = get_session()
db = get_db()
start = time.time()
# Make a list from string
if status and not isinstance(status, (list, tuple)):
@@ -182,120 +182,128 @@ class MediaPlugin(MediaBase):
if types and not isinstance(types, (list, tuple)):
types = [types]
# query movie ids
q = db.query(Media) \
.with_entities(Media.id) \
.group_by(Media.id)
# query media ids
all_media_ids = set([x['_id'] for x in db.all('media')])
media_ids = all_media_ids
filter_by = {}
# Filter on movie status
if status and len(status) > 0:
statuses = fireEvent('status.get', status, single = len(status) > 1)
statuses = [s.get('id') for s in statuses]
q = q.filter(Media.status_id.in_(statuses))
filter_by['media_status'] = set()
for media_status in db.run('media', 'with_status', status):
filter_by['media_status'].add(media_status.get('_id'))
# Filter on release status
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)
statuses = [s.get('id') for s in statuses]
q = q.filter(Release.status_id.in_(statuses))
# Filter by combining ids
for x in filter_by:
media_ids = media_ids & filter_by[x]
# Filter on type
if types and len(types) > 0:
try: q = q.filter(Media.type.in_(types))
except: pass
# if types and len(types) > 0:
# try: q = q.filter(Media.type.in_(types))
# except: pass
# Only join when searching / ordering
if starts_with or search or order != 'release_order':
q = q.join(Media.library, Library.titles) \
.filter(LibraryTitle.default == True)
# if starts_with or search or order != 'release_order':
# q = q.join(Media.library, Library.titles) \
# .filter(LibraryTitle.default == True)
# Add search filters
filter_or = []
if starts_with:
starts_with = toUnicode(starts_with.lower())
if starts_with in ascii_lowercase:
filter_or.append(LibraryTitle.simple_title.startswith(starts_with))
else:
ignore = []
for letter in ascii_lowercase:
ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter)))
filter_or.append(not_(or_(*ignore)))
# filter_or = []
# if starts_with:
# starts_with = toUnicode(starts_with.lower())
# if starts_with in ascii_lowercase:
# filter_or.append(LibraryTitle.simple_title.startswith(starts_with))
# else:
# ignore = []
# for letter in ascii_lowercase:
# ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter)))
# filter_or.append(not_(or_(*ignore)))
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:
q = q.filter(or_(*filter_or))
#if len(filter_or) > 0:
# pass #q = q.filter(or_(*filter_or))
total_count = q.count()
total_count = len(media_ids)
if total_count == 0:
return 0, []
if order == 'release_order':
q = q.order_by(desc(Release.last_edit))
else:
q = q.order_by(asc(LibraryTitle.simple_title))
# if order == 'release_order':
# q = q.order_by(desc(Release.last_edit))
# else:
# q = q.order_by(asc(LibraryTitle.simple_title))
if limit_offset:
splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset
limit = splt[0]
offset = 0 if len(splt) is 1 else splt[1]
q = q.limit(limit).offset(offset)
# if limit_offset:
# splt = splitString(limit_offset) if isinstance(limit_offset, (str, unicode)) else limit_offset
# limit = splt[0]
# offset = 0 if len(splt) is 1 else splt[1]
# q = q.limit(limit).offset(offset)
# 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
releases = db.query(Release) \
.filter(Release.movie_id.in_(media_ids)) \
.all()
# releases = db.query(Release) \
# .filter(Release.movie_id.in_(media_ids)) \
# .all()
release_statuses = dict((m, set()) for m in media_ids)
releases_count = dict((m, 0) for m in media_ids)
for release in releases:
release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id))
releases_count[release.movie_id] += 1
# release_statuses = dict((m, set()) for m in media_ids)
# releases_count = dict((m, 0) for m in media_ids)
# for release in releases:
# release_statuses[release.movie_id].add('%d,%d' % (release.status_id, release.quality_id))
# releases_count[release.movie_id] += 1
# Get main movie data
q2 = db.query(Media) \
.options(joinedload_all('library.titles')) \
.options(joinedload_all('library.files')) \
.options(joinedload_all('status')) \
.options(joinedload_all('files'))
# q2 = db.query(Media) \
# .options(joinedload_all('library.titles')) \
# .options(joinedload_all('library.files')) \
# .options(joinedload_all('status')) \
# .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
movie_dict = {}
for movie in results:
movie_dict[movie.id] = movie
# medias = {}
# for media in media_ids:
# movie_dict[movie.id] = movie
# List movies based on media_ids order
movies = []
medias = []
for media_id in media_ids:
releases = []
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({
media = db.run('media', 'to_dict', media_id, {
'library': {'titles': {}, 'files': {}},
'files': {},
}), {
'releases': releases,
'releases_count': releases_count.get(media_id),
}))
})
pass #db.close()
return total_count, movies
media['releases'] = []
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):
@@ -424,19 +432,18 @@ class MediaPlugin(MediaBase):
db.commit()
deleted = True
else:
done_status = fireEvent('status.get', 'done', single = True)
total_releases = len(media.releases)
total_deleted = 0
new_movie_status = None
for release in media.releases:
if delete_from in ['wanted', 'snatched', 'late']:
if release.status_id != done_status.get('id'):
if release.get('status') != 'done':
db.delete(release)
total_deleted += 1
new_movie_status = 'done'
elif delete_from == 'manage':
if release.status_id == done_status.get('id'):
if release.get('status') == 'done':
db.delete(release)
total_deleted += 1
new_movie_status = 'active'
@@ -447,9 +454,8 @@ class MediaPlugin(MediaBase):
db.commit()
deleted = True
elif new_movie_status:
new_status = fireEvent('status.get', new_movie_status, single = True)
media.profile_id = None
media.status_id = new_status.get('id')
media['status'] = new_status
db.commit()
else:
fireEvent('media.restatus', media.id, single = True)
@@ -458,9 +464,6 @@ class MediaPlugin(MediaBase):
fireEvent('notify.frontend', type = 'movie.deleted', data = media.to_dict())
except:
log.error('Failed deleting media: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return True
@@ -483,8 +486,6 @@ class MediaPlugin(MediaBase):
def restatus(self, media_id):
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
try:
db = get_session()
@@ -494,17 +495,17 @@ class MediaPlugin(MediaBase):
return False
log.debug('Changing status for %s', m.library.titles[0].title)
if not m.profile:
m.status_id = done_status.get('id')
if not m['profile_id']:
m['status'] = 'done'
else:
move_to_wanted = True
for t in m.profile.types:
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
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()

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):

View File

@@ -28,7 +28,7 @@ class SearcherBase(Plugin):
fireEvent('schedule.cron', '%s.searcher.all' % _type, self.searchAll,
day = self.conf('cron_day'), hour = self.conf('cron_hour'), minute = self.conf('cron_minute'))
addEvent('app.load2', setCrons)
addEvent('app.load', setCrons)
addEvent('setting.save.%s_searcher.cron_day.after' % _type, setCrons)
addEvent('setting.save.%s_searcher.cron_hour.after' % _type, setCrons)
addEvent('setting.save.%s_searcher.cron_minute.after' % _type, setCrons)

View File

@@ -48,7 +48,7 @@ class Searcher(SearcherBase):
results = []
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:
results += protocol_results

View File

@@ -1,13 +1,13 @@
import traceback
from couchpotato import get_session, get_db
from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import splitString, tryInt, getTitle
from couchpotato.core.logger import CPLog
from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Media
import time
import six
log = CPLog(__name__)
@@ -42,8 +42,10 @@ class MovieBase(MovieTypeBase):
})
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.get('identifier'):
@@ -62,27 +64,55 @@ class MovieBase(MovieTypeBase):
except:
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'))
# 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)
cat_id = params.get('category_id')
try:
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
try:
m = db.get('movie', params.get('identifier'), with_doc = True)['doc']
m = db.get('media', params.get('identifier'), with_doc = True)['doc']
except:
new = True
m = db.insert({
'type': 'movie',
'identifier': params.get('identifier'),
'status': status_id if status_id 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,
})
m = db.insert(media)
# Update dict to be usable
m.update(media)
# Update movie info
try: del info['in_wanted']
except: pass
try: del info['in_library']
except: pass
m['info'] = info
added = True
do_search = False
@@ -92,7 +122,7 @@ class MovieBase(MovieTypeBase):
if search_after:
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
elif force_readd:
@@ -106,24 +136,24 @@ class MovieBase(MovieTypeBase):
fireEvent('release.delete', release['_id'], single = True)
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:
log.debug('Movie already exists, not updating: %s', params)
added = False
if force_readd:
m['status'] = status_id if status_id else 'active'
m['last_edit'] = int(time.time())
do_search = True
db.update(m)
if added:
db.update(m)
# Remove releases
for rel in db.run('release', 'for_media', m['_id']):
if rel['status'] is 'available':
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:
onComplete = self.createOnComplete(m['_id'])
@@ -137,7 +167,7 @@ class MovieBase(MovieTypeBase):
if title:
message = 'Successfully added "%s" to your wanted list.' % title
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)
return movie_dict
@@ -161,7 +191,7 @@ class MovieBase(MovieTypeBase):
for media_id in ids:
try:
m = db.get('media', media_id)
m = db.get('id', media_id)
m['profile_id'] = kwargs.get('profile_id')
cat_id = kwargs.get('category_id')
@@ -197,3 +227,128 @@ class MovieBase(MovieTypeBase):
return {
'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

View File

@@ -191,11 +191,9 @@ MA.Release = new Class({
self.releases.each(function(release){
var status = Status.get(release.status_id),
quality = Quality.getProfile(release.quality_id) || {},
var quality = Quality.getProfile(release.quality_id) || {},
info = release.info,
provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : '');
release.status = status;
var release_name = self.get(release, 'name');
if(release.files && release.files.length > 0){
@@ -215,7 +213,7 @@ MA.Release = new Class({
'id': 'release_'+release.id
}).adopt(
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.size', {'text': release.info['size'] ? Math.floor(self.get(release, 'size')) : 'n/a'}),
new Element('span.age', {'text': self.get(release, 'age')}),
@@ -257,22 +255,20 @@ MA.Release = new Class({
if(notification.data.id != release.id) return;
var q = self.movie.quality.getElement('.q_id' + release.quality_id),
status = Status.get(release.status_id),
new_status = Status.get(notification.data.status_id);
new_status = notification.data.status;
release.status_id = new_status.id
release.el.set('class', 'item ' + new_status.identifier);
release.el.set('class', 'item ' + new_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);
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);
if(new_status && q && !q.hasClass(new_status.identifier)) {
q.removeClass(status.identifier).addClass(new_status.identifier);
q.set('title', q.get('title').replace(status.label, new_status.label));
if(q && !q.hasClass(new_status)) {
q.removeClass(release.status).addClass(new_status);
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){
if(has_available && has_snatched) return;
var status = Status.get(release.status_id);
if(['snatched', 'downloaded', 'seeding'].contains(status.identifier))
if(['snatched', 'downloaded', 'seeding'].contains(release.status))
has_snatched = true;
if(['available'].contains(status.identifier))
if(['available'].contains(release.status))
has_available = true;
});
@@ -726,10 +720,10 @@ MA.Readd = new Class({
create: function(){
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)
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;
if(movie_done || snatched && snatched > 0)
@@ -924,4 +918,4 @@ MA.Files = new Class({
self.movie.slide('in', self.options_container);
},
});
});

View File

@@ -59,7 +59,7 @@ var Movie = new Class({
if(!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();
}
}
@@ -146,8 +146,7 @@ var Movie = new Class({
create: function(){
var self = this;
var s = Status.get(self.get('status_id'));
self.el.addClass('status_'+s.identifier);
self.el.addClass('status_'+self.get('status'));
self.el.adopt(
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.info_container = new Element('div.info').adopt(
new Element('div.title').adopt(
@@ -165,11 +164,11 @@ var Movie = new Class({
'text': self.getTitle() || 'n/a'
}),
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', {
'text': self.data.library.plot
'text': self.data.info.plot
}),
self.quality = new Element('div.quality', {
'events': {
@@ -221,14 +220,14 @@ var Movie = new Class({
self.data.releases.each(function(release){
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)
if (status && q && !q.hasClass(status.identifier)){
q.addClass(status.identifier);
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status.label)
if (q && !q.hasClass(status)){
q.addClass(status);
q.set('title', (q.get('title') ? q.get('title') : '') + ' status: '+ status)
}
});
@@ -249,16 +248,10 @@ var Movie = new Class({
getTitle: function(){
var self = this;
var titles = self.data.library.titles;
var title = titles.filter(function(title){
return title['default']
}).pop()
if(title)
return self.getUnprefixedTitle(title.title)
else if(titles.length > 0)
return self.getUnprefixedTitle(titles[0].title)
if(self.data.title)
return self.getUnprefixedTitle(self.data.title)
else if(self.data.info.titles.length > 0)
return self.getUnprefixedTitle(self.data.info.titles[0])
return 'Unknown movie'
},
@@ -313,7 +306,7 @@ var Movie = new Class({
},
get: function(attr){
return this.data[attr] || this.data.library[attr]
return this.data[attr] || this.data.info[attr]
},
select: function(bool){

View File

@@ -197,8 +197,8 @@ Block.Search.MovieItem = new Class({
profiles.each(function(profile){
new Element('option', {
'value': profile.id ? profile.id : profile.data.id,
'text': profile.label ? profile.label : profile.data.label
'value': profile.get('_id'),
'text': profile.get('label')
}).inject(self.profile_select)
});

View File

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

View File

@@ -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

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.core.event import addEvent, fireEvent, fireEventAsync
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.media._base.searcher.base import SearcherBase
from couchpotato.core.media.movie import MovieTypeBase
from couchpotato.core.settings.model import Media, Release
from couchpotato.environment import Env
from datetime import date
import random
@@ -51,7 +50,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
})
if self.conf('run_on_launch'):
addEvent('app.load2', self.searchAll)
addEvent('app.load', self.searchAll)
def searchAllView(self, **kwargs):
@@ -94,7 +93,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
self.single(movie_dict, search_protocols)
except IndexError:
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:
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):
# movies don't contain 'type' yet, so just set to default here
if 'type' not in movie:
movie['type'] = 'movie'
# Find out search type
try:
if not search_protocols:
@@ -127,7 +122,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return
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 = []
too_early_to_search = []
@@ -142,39 +137,50 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
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
for quality_type in movie['profile']['types']:
if not self.conf('always_search') and not self.couldBeReleased(quality_type['quality']['identifier'] in pre_releases, release_dates, movie['year']):
too_early_to_search.append(quality_type['quality']['identifier'])
for q_identifier in profile.get('qualities'):
index = profile['qualities'].index(q_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
has_better_quality = 0
# See if better quality is available
for release in movie['releases']:
if release['quality']['order'] <= quality_type['quality']['order'] and release['status'] not in ['available', 'ignored', 'failed']:
for release in media_releases:
if quality_order.index(release['quality']) <= quality_order.index(q_identifier) and release['status'] not in ['available', 'ignored', 'failed']:
has_better_quality += 1
# Don't search for quality lower then already available.
if has_better_quality is 0:
log.info('Search for %s in %s', (default_title, quality_type['quality']['label']))
quality = fireEvent('quality.single', identifier = quality_type['quality']['identifier'], single = True)
quality = fireEvent('quality.single', identifier = q_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 []
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
if not fireEvent('media.get', movie.get('_id'), single = True):
break
# 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
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
# Remove releases that aren't found anymore
@@ -183,7 +189,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
fireEvent('release.delete', release.get('_id'), single = True)
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'])
break
@@ -219,7 +225,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
preferred_quality = fireEvent('quality.single', identifier = quality['identifier'], single = True)
# 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']))
return False
@@ -249,23 +255,23 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
return True
# Check if nzb contains imdb link
if getImdb(nzb.get('description', '')) == media['library']['identifier']:
if getImdb(nzb.get('description', '')) == media['identifier']:
return True
for raw_title in media['library']['titles']:
for movie_title in possibleTitles(raw_title['title']):
for raw_title in media['info']['titles']:
for movie_title in possibleTitles(raw_title):
movie_words = re.split('\W+', simplifyString(movie_title))
if fireEvent('searcher.correct_name', nzb['name'], movie_title, single = True):
# if no IMDB link, at least check year range 1
if len(movie_words) > 2 and 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
# 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
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
def couldBeReleased(self, is_pre_release, dates, year = None):
@@ -337,7 +343,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
def getSearchTitle(self, media):
if media['type'] == 'movie':
return getTitle(media['library'])
return getTitle(media)
class SearchSetupError(Exception):
pass

View File

@@ -89,8 +89,6 @@ class Suggestion(Plugin):
# Get new results and add them
if len(new_suggestions) - 1 < limit:
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
db = get_session()
active_movies = db.query(Media) \
.join(Library) \

View File

@@ -15,7 +15,7 @@ import time"""
return key
def make_key_value(self, data):
if data.get('type') == 'notification':
if data.get('_t') == 'notification':
added = data.get('added', time.time())
data['added'] = added
@@ -35,7 +35,7 @@ import time"""
return key
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())
data['added'] = added

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.clean_messages', self.cleanMessages, seconds = 15, single = True)
addEvent('app.load2', self.clean)
addEvent('app.load2', self.checkMessages)
addEvent('app.load', self.clean)
addEvent('app.load', self.checkMessages)
addEvent('database.setup', self.databaseSetup)
@@ -161,7 +161,7 @@ class CoreNotifier(Notification):
data['notification_type'] = listener if listener else 'unknown'
n = {
'type': 'notification',
'_t': 'notification',
'time': int(time.time()),
'message': toUnicode(message),
'data': data

View File

@@ -16,7 +16,7 @@ class Growl(Notification):
super(Growl, self).__init__()
if self.isEnabled():
addEvent('app.load2', self.register)
addEvent('app.load', self.register)
def register(self):
if self.registered: return

View File

@@ -23,16 +23,16 @@ class Pushover(Notification):
'priority': self.conf('priority'),
}
if data and data.get('library'):
if data and data.get('identifier'):
api_data.update({
'url': toUnicode('http://www.imdb.com/title/%s/' % data['library']['identifier']),
'url_title': toUnicode('%s on IMDb' % getTitle(data['library'])),
'url': toUnicode('http://www.imdb.com/title/%s/' % data['identifier']),
'url_title': toUnicode('%s on IMDb' % getTitle(data)),
})
http_handler.request('POST',
"/1/messages.json",
headers = {'Content-type': 'application/x-www-form-urlencoded'},
body = tryUrlencode(api_data)
"/1/messages.json",
headers = {'Content-type': 'application/x-www-form-urlencoded'},
body = tryUrlencode(api_data)
)
response = http_handler.getresponse()

View File

@@ -1,3 +1,4 @@
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.logger import CPLog
from couchpotato.core.notifications.base import Notification
@@ -21,9 +22,9 @@ class Trakt(Notification):
'username': self.conf('automation_username'),
'password' : self.conf('automation_password'),
'movies': [{
'imdb_id': data['library']['identifier'],
'title': data['library']['titles'][0]['title'],
'year': data['library']['year']
'imdb_id': data['identifier'],
'title': getTitle(data),
'year': data['info']['year']
}] if data else []
}

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.notifications.base import Notification
import base64
@@ -131,7 +131,7 @@ class XBMC(Notification):
server = 'http://%s/xbmcCmds/' % host
# 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
# I have no idea what to set to, just tried text/plain and seems to be working :)

View File

@@ -10,10 +10,10 @@ class Automation(Plugin):
def __init__(self):
addEvent('app.load2', self.setCrons)
addEvent('app.load', self.setCrons)
if not Env.get('dev'):
addEvent('app.load2', self.addMovies)
addEvent('app.load', self.addMovies)
addEvent('setting.save.automation.hour.after', self.setCrons)

View File

@@ -291,7 +291,7 @@ class Plugin(object):
def cpTag(self, media):
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 ''

View File

@@ -5,12 +5,12 @@ from CodernityDB.tree_index import TreeBasedIndex
class CategoryIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = '32s'
super(CategoryIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('type') == 'category':
return md5(data['media_id']).digest(), None
if data.get('_t') == 'category':
return md5(data['media_id']).hexdigest(), None

View File

@@ -10,7 +10,7 @@ log = CPLog(__name__)
class Custom(Plugin):
def __init__(self):
addEvent('app.load2', self.createStructure)
addEvent('app.load', self.createStructure)
def createStructure(self):

View File

@@ -49,7 +49,6 @@ class Dashboard(Plugin):
limit = tryInt(splt[0])
# Get all active movies
active_status, ignored_status = fireEvent('status.get', ['active', 'ignored'], single = True)
q = db.query(Media) \
.join(Library) \
.outerjoin(Media.releases) \

View File

@@ -5,8 +5,7 @@ from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import md5, getExt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.plugins.scanner.main import Scanner
from couchpotato.core.settings.model import FileType, File
from couchpotato.core.settings.model import File
from couchpotato.environment import Env
from tornado.web import StaticFileHandler
import os.path

View File

@@ -47,7 +47,7 @@ class Manage(Plugin):
})
if not Env.get('dev') and self.conf('startup_scan'):
addEvent('app.load2', self.updateLibraryQuick)
addEvent('app.load', self.updateLibraryQuick)
def getProgress(self, **kwargs):
return {
@@ -120,7 +120,7 @@ class Manage(Plugin):
total_movies, done_movies = fireEvent('media.list', types = 'movie', status = 'done', single = True)
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')
else:
@@ -184,13 +184,13 @@ class Manage(Plugin):
'to_go': total_found,
})
if group['library'] and group['library'].get('identifier'):
identifier = group['library'].get('identifier')
if group['media'] and group['media'].get('identifier'):
identifier = group['media'].get('identifier')
added_identifiers.append(identifier)
# Add it to release and update the info
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:
self.updateProgress(folder)
@@ -207,7 +207,7 @@ class Manage(Plugin):
total = self.in_progress[folder]['total']
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
@@ -237,7 +237,7 @@ class Manage(Plugin):
if groups:
for group in groups.values():
if group['library'] and group['library'].get('identifier'):
if group.get('info'):
fireEvent('release.add', group = group)
def getDiskSpace(self):

View File

@@ -12,6 +12,6 @@ class NameIndex(TreeBasedIndex):
return key
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

View File

@@ -2,7 +2,6 @@ import time
from couchpotato import CPLog, get_db
from couchpotato.core.event import addEvent
from couchpotato.core.plugins.base import Plugin
from .index import ReleaseIndex, NameIndex
log = CPLog(__name__)
@@ -13,7 +12,7 @@ class NoSQL(Plugin):
def __init__(self):
pass #addEvent('app.load2', self.test)
pass #addEvent('app.load', self.test)
def test(self):
@@ -31,7 +30,8 @@ class NoSQL(Plugin):
for id in range(10):
media = db.insert({
'type': 'media',
'_t': 'media',
'type': 'movie',
'tmdb': id,
'imdb': 'tt%s' % id,
'last_edit': 0,

View File

@@ -1,16 +1,15 @@
from CodernityDB.hash_index import HashIndex
from hashlib import md5
from CodernityDB.tree_index import TreeBasedIndex
class ProfileIndex(HashIndex):
class ProfileIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = 'i'
super(ProfileIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return key
def make_key_value(self, data):
if data.get('type') == 'profile' and data.get('identifier'):
return md5(data.get('identifier')).digest(), None
if data.get('_t') == 'profile':
return data.get('order', 99), None

View File

@@ -1,13 +1,12 @@
import traceback
from couchpotato import get_session, get_db
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.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from .index import ProfileIndex
from couchpotato.core.settings.model import Profile, ProfileType, Media
from sqlalchemy.orm import joinedload_all
from couchpotato.core.settings.model import Profile, ProfileType
log = CPLog(__name__)
@@ -34,7 +33,7 @@ class ProfilePlugin(Plugin):
addEvent('database.setup', self.databaseSetup)
addEvent('app.initialize', self.fill, priority = 90)
addEvent('app.load2', self.forceDefaults)
addEvent('app.load', self.forceDefaults)
def databaseSetup(self):
@@ -46,7 +45,6 @@ class ProfilePlugin(Plugin):
log.debug('Index already exists')
db.edit_index(ProfileIndex(db.path, 'profile'))
def forceDefaults(self):
# Get all active movies without profile
@@ -57,7 +55,7 @@ class ProfilePlugin(Plugin):
profile_ids = [x.get('_id') for x in self.all()]
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()
media['profile_id'] = default_profile.get('id')
db.update(media)
@@ -76,7 +74,7 @@ class ProfilePlugin(Plugin):
db = get_db()
profiles = db.all('profile', with_doc = True)
return list(profiles)
return [x['doc'] for x in profiles]
def save(self, **kwargs):
@@ -127,7 +125,7 @@ class ProfilePlugin(Plugin):
def default(self):
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):
@@ -213,8 +211,7 @@ class ProfilePlugin(Plugin):
log.info('Creating default profile: %s', profile.get('label'))
pro = {
'type': 'profile',
'identifier': profile.get('label').lower(),
'_t': 'profile',
'label': toUnicode(profile.get('label')),
'order': order,
'qualities': profile.get('qualities'),
@@ -229,9 +226,6 @@ class ProfilePlugin(Plugin):
db.insert(pro)
order += 1
for x in db.all('profile', with_doc = True):
log.info(x)
return True
except:
log.error('Failed: %s', traceback.format_exc())

View File

@@ -324,4 +324,4 @@ Profile.Type = new Class({
return this.el;
}
})
})

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

View File

@@ -1,15 +1,14 @@
import traceback
from couchpotato import get_session
from couchpotato import get_session, get_db
from couchpotato.api import addApiView
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import toUnicode, ss
from couchpotato.core.helpers.variable import mergeDicts, getExt
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Quality, Profile, ProfileType
from sqlalchemy.sql.expression import or_
from couchpotato.core.plugins.quality.index import QualityIndex
from couchpotato.core.settings.model import Quality
import re
import time
log = CPLog(__name__)
@@ -39,6 +38,7 @@ class QualityPlugin(Plugin):
addEvent('quality.single', self.single)
addEvent('quality.guess', self.guess)
addEvent('quality.pre_releases', self.preReleases)
addEvent('quality.order', self.getOrder)
addApiView('quality.size.save', self.saveSize)
addApiView('quality.list', self.allView, docs = {
@@ -50,9 +50,31 @@ class QualityPlugin(Plugin):
})
addEvent('app.initialize', self.fill, priority = 10)
addEvent('database.setup', self.databaseSetup)
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):
return self.pre_releases
@@ -68,30 +90,29 @@ class QualityPlugin(Plugin):
if 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 = []
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)
self.cached_qualities = temp
pass #db.close()
return temp
def single(self, identifier = ''):
db = get_session()
db = get_db()
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:
quality_dict = dict(self.getQuality(quality.identifier), **quality.to_dict())
quality_dict = mergeDicts(self.getQuality(quality['identifier']), quality)
pass #db.close()
return quality_dict
def getQuality(self, identifier):
@@ -128,60 +149,35 @@ class QualityPlugin(Plugin):
def fill(self):
try:
db = get_session()
db = get_db()
order = 0
for q in self.qualities:
# Create quality
qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first()
db.insert({
'_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 quality: %s', q.get('label'))
qual = Quality()
qual.order = order
qual.identifier = q.get('identifier')
qual.label = toUnicode(q.get('label'))
qual.size_min, qual.size_max = q.get('size')
db.add(qual)
# 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)
log.info('Creating profile: %s', q.get('label'))
db.insert({
'_t': 'profile',
'order': order + 20, # Make sure it goes behind other profiles
'core': True,
'qualities': [q.get('identifier')],
'label': toUnicode(q.get('label')),
'finish': [True],
'wait_for': [0],
})
order += 1
db.commit()
time.sleep(0.3) # Wait a moment
return True
except:
log.error('Failed: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return False

View File

@@ -5,15 +5,15 @@ from CodernityDB.tree_index import TreeBasedIndex
class ReleaseIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = '32s'
super(ReleaseIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('type') == 'release' and data.get('media_id'):
return md5(data['media_id']).digest(), {'media_id': data.get('media_id')}
if data.get('_t') == 'release' and data.get('media_id'):
return md5(data['media_id']).hexdigest(), {'media_id': data.get('media_id')}
def run_for_media(self, db, media_id):
for release in db.get_many('release', media_id, with_doc = True):
@@ -31,12 +31,26 @@ class ReleaseIndex(TreeBasedIndex):
class ReleaseStatusIndex(TreeBasedIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = '32s'
super(ReleaseStatusIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('type') == 'release' and data.get('status'):
return md5(data.get('status')).digest(), None
if data.get('_t') == 'release' and data.get('status'):
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

View File

@@ -5,7 +5,7 @@ from couchpotato.core.helpers.encoding import ss, toUnicode
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.logger import CPLog
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.settings.model import Release as Relea, Media, \
ReleaseInfo
@@ -61,7 +61,7 @@ class Release(Plugin):
addEvent('database.setup', self.databaseSetup)
# 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)
def databaseSetup(self):
@@ -82,6 +82,13 @@ class Release(Plugin):
log.debug('Index already exists')
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):
log.debug('Removing releases from dashboard')
@@ -112,7 +119,7 @@ class Release(Plugin):
try:
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
media = db.query(Media).filter_by(library_id = group['library'].get('id')).first()
@@ -120,7 +127,7 @@ class Release(Plugin):
media = Media(
library_id = group['library'].get('id'),
profile_id = 0,
status_id = done_status.get('id')
status = 'done'
)
db.add(media)
db.commit()
@@ -129,7 +136,7 @@ class Release(Plugin):
rel = db.query(Relea).filter(
or_(
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()
if not rel:
@@ -137,7 +144,7 @@ class Release(Plugin):
identifier = identifier,
movie = media,
quality_id = group['meta_data']['quality'].get('id'),
status_id = done_status.get('id')
status = 'done'
)
db.add(rel)
db.commit()
@@ -246,11 +253,6 @@ class Release(Plugin):
# Get matching provider
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':
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):
# 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
downloader_enabled = fireEvent('download.enabled', manual, data, single = True)
if not downloader_enabled:
@@ -303,8 +300,6 @@ class Release(Plugin):
return False
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:
db = get_session()
rls = db.query(Relea).filter_by(identifier = md5(data['url'])).first()
@@ -324,7 +319,7 @@ class Release(Plugin):
rls.info.append(rls_info)
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)
log.info(snatch_message)
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
else:
if media['status_id'] == active_status.get('id'):
if media['status'] == 'active':
finished = next((True for profile_type in media['profile']['types']
if profile_type['quality_id'] == rls.quality.id and profile_type['finish']), False)
if finished:
@@ -346,7 +341,7 @@ class Release(Plugin):
# Mark media done
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())
db.commit()
@@ -364,15 +359,14 @@ class Release(Plugin):
return True
def tryDownloadResult(self, results, media, quality_type, manual = False):
ignored_status, failed_status = fireEvent('status.get', ['ignored', 'failed'], single = True)
def tryDownloadResult(self, results, media, quality_custom, manual = False):
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):
log.info('Ignored, waiting %s days: %s', (quality_type.get('wait_for'), rel['name']))
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_custom.get('wait_for'), rel['name']))
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'])
continue
@@ -388,12 +382,10 @@ class Release(Plugin):
return False
def createFromSearch(self, search_results, media, quality_type):
available_status = fireEvent('status.get', ['available'], single = True)
def createFromSearch(self, search_results, media, quality):
try:
db = get_session()
db = get_db()
found_releases = []
@@ -402,45 +394,40 @@ class Release(Plugin):
rel_identifier = md5(rel['url'])
found_releases.append(rel_identifier)
rls = db.query(Relea).filter_by(identifier = rel_identifier).first()
if not rls:
rls = Relea(
identifier = rel_identifier,
movie_id = media.get('id'),
#media_id = media.get('id'),
quality_id = quality_type.get('quality_id'),
status_id = available_status.get('id')
)
db.add(rls)
else:
[db.delete(old_info) for old_info in rls.info]
rls.last_edit = int(time.time())
release = {
'_t': 'release',
'identifier': rel_identifier,
'media_id': media.get('_id'),
'quality': quality.get('identifier'),
'status': 'available',
'last_edit': int(time.time()),
'info': {}
}
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:
try:
if not isinstance(rel[info], (str, unicode, int, long, float)):
continue
rls_info = ReleaseInfo(
identifier = info,
value = toUnicode(rel[info])
)
rls.info.append(rls_info)
rls['info'][info] = toUnicode(rel[info])
except InterfaceError:
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
except:
log.error('Failed: %s', traceback.format_exc())
db.rollback()
finally:
pass #db.close()
return []

View File

@@ -45,7 +45,7 @@ class Renamer(Plugin):
addEvent('renamer.scan', self.scan)
addEvent('renamer.check_snatched', self.checkSnatched)
addEvent('app.load2', self.scan)
addEvent('app.load', self.scan)
addEvent('app.load', self.setCrons)
# Enable / disable interval
@@ -222,23 +222,20 @@ class Renamer(Plugin):
remove_files = []
remove_releases = []
movie_title = getTitle(group['library'])
movie_title = getTitle(group)
# 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')
continue
# Rename the files using the library data
else:
group['library'] = fireEvent('library.update.movie', identifier = group['library']['identifier'], single = True)
if not group['library']:
group['media'] = fireEvent('movie.update_info', identifier = group['media']['identifier'], single = True)
if not group['media']:
log.error('Could not rename, no library item to work with: %s', group_identifier)
continue
library = group['library']
library_ent = db.query(Library).filter_by(identifier = group['library']['identifier']).first()
movie_title = getTitle(library)
movie_title = getTitle(group['media'])
# Overwrite destination when set in category
destination = to_folder
@@ -419,19 +416,19 @@ class Renamer(Plugin):
# Add it to the wanted list before we continue
if len(library_ent.movies) == 0:
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()
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:
# Mark movie "done" once it's found the quality with the finish check
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:
if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish:
movie.status_id = done_status.get('id')
movie.last_edit = int(time.time())
movie['status'] = 'done'
movie['last_edit'] = int(time.time())
db.commit()
except Exception as e:
log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))
@@ -441,7 +438,7 @@ class Renamer(Plugin):
for release in movie.releases:
# 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
if release.quality.order > group['meta_data']['quality']['order']:
@@ -470,7 +467,7 @@ class Renamer(Plugin):
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['rls_id'] == release.id:
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
break
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'])
found_release = True
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':
#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']))
# Remove the downloading tag

View File

@@ -5,7 +5,7 @@ from couchpotato.core.helpers.variable import getExt, getImdb, tryInt, \
splitString
from couchpotato.core.logger import CPLog
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 guessit import guess_movie_info
from subliminal.videos import Video
@@ -417,13 +417,11 @@ class Scanner(Plugin):
del group['unsorted_files']
# Determine movie
group['library'] = self.determineMovie(group, release_download = release_download)
if not group['library']:
log.error('Unable to determine movie: %s', group['identifiers'])
group['media'] = self.determineMedia(group, release_download = release_download)
if not group['media']:
log.error('Unable to determine media: %s', group['identifiers'])
else:
movie = db.query(Media).filter_by(library_id = group['library']['id']).first()
group['movie_id'] = None if not movie else movie.id
db.expire_all()
group['identifier'] = group['media']['identifier']
processed_movies[identifier] = group
@@ -554,7 +552,7 @@ class Scanner(Plugin):
return detected_languages
def determineMovie(self, group, release_download = None):
def determineMedia(self, group, release_download = None):
# Get imdb id from downloader
imdb_id = release_download and release_download.get('imdb_id')

View File

@@ -24,11 +24,11 @@ class Score(Plugin):
try: preferred_words = removeDuplicate(preferred_words + splitString(movie['category']['preferred'].lower()))
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']:
score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title['title']))
score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title['title']))
for movie_title in movie['info']['titles']:
score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title))
score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title))
score += sizeScore(nzb['size'])
@@ -44,7 +44,7 @@ class Score(Plugin):
score += providerScore(nzb['provider'])
# Duplicates in name
score += duplicateScore(nzb['name'], getTitle(movie['library']))
score += duplicateScore(nzb['name'], getTitle(movie))
# Merge global and category
ignored_words = splitString(Env.setting('ignored_words', section = 'searcher').lower())
@@ -52,7 +52,7 @@ class Score(Plugin):
except: pass
# 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
score += halfMultipartScore(nzb['name'])

View File

@@ -25,14 +25,13 @@ class Subtitle(Plugin):
db = get_session()
library = db.query(Library).all()
done_status = fireEvent('status.get', 'done', single = True)
for movie in library.movies:
for release in movie.releases:
# get releases and their movie files
if release.status_id is done_status.get('id'):
if release.get('status') == 'done':
files = []
for file in release.files.filter(FileType.status.has(identifier = 'movie')).all():

View File

@@ -18,7 +18,7 @@ class Trailer(Plugin):
trailers = fireEvent('trailer.search', group = group, merge = True)
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
for trailer in trailers.get(self.conf('quality'), []):

View File

@@ -199,7 +199,7 @@ class YarrProvider(Provider):
self._search(movie, quality, results)
# Search possible titles
else:
for title in possibleTitles(getTitle(movie['library'])):
for title in possibleTitles(getTitle(movie)):
self._searchOnTitle(title, movie, quality, results)
return results

View File

@@ -1,9 +1,9 @@
from couchpotato import get_session
from couchpotato.core.event import addEvent, fireEvent
from CodernityDB.database import RecordNotFound
from couchpotato import get_db
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.variable import mergeDicts, randomString
from couchpotato.core.logger import CPLog
from couchpotato.core.plugins.base import Plugin
from couchpotato.core.settings.model import Library
import copy
import traceback
@@ -86,25 +86,26 @@ class MovieResultModifier(Plugin):
}
# Add release info from current library
db = get_session()
db = get_db()
try:
l = db.query(Library).filter_by(identifier = imdb).first()
if l:
# Statuses
active_status, done_status = fireEvent('status.get', ['active', 'done'], single = True)
media = None
try:
media = db.get('media', imdb, with_doc = True)['doc']
except RecordNotFound:
pass
for movie in l.movies:
if movie.status_id == active_status['id']:
temp['in_wanted'] = fireEvent('media.get', movie.id, single = True)
if media:
for release in movie.releases:
if release.status_id == done_status['id']:
temp['in_library'] = fireEvent('media.get', movie.id, single = True)
if media.get('status') == 'active':
temp['in_wanted'] = media
for release in db.get_many('release', media.get('_id'), with_doc = True):
if release.get('status') == 'done':
temp['in_library'] = media
except:
log.error('Tried getting more info on searched movies: %s', traceback.format_exc())
pass #db.close()
return temp
def checkLibrary(self, result):

View File

@@ -26,9 +26,11 @@ class CouchPotatoApi(MovieProvider):
def __init__(self):
addEvent('movie.info', self.getInfo, priority = 1)
addEvent('movie.info.release_date', self.getReleaseDate)
addEvent('info.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.is_movie', self.isMovie)

View File

@@ -12,8 +12,6 @@ log = CPLog(__name__)
class TheMovieDb(MovieProvider):
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_by_tmdb', self.getInfo)

View File

@@ -25,8 +25,7 @@ class MetaDataBase(Plugin):
# Update library to get latest info
try:
updated_library = fireEvent('library.update.movie', group['library']['identifier'], extended = True, single = True)
group['library'] = mergeDicts(group['library'], updated_library)
group['media'] = fireEvent('movie.update_info', group['media']['identifier'], extended = True, single = True)
except:
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)
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']:
try:
@@ -96,13 +95,13 @@ class MetaDataBase(Plugin):
break
# 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')):
return cur_file.get('path')
# Download using existing info
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)
return file_path
except:

View File

@@ -30,21 +30,21 @@ class XBMC(MetaDataBase):
# return imdb 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')
# Title
try:
el = SubElement(nfoxml, 'title')
el.text = toUnicode(getTitle(data['library']))
el.text = toUnicode(getTitle(data))
except:
pass
# IMDB id
try:
el = SubElement(nfoxml, 'id')
el.text = toUnicode(data['library']['identifier'])
el.text = toUnicode(data['identifier'])
except:
pass

View File

@@ -23,7 +23,7 @@ class BinSearch(NZBProvider):
def _search(self, movie, quality, results):
arguments = tryUrlencode({
'q': movie['library']['identifier'],
'q': movie['identifier'],
'm': 'n',
'max': 400,
'adv_age': Env.setting('retention', 'nzb'),

View File

@@ -43,7 +43,7 @@ class Newznab(NZBProvider, RSS):
def _searchOnHost(self, host, movie, quality, results):
arguments = tryUrlencode({
'imdbid': movie['library']['identifier'].replace('tt', ''),
'imdbid': movie['identifier'].replace('tt', ''),
'apikey': host['api_key'],
'extended': 1
}) + ('&%s' % host['custom_tag'] if host.get('custom_tag') else '')

View File

@@ -20,7 +20,7 @@ class NZBClub(NZBProvider, RSS):
def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s"' % (title, movie['library']['year'])
q = '"%s %s"' % (title, movie['info']['year'])
params = tryUrlencode({
'q': q,

View File

@@ -23,7 +23,7 @@ class NzbIndex(NZBProvider, RSS):
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({
'q': q,
'age': Env.setting('retention', 'nzb'),

View File

@@ -37,7 +37,7 @@ class OMGWTFNZBs(NZBProvider, RSS):
def _searchOnTitle(self, title, movie, quality, results):
q = '%s %s' % (title, movie['library']['year'])
q = '%s %s' % (title, movie['info']['year'])
params = tryUrlencode({
'search': q,
'catid': ','.join([str(x) for x in self.getCatId(quality['identifier'])]),

View File

@@ -20,7 +20,7 @@ class AwesomeHD(TorrentProvider):
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:
try:

View File

@@ -26,7 +26,7 @@ class BiTHDTV(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results):
arguments = tryUrlencode({
'search': '%s %s' % (title.replace(':', ''), movie['library']['year']),
'search': '%s %s' % (title.replace(':', ''), movie['info']['year']),
'cat': self.cat_id_movies
})

View File

@@ -22,7 +22,7 @@ class Bitsoup(TorrentProvider):
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({
'search': q,
})

View File

@@ -43,7 +43,7 @@ class HDBits(TorrentProvider):
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)})

View File

@@ -38,7 +38,7 @@ class ILoveTorrents(TorrentProvider):
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])
page += 1

View File

@@ -36,7 +36,7 @@ class IPTorrents(TorrentProvider):
current_page = 1
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)
if data:

View File

@@ -36,7 +36,7 @@ class KickAssTorrents(TorrentMagnetProvider):
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:

View File

@@ -56,13 +56,13 @@ class PassThePopcorn(TorrentProvider):
def _search(self, movie, quality, results):
movie_title = getTitle(movie['library'])
movie_title = getTitle(movie)
quality_id = quality['identifier']
params = mergeDicts(self.quality_search_params[quality_id].copy(), {
'order_by': 'relevance',
'order_way': 'descending',
'searchstr': movie['library']['identifier']
'searchstr': movie['identifier']
})
url = '%s?json=noredirect&%s' % (self.urls['torrent'], tryUrlencode(params))

View File

@@ -30,7 +30,7 @@ class PublicHD(TorrentMagnetProvider):
params = tryUrlencode({
'page':'torrents',
'search': '%s %s' % (title, movie['library']['year']),
'search': '%s %s' % (title, movie['info']['year']),
'active': 1,
})

View File

@@ -39,7 +39,7 @@ class SceneAccess(TorrentProvider):
)
arguments = tryUrlencode({
'search': movie['library']['identifier'],
'search': movie['identifier'],
'method': 1,
})
url = "%s&%s" % (url, arguments)

View File

@@ -50,7 +50,7 @@ class ThePirateBay(TorrentMagnetProvider):
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
data = self.getHTMLData(search_url)

View File

@@ -34,7 +34,7 @@ class TorrentBytes(TorrentProvider):
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)
if data:

View File

@@ -27,7 +27,7 @@ class TorrentDay(TorrentProvider):
def _searchOnTitle(self, title, movie, quality, results):
q = '"%s %s"' % (title, movie['library']['year'])
q = '"%s %s"' % (title, movie['info']['year'])
data = {
'/browse.php?': None,

View File

@@ -35,7 +35,7 @@ class TorrentLeech(TorrentProvider):
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)
if data:

View File

@@ -35,7 +35,7 @@ class TorrentPotato(TorrentProvider):
arguments = tryUrlencode({
'user': host['name'],
'passkey': host['pass_key'],
'imdbid': movie['library']['identifier']
'imdbid': movie['identifier']
})
url = '%s?%s' % (host['host'], arguments)

View File

@@ -34,7 +34,7 @@ class TorrentShack(TorrentProvider):
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)
if data:

View File

@@ -33,7 +33,7 @@ class Yify(TorrentMagnetProvider):
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)

View File

@@ -20,11 +20,11 @@ class HDTrailers(TrailerProvider):
def search(self, group):
movie_name = getTitle(group['library'])
movie_name = getTitle(group)
url = self.urls['api'] % self.movieUrlName(movie_name)
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:
log.debug('No page found for: %s', movie_name)
data = None
@@ -50,11 +50,11 @@ class HDTrailers(TrailerProvider):
def findViaAlternative(self, group):
results = {'480p':[], '720p':[], '1080p':[]}
movie_name = getTitle(group['library'])
movie_name = getTitle(group)
url = "%s?%s" % (self.urls['backup'], tryUrlencode({'s':movie_name}))
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:
log.debug('No alternative page found for: %s', movie_name)
data = None

View File

@@ -5,7 +5,6 @@ from couchpotato.core.event import addEvent, fireEvent
from couchpotato.core.helpers.encoding import toUnicode
from couchpotato.core.helpers.variable import mergeDicts, tryInt, tryFloat
from couchpotato.core.settings.index import PropertyIndex
from couchpotato.core.settings.model import Properties
import ConfigParser
@@ -247,7 +246,7 @@ class Settings(object):
db.update(p['doc'])
except:
db.insert({
'type': 'property',
'_t': 'property',
'identifier': identifier,
'value': toUnicode(value),
})

View File

@@ -5,12 +5,12 @@ from hashlib import md5
class PropertyIndex(HashIndex):
def __init__(self, *args, **kwargs):
kwargs['key_format'] = '16s'
kwargs['key_format'] = '32s'
super(PropertyIndex, self).__init__(*args, **kwargs)
def make_key(self, key):
return md5(key).digest()
return md5(key).hexdigest()
def make_key_value(self, data):
if data.get('type') == 'property':
return md5(data['identifier']).digest(), None
if data.get('_t') == 'property':
return md5(data['identifier']).hexdigest(), None

View File

@@ -223,9 +223,9 @@ def runCouchPotato(options, base_path, args, data_dir = None, log_dir = None, En
loader.run()
# Fill database with needed stuff
fireEvent('database.setup')
if not db_exists:
fireEvent('app.initialize', in_order = True)
fireEvent('database.setup')
# Go go go!
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
try: log.info('Starting server on port %(port)s', config)
except: pass
fireEventAsync('app.load2')
fireEventAsync('app.load')
if config['ssl_cert'] and config['ssl_key']:
server = HTTPServer(application, no_keep_alive = True, ssl_options = {

View File

@@ -69,8 +69,6 @@
'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)) }});
App.setup({