diff --git a/couchpotato/core/media/_base/media/main.py b/couchpotato/core/media/_base/media/main.py index 480b571..af12bfb 100644 --- a/couchpotato/core/media/_base/media/main.py +++ b/couchpotato/core/media/_base/media/main.py @@ -124,7 +124,7 @@ class MediaPlugin(MediaBase): if refresh_handler: handlers.append(refresh_handler) - fireEvent('notify.frontend', type = 'media.busy', data = {'id': ids}) + fireEvent('notify.frontend', type = 'media.busy', data = {'_id': ids}) fireEventAsync('schedule.queue', handlers = handlers) return { @@ -266,7 +266,7 @@ class MediaPlugin(MediaBase): def listView(self, **kwargs): - types = splitString(kwargs.get('types')) + types = splitString(kwargs.get('type')) status = splitString(kwargs.get('status')) release_status = splitString(kwargs.get('release_status')) limit_offset = kwargs.get('limit_offset') diff --git a/couchpotato/core/media/movie/_base/static/movie.actions.js b/couchpotato/core/media/movie/_base/static/movie.actions.js index 50548cc..4152d82 100644 --- a/couchpotato/core/media/movie/_base/static/movie.actions.js +++ b/couchpotato/core/media/movie/_base/static/movie.actions.js @@ -121,7 +121,7 @@ MA.Release = new Class({ } }); - if(self.movie.data.releases.length == 0) + if(!self.movie.data.releases || self.movie.data.releases.length == 0) self.el.hide() else self.showHelper(); @@ -166,92 +166,93 @@ MA.Release = new Class({ new Element('span.provider', {'text': 'Provider'}) ).inject(self.release_container) - self.movie.data.releases.each(function(release){ + if(self.movie.data.releases) + self.movie.data.releases.each(function(release){ + + var quality = Quality.getQuality(release.quality) || {}, + info = release.info, + provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : ''); - var quality = Quality.getQuality(release.quality) || {}, - info = release.info, - provider = self.get(release, 'provider') + (release.info['provider_extra'] ? self.get(release, 'provider_extra') : ''); - - var release_name = self.get(release, 'name'); - if(release.files && release.files.length > 0){ - try { - var movie_file = release.files.filter(function(file){ - var type = File.Type.get(file.type_id); - return type && type.identifier == 'movie' - }).pick(); - release_name = movie_file.path.split(Api.getOption('path_sep')).getLast(); + var release_name = self.get(release, 'name'); + if(release.files && release.files.length > 0){ + try { + var movie_file = release.files.filter(function(file){ + var type = File.Type.get(file.type_id); + return type && type.identifier == 'movie' + }).pick(); + release_name = movie_file.path.split(Api.getOption('path_sep')).getLast(); + } + catch(e){} } - catch(e){} - } - // Create release - var item = new Element('div', { - 'class': 'item '+release.status, - 'id': 'release_'+release._id - }).adopt( - new Element('span.name', {'text': release_name, 'title': release_name}), - new Element('span.status', {'text': release.status, 'class': 'release_status '+release.status}), - new Element('span.quality', {'text': quality.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')}), - new Element('span.score', {'text': self.get(release, 'score')}), - new Element('span.provider', { 'text': provider, 'title': provider }), - release.info['detail_url'] ? new Element('a.info.icon2', { - 'href': release.info['detail_url'], - 'target': '_blank' - }) : new Element('a'), - new Element('a.download.icon2', { - 'events': { - 'click': function(e){ - (e).preventDefault(); - if(!this.hasClass('completed')) - self.download(release); + // Create release + var item = new Element('div', { + 'class': 'item '+release.status, + 'id': 'release_'+release._id + }).adopt( + new Element('span.name', {'text': release_name, 'title': release_name}), + new Element('span.status', {'text': release.status, 'class': 'release_status '+release.status}), + new Element('span.quality', {'text': quality.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')}), + new Element('span.score', {'text': self.get(release, 'score')}), + new Element('span.provider', { 'text': provider, 'title': provider }), + release.info['detail_url'] ? new Element('a.info.icon2', { + 'href': release.info['detail_url'], + 'target': '_blank' + }) : new Element('a'), + new Element('a.download.icon2', { + 'events': { + 'click': function(e){ + (e).preventDefault(); + if(!this.hasClass('completed')) + self.download(release); + } } - } - }), - new Element('a.delete.icon2', { - 'events': { - 'click': function(e){ - (e).preventDefault(); - self.ignore(release); + }), + new Element('a.delete.icon2', { + 'events': { + 'click': function(e){ + (e).preventDefault(); + self.ignore(release); + } } - } - }) - ).inject(self.release_container); - release['el'] = item; + }) + ).inject(self.release_container); + release['el'] = item; - if(release.status == 'ignored' || release.status == 'failed' || release.status == 'snatched'){ - if(!self.last_release || (self.last_release && self.last_release.status != 'snatched' && release.status == 'snatched')) - self.last_release = release; - } - else if(!self.next_release && release.status == 'available'){ - self.next_release = release; - } + if(release.status == 'ignored' || release.status == 'failed' || release.status == 'snatched'){ + if(!self.last_release || (self.last_release && self.last_release.status != 'snatched' && release.status == 'snatched')) + self.last_release = release; + } + else if(!self.next_release && release.status == 'available'){ + self.next_release = release; + } - var update_handle = function(notification) { - if(notification.data._id != release._id) return; + var update_handle = function(notification) { + if(notification.data._id != release._id) return; - var q = self.movie.quality.getElement('.q_' + release.quality), - new_status = notification.data.status; + var q = self.movie.quality.getElement('.q_' + release.quality), + new_status = notification.data.status; - release.el.set('class', 'item ' + new_status); + release.el.set('class', 'item ' + new_status); - var status_el = release.el.getElement('.release_status'); - status_el.set('class', 'release_status ' + new_status); - status_el.set('text', new_status); + var status_el = release.el.getElement('.release_status'); + status_el.set('class', 'release_status ' + new_status); + status_el.set('text', new_status); - if(!q && (new_status == 'snatched' || new_status == 'seeding' || new_status == 'done')) - var q = self.addQuality(release.quality_id); + if(!q && (new_status == 'snatched' || new_status == 'seeding' || new_status == 'done')) + var q = self.addQuality(release.quality_id); - if(q && !q.hasClass(new_status)) { - q.removeClass(release.status).addClass(new_status); - q.set('title', q.get('title').replace(release.status, new_status)); + if(q && !q.hasClass(new_status)) { + q.removeClass(release.status).addClass(new_status); + q.set('title', q.get('title').replace(release.status, new_status)); + } } - } - App.on('release.update_status', update_handle); + App.on('release.update_status', update_handle); - }); + }); if(self.last_release) self.release_container.getElements('#release_'+self.last_release._id).addClass('last_release'); @@ -314,16 +315,17 @@ MA.Release = new Class({ var has_available = false, has_snatched = false; - self.movie.data.releases.each(function(release){ - if(has_available && has_snatched) return; + if(self.movie.data.releases) + self.movie.data.releases.each(function(release){ + if(has_available && has_snatched) return; - if(['snatched', 'downloaded', 'seeding'].contains(release.status)) - has_snatched = true; + if(['snatched', 'downloaded', 'seeding'].contains(release.status)) + has_snatched = true; - if(['available'].contains(release.status)) - has_available = true; + if(['available'].contains(release.status)) + has_available = true; - }); + }); if(has_available || has_snatched){ @@ -698,7 +700,7 @@ MA.Readd = new Class({ var self = this; var movie_done = self.movie.data.status == 'done'; - if(!movie_done) + if(self.movie.data.releases && !movie_done) var snatched = self.movie.data.releases.filter(function(release){ return release.status && (release.status == 'snatched' || release.status == 'downloaded' || release.status == 'done'); }).length; @@ -832,15 +834,7 @@ MA.Files = new Class({ }, - show: function(e){ - var self = this; - (e).preventDefault(); - - self.showFiles(); - - }, - - showFiles: function(){ + show: function(){ var self = this; if(!self.options_container){ @@ -851,26 +845,26 @@ MA.Files = new Class({ // Header new Element('div.item.head').adopt( new Element('span.name', {'text': 'File'}), - new Element('span.type', {'text': 'Type'}), - new Element('span.is_available', {'text': 'Available'}) + new Element('span.type', {'text': 'Type'}) ).inject(self.files_container) - Array.each(self.releases, function(release){ - - var rel = new Element('div.release').inject(self.files_container); + if(self.movie.data.releases) + Array.each(self.movie.data.releases, function(release){ + var rel = new Element('div.release').inject(self.files_container); - Array.each(release.files, function(file){ - new Element('div.file.item').adopt( - new Element('span.name', {'text': file.path}), - new Element('span.type', {'text': File.Type.get(file.type_id).name}), - new Element('span.available', {'text': file.available}) - ).inject(rel) + Object.each(release.files, function(files, type){ + Array.each(files, function(file){ + new Element('div.file.item').adopt( + new Element('span.name', {'text': file}), + new Element('span.type', {'text': type}) + ).inject(rel) + }); + }); }); - }); } self.movie.slide('in', self.options_container); - }, + } }); diff --git a/couchpotato/core/media/movie/_base/static/movie.js b/couchpotato/core/media/movie/_base/static/movie.js index 417f065..835847e 100644 --- a/couchpotato/core/media/movie/_base/static/movie.js +++ b/couchpotato/core/media/movie/_base/static/movie.js @@ -187,7 +187,7 @@ var Movie = new Class({ ) ); - if(self.thumbnail.empty) + if(!self.thumbnail || self.thumbnail.empty) self.el.addClass('no_thumbnail'); //self.changeView(self.view); diff --git a/couchpotato/core/media/movie/searcher/main.py b/couchpotato/core/media/movie/searcher/main.py index cecfd72..155390d 100644 --- a/couchpotato/core/media/movie/searcher/main.py +++ b/couchpotato/core/media/movie/searcher/main.py @@ -133,7 +133,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): fireEvent('media.delete', movie['_id'], single = True) return - fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'id': movie['_id']}, message = 'Searching for "%s"' % default_title) + fireEvent('notify.frontend', type = 'movie.searcher.started', data = {'_id': movie['_id']}, message = 'Searching for "%s"' % default_title) db = get_db() @@ -200,7 +200,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase): if len(too_early_to_search) > 0: log.info2('Too early to search for %s, %s', (too_early_to_search, default_title)) - fireEvent('notify.frontend', type = 'movie.searcher.ended', data = {'id': movie['_id']}) + fireEvent('notify.frontend', type = 'movie.searcher.ended', data = {'_id': movie['_id']}) return ret diff --git a/couchpotato/core/notifications/core/static/notification.js b/couchpotato/core/notifications/core/static/notification.js index 756c41e..717fbf1 100644 --- a/couchpotato/core/notifications/core/static/notification.js +++ b/couchpotato/core/notifications/core/static/notification.js @@ -147,7 +147,7 @@ var NotificationBase = new Class({ // Process data if(json){ Array.each(json.result, function(result){ - App.trigger(result._t, [result]); + App.trigger(result._t || result.type, [result]); if(result.message && result.read === undefined) self.showMessage(result.message); }) diff --git a/couchpotato/core/plugins/manage/main.py b/couchpotato/core/plugins/manage/main.py index 2606500..65618b5 100644 --- a/couchpotato/core/plugins/manage/main.py +++ b/couchpotato/core/plugins/manage/main.py @@ -1,3 +1,4 @@ +from couchpotato import get_db from couchpotato.api import addApiView from couchpotato.core.event import fireEvent, addEvent, fireEventAsync from couchpotato.core.helpers.encoding import sp @@ -48,7 +49,6 @@ class Manage(Plugin): if not Env.get('dev') and self.conf('startup_scan'): addEvent('app.load', self.updateLibraryQuick) - addEvent('app.load', self.updateLibrary) def getProgress(self, **kwargs): return { @@ -125,32 +125,34 @@ class Manage(Plugin): fireEvent('media.delete', media_id = done_movie['id'], delete_from = 'all') else: - releases = fireEvent('release.for_movie', id = done_movie.get('_id'), single = True) + db = get_db() + releases = list(db.run('release', 'for_media', done_movie.get('_id'))) for release in releases: if len(release.get('files', [])) > 0: - for release_file in release.get('files', []): - # Remove release not available anymore - if not os.path.isfile(sp(release_file['path'])): - fireEvent('release.clean', release['id']) - break + for file_type in release.get('files', {}): + for release_file in release['files'][file_type]: + # Remove release not available anymore + if not os.path.isfile(sp(release_file)): + fireEvent('release.clean', release['_id']) + break # Check if there are duplicate releases (different quality) use the last one, delete the rest if len(releases) > 1: used_files = {} for release in releases: - - for release_file in release.get('files', []): - already_used = used_files.get(release_file['path']) - - if already_used: - if already_used < release['id']: - fireEvent('release.delete', release['id'], single = True) # delete this one + for file_type in release.get('files', {}): + for release_file in release['files'][file_type]: + already_used = used_files.get(release_file) + + if already_used: + if already_used.get('last_edit', 0) < release.get('last_edit', 0): + fireEvent('release.delete', release['_id'], single = True) # delete current one + else: + fireEvent('release.delete', already_used['_id'], single = True) # delete previous one + break else: - fireEvent('release.delete', already_used, single = True) # delete previous one - break - else: - used_files[release_file['path']] = release.get('id') + used_files[release_file] = release del used_files Env.prop('manage.last_update', time.time()) diff --git a/couchpotato/core/plugins/release/index.py b/couchpotato/core/plugins/release/index.py index 2629fc6..9317cc2 100644 --- a/couchpotato/core/plugins/release/index.py +++ b/couchpotato/core/plugins/release/index.py @@ -1,4 +1,5 @@ from hashlib import md5 +from CodernityDB.hash_index import HashIndex from CodernityDB.tree_index import TreeBasedIndex @@ -42,14 +43,13 @@ class ReleaseStatusIndex(TreeBasedIndex): return md5(data.get('status')).hexdigest(), {'media_id': data.get('media_id')} -class ReleaseIDIndex(TreeBasedIndex): +class ReleaseIDIndex(HashIndex): def __init__(self, *args, **kwargs): kwargs['key_format'] = '32s' super(ReleaseIDIndex, self).__init__(*args, **kwargs) def make_key(self, key): - print key return md5(key).hexdigest() def make_key_value(self, data): diff --git a/couchpotato/core/plugins/release/main.py b/couchpotato/core/plugins/release/main.py index 3623a1a..28ae8c3 100644 --- a/couchpotato/core/plugins/release/main.py +++ b/couchpotato/core/plugins/release/main.py @@ -111,41 +111,41 @@ class Release(Plugin): try: db = get_db() - identifier = '%s.%s.%s' % (group['identifier'], group['meta_data'].get('audio', 'unknown'), group['meta_data']['quality']['identifier']) + release_identifier = '%s.%s.%s' % (group['identifier'], group['meta_data'].get('audio', 'unknown'), group['meta_data']['quality']['identifier']) # Add movie if it doesn't exist try: media = db.get('media', group['identifier'], with_doc = True)['doc'] - media['status'] = 'done' - db.update(media) except: - media = { - '_t': 'media', + media = fireEvent('movie.add', params = { 'identifier': group['identifier'], 'profile_id': None, - 'status': 'done' - } - m = db.insert(media) - media.update(m) + }, search_after = False, status = 'done', single = True) # Add Release release = { '_t': 'release', 'media_id': media['_id'], - 'identifier': identifier, + 'identifier': release_identifier, 'quality': group['meta_data']['quality'].get('identifier'), + 'last_edit': int(time.time()), 'status': 'done' } try: - r = db.get('release_identifier', identifier, with_doc = True)['doc'] - release.update(r) - db.update(release) + r = db.get('release_identifier', release_identifier, with_doc = True)['doc'] + r['media_id'] = media['_id'] except: r = db.insert(release) - release.update(r) - # Add each file type + # Update with ref and _id + release.update({ + '_id': r['_id'], + '_rev': r['_rev'], + }) + + # Empty out empty file groups release['files'] = dict((k, v) for k, v in group['files'].items() if v) + db.update(release) fireEvent('media.restatus', media['_id']) @@ -307,7 +307,7 @@ class Release(Plugin): # Mark release as snatched if renamer_enabled: - self.updateStatus(rls.id, status = snatched_status) + self.updateStatus(rls.id, status = 'snatched') # If renamer isn't used, mark media done if finished or release downloaded else: @@ -318,7 +318,7 @@ class Release(Plugin): log.info('Renamer disabled, marking media as finished: %s', log_movie) # Mark release done - self.updateStatus(rls.id, status = done_status) + self.updateStatus(rls.id, status = 'done') # Mark media done mdia = db.query(Media).filter_by(id = media['id']).first() @@ -329,7 +329,7 @@ class Release(Plugin): return True # Assume release downloaded - self.updateStatus(rls.id, status = downloaded_status) + self.updateStatus(rls.id, status = 'downloaded') except: log.error('Failed storing download status: %s', traceback.format_exc()) diff --git a/couchpotato/core/plugins/renamer/main.py b/couchpotato/core/plugins/renamer/main.py index c26de9e..8cc14c9 100755 --- a/couchpotato/core/plugins/renamer/main.py +++ b/couchpotato/core/plugins/renamer/main.py @@ -472,14 +472,14 @@ class Renamer(Plugin): if release_download['rls_id'] == release.id: if release_download['status'] == 'completed': # Set the release to downloaded - fireEvent('release.update_status', release.id, status = downloaded_status, single = True) + fireEvent('release.update_status', release.id, status = 'downloaded', single = True) elif release_download['status'] == 'seeding': # Set the release to seeding - fireEvent('release.update_status', release.id, status = seeding_status, single = True) + fireEvent('release.update_status', release.id, status = 'seeding', single = True) elif release.quality.id is group['meta_data']['quality']['id']: # Set the release to downloaded - fireEvent('release.update_status', release.id, status = downloaded_status, single = True) + fireEvent('release.update_status', release.id, status = 'downloaded', single = True) # Remove leftover files if not remove_leftovers: # Don't remove anything diff --git a/couchpotato/runner.py b/couchpotato/runner.py index d6a967c..c79317a 100644 --- a/couchpotato/runner.py +++ b/couchpotato/runner.py @@ -13,7 +13,6 @@ from uuid import uuid4 import locale import logging import os.path -import shutil import sys import time import traceback