diff --git a/couchpotato/core/media/show/_base/main.py b/couchpotato/core/media/show/_base/main.py index 2e0146d3..1e43a225 100644 --- a/couchpotato/core/media/show/_base/main.py +++ b/couchpotato/core/media/show/_base/main.py @@ -86,7 +86,8 @@ class ShowBase(MediaBase): # Can we make a base function to do this stuff? # Remove season info for later use (save separately) - season_info = info.get('seasons', {}) + seasons_info = info.get('seasons', {}) + identifiers = info.get('identifiers', {}) # Make sure we don't nest in_wanted data del info['identifiers'] @@ -103,7 +104,7 @@ class ShowBase(MediaBase): new = False try: - m = db.run('media', 'identifiers', params.get('identifiers'), with_doc = True)['doc'] + m = fireEvent('media.with_identifiers', params.get('identifiers'), with_doc = True, single = True)['doc'] except: new = True m = db.insert(media) @@ -124,7 +125,7 @@ class ShowBase(MediaBase): elif force_readd: # Clean snatched history - for release in db.run('release', 'for_media', m['_id']): + for release in fireEvent('release.for_media', m['_id'], single = True): if release.get('status') in ['downloaded', 'snatched', 'done']: if params.get('ignore_previous', False): release['status'] = 'ignored' @@ -147,19 +148,32 @@ class ShowBase(MediaBase): # Trigger update info if added and update_after: # Do full update to get images etc - fireEventAsync('show.update_info', m['_id'], on_complete = onComplete) + fireEventAsync('show.update_info', m['_id'], info = info, on_complete = onComplete) # Remove releases - for rel in db.run('release', 'for_media', m['_id']): + for rel in fireEvent('release.for_media', m['_id'], single = True): if rel['status'] is 'available': db.delete(rel) - movie_dict = db.run('media', 'to_dict', m['_id']) + movie_dict = fireEvent('media.get', m['_id'], single = True) if do_search and search_after: onComplete = self.createOnComplete(m['_id']) onComplete() + # Add Seasons + for season_nr in seasons_info: + + season_info = seasons_info[season_nr] + season = fireEvent('show.season.add', media.get('_id'), season_info, single = True) + + # Add Episodes + for episode_nr in season_info.get('episodes', {}): + + episode_info = season_info['episodes'][episode_nr] + fireEvent('show.episode.add', season.get('_id'), episode_info, single = True) + + if added and notify_after: if params.get('title'): @@ -170,22 +184,17 @@ class ShowBase(MediaBase): message = 'Successfully added "%s" to your wanted list.' % title else: message = 'Successfully added to your wanted list.' - fireEvent('notify.frontend', type = 'movie.added', data = movie_dict, message = message) + fireEvent('notify.frontend', type = 'show.added', data = movie_dict, message = message) + return movie_dict except: log.error('Failed adding media: %s', traceback.format_exc()) - # Add Seasons - for season_info in info.get('seasons', []): + def updateInfo(self, media_id = None, identifiers = None, info = None): + if not info: info = {} + if not identifiers: identifiers = {} - season = fireEvent('show.season.add', media.get('_id'), season_info) - - for episode_info in season_info.get('seasons', []): - - fireEvent('show.episode.add', season.get('_id'), episode_info) - - def updateInfo(self, media_id = None, identifiers = None): """ Update movie information inside media['doc']['info'] @@ -211,9 +220,14 @@ class ShowBase(MediaBase): else: media = db.get('media', identifiers, with_doc = True)['doc'] - info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True) + if not info: + info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True) # Don't need those here + try: del info['seasons'] + except: pass + try: del info['identifiers'] + except: pass try: del info['in_wanted'] except: pass try: del info['in_library'] diff --git a/couchpotato/core/media/show/episode.py b/couchpotato/core/media/show/episode.py index d7110159..db5ff288 100644 --- a/couchpotato/core/media/show/episode.py +++ b/couchpotato/core/media/show/episode.py @@ -1,15 +1,16 @@ -from couchpotato.core.event import addEvent, fireEvent +from couchpotato import get_db +from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.helpers.encoding import toUnicode from couchpotato.core.logger import CPLog from couchpotato.core.helpers.variable import tryInt -from couchpotato.core.plugins.base import Plugin +from couchpotato.core.media import MediaBase log = CPLog(__name__) -autload = 'Episode' +autoload = 'Episode' -class Episode(Plugin): +class Episode(MediaBase): def __init__(self): addEvent('media.search_query', self.query) @@ -18,53 +19,72 @@ class Episode(Plugin): addEvent('show.episode.add', self.add) addEvent('show.episode.update_info', self.updateInfo) - def add(self, parent_id, update_after = True): + def add(self, parent_id, info = None, update_after = True): + if not info: info = {} + + identifiers = info.get('identifiers') + try: del info['identifiers'] + except: pass # Add Season - season = { + episode_info = { '_t': 'media', 'type': 'episode', - 'nr': 1, - 'identifiers': { - 'imdb': 'tt1234', - 'thetvdb': 123, - 'tmdb': 123, - 'rage': 123 - }, - 'parent': '_id', - 'info': {}, # Returned dict by providers + 'identifiers': identifiers, + 'parent': parent_id, + 'info': info, # Returned dict by providers } - episode_exists = True or False + # Check if season already exists + existing_episode = fireEvent('media.with_identifiers', identifiers, with_doc = True, single = True) - if episode_exists: - pass #update existing + db = get_db() + + if existing_episode: + s = existing_episode['doc'] + s.update(episode_info) + episode = db.update(s) else: - pass # Add Episode - + episode = db.insert(episode_info) # Update library info if update_after is not False: handle = fireEventAsync if update_after is 'async' else fireEvent - handle('show.episode.update_info', season.get('_id'), default_title = toUnicode(attrs.get('title', ''))) + handle('show.season.update_info', episode.get('_id'), info = info, single = True) - return season + return episode - def updateInfo(self, media_id = None, default_title = '', force = False): + def update_info(self, media_id = None, info = None, force = False): + if not info: info = {} if self.shuttingDown(): return + db = get_db() + + episode = db.get('id', media_id) + # Get new info - fireEvent('episode.info', merge = True) + if not info: + info = fireEvent('episode.info', episode.get('identifiers'), merge = True) # Update/create media + if force: + episode['identifiers'].update(info['identifiers']) + if 'identifiers' in info: + del info['identifiers'] + + episode.update({'info': info}) + e = db.update(episode) + episode.update(e) # Get images + image_urls = info.get('images', []) + existing_files = episode.get('files', {}) + self.getPoster(image_urls, existing_files) - - return info + return episode def query(self, library, first = True, condense = True, include_identifier = True, **kwargs): if library is list or library.get('type') != 'episode': diff --git a/couchpotato/core/media/show/providers/info/thetvdb.py b/couchpotato/core/media/show/providers/info/thetvdb.py index 706fff94..af0ded3a 100644 --- a/couchpotato/core/media/show/providers/info/thetvdb.py +++ b/couchpotato/core/media/show/providers/info/thetvdb.py @@ -118,7 +118,7 @@ class TheTVDb(ShowProvider): identifier = tryInt(identifiers.get('thetvdb')) cache_key = 'thetvdb.cache.show.%s' % identifier - result = self.getCache(cache_key) + result = None #self.getCache(cache_key) if result: return result @@ -253,15 +253,13 @@ class TheTVDb(ShowProvider): 'network': get('network'), 'plot': get('overview'), 'networkid': get('networkid'), - 'airs_dayofweek': get('airs_dayofweek'), - 'airs_time': get('airs_time'), + 'air_day': (get('airs_dayofweek') or '').lower(), + 'air_time': self.parseTime(get('airs_time')), 'firstaired': get('firstaired'), - 'released': get('firstaired'), - 'runtime': get('runtime'), + 'runtime': tryInt(get('runtime')), 'contentrating': get('contentrating'), 'rating': {}, 'actors': splitString(get('actors'), '|'), - 'lastupdated': get('lastupdated'), 'status': get('status'), 'language': get('language'), } @@ -272,21 +270,16 @@ class TheTVDb(ShowProvider): show_data = dict((k, v) for k, v in show_data.iteritems() if v) # Parse season and episode data - seasons = {} - episodes = get('episodes') - if episodes: - for episode in episodes: - episode_nr = episode.get('nr') - episode_season = episode.get('season') + show_data['seasons'] = {} - # Create season - if seasons.get(episode_season): - seasons[episode_season] = { - 'episodes': {} - } + for season_nr in show: + season = self._parseSeason(show, season_nr, show[season_nr]) + season['episodes'] = {} - # Add episode information - seasons[episode_season]['episodes'][episode_nr] = self._parseEpisode(show, episode) + for episode_nr in show[season_nr]: + season['episodes'][episode_nr] = self._parseEpisode(show[season_nr][episode_nr]) + + show_data['seasons'][season_nr] = season # Add alternative titles # try: @@ -302,52 +295,36 @@ class TheTVDb(ShowProvider): return show_data - def _parseSeason(self, show, season_tuple): + def _parseSeason(self, show, number, season): """ contains no data """ - number, season = season_tuple - title = toUnicode('%s - Season %s' % (show['seriesname'] or u'', str(number))) poster = [] try: + temp_poster = {} for id, data in show.data['_banners']['season']['season'].items(): - if data.get('season', None) == str(number) and data['bannertype'] == 'season' and data['bannertype2'] == 'season': - poster.append(data.get('_bannerpath')) - break # Only really need one + if data.get('season') == str(number) and data.get('language') == self.tvdb_api_parms['language']: + temp_poster[tryFloat(data.get('rating')) * tryInt(data.get('ratingcount'))] = data.get('_bannerpath') + #break + poster.append(temp_poster[sorted(temp_poster, reverse = True)[0]]) except: pass - try: - id = (show['id'] + ':' + str(number)) - except: - id = None - - # XXX: work on title; added defualt_title to fix an error season_data = { - 'id': id, - 'type': 'season', - 'primary_provider': 'thetvdb', - 'titles': [title, ], - 'original_title': title, - 'via_thetvdb': True, - 'parent_identifier': show['id'] or None, - 'seasonnumber': str(number), + 'identifiers': { + 'thetvdb': show[number][1]['seasonid'] + }, + 'number': number, 'images': { 'poster': poster, - 'backdrop': [], - 'poster_original': [], - 'backdrop_original': [], }, - 'year': None, - 'genres': None, - 'imdb': None, } season_data = dict((k, v) for k, v in season_data.iteritems() if v) return season_data - def _parseEpisode(self, show, episode): + def _parseEpisode(self, episode): """ ('episodenumber', u'1'), ('thumb_added', None), @@ -383,86 +360,36 @@ class TheTVDb(ShowProvider): ('episodename', u'Pilot')] """ - poster = episode.get('filename', []) - backdrop = [] - genres = [] - plot = "%s - %sx%s - %s" % (show['seriesname'] or u'', - episode.get('seasonnumber', u'?'), - episode.get('episodenumber', u'?'), - episode.get('overview', u'')) - if episode.get('firstaired', None) is not None: - try: year = datetime.strptime(episode['firstaired'], '%Y-%m-%d').year - except: year = None - else: - year = None + def get(name, default = None): + return episode.get(name, default) - try: - id = int(episode['id']) - except: - id = None + poster = get('filename', []) episode_data = { - 'id': id, + 'number': get('episodenumber'), + 'absolute_number': get('absolute_number'), + 'identifiers': { + 'thetvdb': tryInt(episode['id']) + }, 'type': 'episode', - 'primary_provider': 'thetvdb', - 'via_thetvdb': True, - 'thetvdb_id': id, - 'titles': [episode.get('episodename', u''), ], - 'original_title': episode.get('episodename', u'') , + 'titles': [get('episodename')] if get('episodename') else [], 'images': { 'poster': [poster] if poster else [], - 'backdrop': [backdrop] if backdrop else [], - 'poster_original': [], - 'backdrop_original': [], }, - 'imdb': episode.get('imdb_id', None), - 'runtime': None, - 'released': episode.get('firstaired', None), - 'year': year, - 'plot': plot, - 'genres': genres, - 'parent_identifier': show['id'] or None, - 'seasonnumber': episode.get('seasonnumber', None), - 'episodenumber': episode.get('episodenumber', None), - 'combined_episodenumber': episode.get('combined_episodenumber', None), - 'absolute_number': episode.get('absolute_number', None), - 'combined_season': episode.get('combined_season', None), - 'productioncode': episode.get('productioncode', None), - 'seriesid': episode.get('seriesid', None), - 'seasonid': episode.get('seasonid', None), - 'firstaired': episode.get('firstaired', None), - 'thumb_added': episode.get('thumb_added', None), - 'thumb_height': episode.get('thumb_height', None), - 'thumb_width': episode.get('thumb_width', None), - 'rating': episode.get('rating', None), - 'ratingcount': episode.get('ratingcount', None), - 'epimgflag': episode.get('epimgflag', None), - 'dvd_episodenumber': episode.get('dvd_episodenumber', None), - 'dvd_discid': episode.get('dvd_discid', None), - 'dvd_chapter': episode.get('dvd_chapter', None), - 'dvd_season': episode.get('dvd_season', None), - 'tms_export': episode.get('tms_export', None), - 'writer': episode.get('writer', None), - 'director': episode.get('director', None), - 'gueststars': episode.get('gueststars', None), - 'lastupdated': episode.get('lastupdated', None), - 'language': episode.get('language', None), + 'released': get('firstaired'), + 'plot': get('overview'), + 'firstaired': get('firstaired'), + 'language': get('language'), } + if get('imdb_id'): + episode_data['identifiers']['imdb'] = get('imdb_id') + episode_data = dict((k, v) for k, v in episode_data.iteritems() if v) return episode_data - #def getImage(self, show, type = 'poster', size = 'cover'): - #"""""" - ## XXX: Need to implement size - #image_url = '' - - #for res, res_data in show['_banners'].get(type, {}).items(): - #for bid, banner_info in res_data.items(): - #image_url = banner_info.get('_bannerpath', '') - #break - - #return image_url + def parseTime(self, time): + return time def isDisabled(self): if self.conf('api_key') == '': diff --git a/couchpotato/core/media/show/searcher.py b/couchpotato/core/media/show/searcher.py index 87232aa9..aab7ee9f 100644 --- a/couchpotato/core/media/show/searcher.py +++ b/couchpotato/core/media/show/searcher.py @@ -1,4 +1,4 @@ -from couchpotato import Env, get_session +from couchpotato import Env from couchpotato.core.event import addEvent, fireEvent from couchpotato.core.helpers.variable import getTitle, toIterable from couchpotato.core.logger import CPLog @@ -31,8 +31,6 @@ class ShowSearcher(SearcherBase, ShowTypeBase): def single(self, media, search_protocols = None, manual = False): show, season, episode = self.getLibraries(media['library']) - db = get_session() - if media['type'] == 'show': for library in season: # TODO ideally we shouldn't need to fetch the media for each season library here diff --git a/couchpotato/core/media/show/season.py b/couchpotato/core/media/show/season.py index c7aca946..2f248763 100644 --- a/couchpotato/core/media/show/season.py +++ b/couchpotato/core/media/show/season.py @@ -1,71 +1,90 @@ -from couchpotato.core.event import addEvent, fireEvent +from couchpotato import get_db +from couchpotato.core.event import addEvent, fireEvent, fireEventAsync from couchpotato.core.logger import CPLog from couchpotato.core.helpers.variable import tryInt -from couchpotato.core.plugins.base import Plugin +from couchpotato.core.media import MediaBase log = CPLog(__name__) -autload = 'Season' +autoload = 'Season' -class Season(Plugin): +class Season(MediaBase): def __init__(self): addEvent('media.search_query', self.query) addEvent('media.identifier', self.identifier) - addEvent('show.season.add', self.update) - addEvent('show.season.update_info', self.update) + addEvent('show.season.add', self.add) + addEvent('show.season.update_info', self.update_info) - def add(self, parent_id, update_after = True): + def add(self, parent_id, info = None, update_after = True): + if not info: info = {} + + identifiers = info.get('identifiers') + try: del info['identifiers'] + except: pass # Add Season - season = { + season_info = { '_t': 'media', 'type': 'season', - 'nr': 1, - 'identifiers': { - 'imdb': 'tt1234', - 'thetvdb': 123, - 'tmdb': 123, - 'rage': 123 - }, - 'parent': '_id', - 'info': {}, # Returned dict by providers + 'identifiers': identifiers, + 'parent': parent_id, + 'info': info, # Returned dict by providers } # Check if season already exists - season_exists = True or False + existing_season = fireEvent('media.with_identifiers', identifiers, with_doc = True, single = True) - if season_exists: - pass #update existing + db = get_db() + + if existing_season: + s = existing_season['doc'] + s.update(season_info) + season = db.update(s) else: - - db.insert(season) - + season = db.insert(season_info) # Update library info if update_after is not False: handle = fireEventAsync if update_after is 'async' else fireEvent - handle('show.season.update_info', episode.get('_id')) + handle('show.season.update_info', season.get('_id'), info = info, single = True) return season - def update_info(self, media_id = None, default_title = '', force = False): + def update_info(self, media_id = None, info = None, force = False): + if not info: info = {} if self.shuttingDown(): return + db = get_db() + + season = db.get('id', media_id) + # Get new info - fireEvent('season.info', merge = True) + if not info: + info = fireEvent('season.info', season.get('identifiers'), merge = True) # Update/create media + if force: + + season['identifiers'].update(info['identifiers']) + if 'identifiers' in info: + del info['identifiers'] + + season.update({'info': info}) + s = db.update(season) + season.update(s) # Get images + image_urls = info.get('images', []) + existing_files = season.get('files', {}) + self.getPoster(image_urls, existing_files) - - return info + return season def query(self, library, first = True, condense = True, include_identifier = True, **kwargs): if library is list or library.get('type') != 'season':