Merge branch 'tv_xem' into tv

This commit is contained in:
Dean Gardiner
2014-07-28 20:39:10 +12:00
16 changed files with 375 additions and 279 deletions
+8
View File
@@ -380,3 +380,11 @@ def getFreeSpace(directories):
free_space[folder] = size free_space[folder] = size
return free_space return free_space
def find(func, iterable):
for item in iterable:
if func(item):
return item
return None
+12 -5
View File
@@ -78,13 +78,18 @@ class Library(LibraryBase):
return cur return cur
def tree(self, media): def tree(self, media = None, media_id = None):
result = media
db = get_db() db = get_db()
if media:
result = media
elif media_id:
result = db.get('id', media_id, with_doc = True)
else:
return None
# Find children # Find children
items = db.get_many('media_children', media['_id'], with_doc = True) items = db.get_many('media_children', result['_id'], with_doc = True)
keys = [] keys = []
# Build children arrays # Build children arrays
@@ -94,6 +99,8 @@ class Library(LibraryBase):
if key not in result: if key not in result:
result[key] = {} result[key] = {}
elif type(result[key]) is not dict:
result[key] = {}
if key not in keys: if key not in keys:
keys.append(key) keys.append(key)
@@ -105,6 +112,6 @@ class Library(LibraryBase):
result[key] = result[key].values() result[key] = result[key].values()
# Include releases # Include releases
result['releases'] = fireEvent('release.for_media', media['_id'], single = True) result['releases'] = fireEvent('release.for_media', result['_id'], single = True)
return result return result
+9 -2
View File
@@ -109,7 +109,7 @@ class MediaPlugin(MediaBase):
try: try:
media = get_db().get('id', media_id) media = get_db().get('id', media_id)
event = '%s.update_info' % media.get('type') event = '%s.update' % media.get('type')
def handler(): def handler():
fireEvent(event, media_id = media_id, on_complete = self.createOnComplete(media_id)) fireEvent(event, media_id = media_id, on_complete = self.createOnComplete(media_id))
@@ -160,10 +160,13 @@ class MediaPlugin(MediaBase):
'media': media, 'media': media,
} }
def withStatus(self, status, with_doc = True): def withStatus(self, status, types = None, with_doc = True):
db = get_db() db = get_db()
if types and not isinstance(types, (list, tuple)):
types = [types]
status = list(status if isinstance(status, (list, tuple)) else [status]) status = list(status if isinstance(status, (list, tuple)) else [status])
for s in status: for s in status:
@@ -171,6 +174,10 @@ class MediaPlugin(MediaBase):
if with_doc: if with_doc:
try: try:
doc = db.get('id', ms['_id']) doc = db.get('id', ms['_id'])
if types and doc.get('type') not in types:
continue
yield doc yield doc
except RecordNotFound: except RecordNotFound:
log.debug('Record not found, skipping: %s', ms['_id']) log.debug('Record not found, skipping: %s', ms['_id'])
+4 -4
View File
@@ -46,7 +46,7 @@ class MovieBase(MovieTypeBase):
}) })
addEvent('movie.add', self.add) addEvent('movie.add', self.add)
addEvent('movie.update_info', self.updateInfo) addEvent('movie.update', self.update)
addEvent('movie.update_release_dates', self.updateReleaseDate) addEvent('movie.update_release_dates', self.updateReleaseDate)
def add(self, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None): def add(self, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None):
@@ -172,7 +172,7 @@ class MovieBase(MovieTypeBase):
# Trigger update info # Trigger update info
if added and update_after: if added and update_after:
# Do full update to get images etc # Do full update to get images etc
fireEventAsync('movie.update_info', m['_id'], default_title = params.get('title'), on_complete = onComplete) fireEventAsync('movie.update', m['_id'], default_title = params.get('title'), on_complete = onComplete)
# Remove releases # Remove releases
for rel in fireEvent('release.for_media', m['_id'], single = True): for rel in fireEvent('release.for_media', m['_id'], single = True):
@@ -256,7 +256,7 @@ class MovieBase(MovieTypeBase):
'success': False, 'success': False,
} }
def updateInfo(self, media_id = None, identifier = None, default_title = None, extended = False): def update(self, media_id = None, identifier = None, default_title = None, extended = False):
""" """
Update movie information inside media['doc']['info'] Update movie information inside media['doc']['info']
@@ -337,7 +337,7 @@ class MovieBase(MovieTypeBase):
media = db.get('id', media_id) media = db.get('id', media_id)
if not media.get('info'): if not media.get('info'):
media = self.updateInfo(media_id) media = self.update(media_id)
dates = media.get('info', {}).get('release_date') dates = media.get('info', {}).get('release_date')
else: else:
dates = media.get('info').get('release_date') dates = media.get('info').get('release_date')
+1 -1
View File
@@ -28,7 +28,7 @@ class MovieMetaData(MetaDataBase):
# Update library to get latest info # Update library to get latest info
try: try:
group['media'] = fireEvent('movie.update_info', group['media'].get('_id'), identifier = getIdentifier(group['media']), extended = True, single = True) group['media'] = fireEvent('movie.update', group['media'].get('_id'), identifier = getIdentifier(group['media']), extended = True, single = True)
except: except:
log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc()) log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc())
+1 -1
View File
@@ -94,7 +94,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
self.single(media, search_protocols, manual = manual) self.single(media, search_protocols, manual = manual)
except IndexError: except IndexError:
log.error('Forcing library update for %s, if you see this often, please report: %s', (getIdentifier(media), traceback.format_exc())) log.error('Forcing library update for %s, if you see this often, please report: %s', (getIdentifier(media), traceback.format_exc()))
fireEvent('movie.update_info', media_id) fireEvent('movie.update', media_id)
except: except:
log.error('Search failed for %s: %s', (getIdentifier(media), traceback.format_exc())) log.error('Search failed for %s: %s', (getIdentifier(media), traceback.format_exc()))
+1 -1
View File
@@ -27,7 +27,7 @@ class Suggestion(Plugin):
else: else:
if not movies or len(movies) == 0: if not movies or len(movies) == 0:
active_movies = fireEvent('media.with_status', ['active', 'done'], single = True) active_movies = fireEvent('media.with_status', ['active', 'done'], 'movie', single = True)
movies = [getIdentifier(x) for x in active_movies] movies = [getIdentifier(x) for x in active_movies]
if not ignored or len(ignored) == 0: if not ignored or len(ignored) == 0:
+188 -152
View File
@@ -5,7 +5,7 @@ from couchpotato import get_db
from couchpotato.api import addApiView from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.encoding import simplifyString from couchpotato.core.helpers.encoding import simplifyString
from couchpotato.core.helpers.variable import getTitle from couchpotato.core.helpers.variable import getTitle, find
from couchpotato.core.logger import CPLog from couchpotato.core.logger import CPLog
from couchpotato.core.media import MediaBase from couchpotato.core.media import MediaBase
from qcond import QueryCondenser from qcond import QueryCondenser
@@ -32,7 +32,8 @@ class ShowBase(MediaBase):
}) })
addEvent('show.add', self.add) addEvent('show.add', self.add)
addEvent('show.update_info', self.updateInfo) addEvent('show.update', self.update)
addEvent('show.update_extras', self.updateExtras)
def addView(self, **kwargs): def addView(self, **kwargs):
add_dict = self.add(params = kwargs) add_dict = self.add(params = kwargs)
@@ -45,8 +46,6 @@ class ShowBase(MediaBase):
def add(self, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None): def add(self, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None):
if not params: params = {} if not params: params = {}
db = get_db()
# Identifiers # Identifiers
if not params.get('identifiers'): if not params.get('identifiers'):
msg = 'Can\'t add show without at least 1 identifier.' msg = 'Can\'t add show without at least 1 identifier.'
@@ -58,124 +57,13 @@ class ShowBase(MediaBase):
if not info or (info and len(info.get('titles', [])) == 0): if not info or (info and len(info.get('titles', [])) == 0):
info = fireEvent('show.info', merge = True, identifiers = params.get('identifiers')) info = fireEvent('show.info', merge = True, identifiers = params.get('identifiers'))
# Set default title
def_title = self.getDefaultTitle(info)
# Default profile and category
default_profile = {}
if not params.get('profile_id'):
default_profile = fireEvent('profile.default', single = True)
cat_id = params.get('category_id')
# Add Show # Add Show
try: try:
media = { m, added = self.create(info, params, force_readd, search_after, update_after)
'_t': 'media',
'type': 'show',
'title': def_title,
'identifiers': info.get('identifiers'),
'status': status if status else 'active',
'profile_id': params.get('profile_id', default_profile.get('_id')),
'category_id': cat_id if cat_id is not None and len(cat_id) > 0 and cat_id != '-1' else None
}
# TODO: stuff below is mostly a copy of what is done in movie
# Can we make a base function to do this stuff?
# Remove season info for later use (save separately)
seasons_info = info.get('seasons', {})
identifiers = info.get('identifiers', {})
# Make sure we don't nest in_wanted data
del info['identifiers']
try: del info['in_wanted']
except: pass
try: del info['in_library']
except: pass
try: del info['identifiers']
except: pass
try: del info['seasons']
except: pass
media['info'] = info
new = False
try:
m = fireEvent('media.with_identifiers', params.get('identifiers'), with_doc = True, single = True)['doc']
except:
new = True
m = db.insert(media)
# Update dict to be usable
m.update(media)
added = True
do_search = False
search_after = search_after and self.conf('search_on_add', section = 'showsearcher')
onComplete = None
if new:
if search_after:
onComplete = self.createOnComplete(m['_id'])
search_after = False
elif force_readd:
# Clean snatched history
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'
db.update(release)
else:
fireEvent('release.delete', release['_id'], single = True)
m['profile_id'] = params.get('profile_id', default_profile.get('id'))
m['category_id'] = media.get('category_id')
m['last_edit'] = int(time.time())
do_search = True
db.update(m)
else:
try: del params['info']
except: pass
log.debug('Show already exists, not updating: %s', params)
added = False
# Trigger update info
if added and update_after:
# Do full update to get images etc
fireEventAsync('show.update_info', m['_id'], info = info, on_complete = onComplete)
# Remove releases
for rel in fireEvent('release.for_media', m['_id'], single = True):
if rel['status'] is 'available':
db.delete(rel)
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]
episodes = season_info.get('episodes', {})
season = fireEvent('show.season.add', m.get('_id'), season_info, single = True)
# Add Episodes
for episode_nr in episodes:
episode_info = episodes[episode_nr]
episode_info['season_number'] = season_nr
fireEvent('show.episode.add', season.get('_id'), episode_info, single = True)
result = fireEvent('media.get', m['_id'], single = True)
if added and notify_after: if added and notify_after:
if params.get('title'): if params.get('title'):
message = 'Successfully added "%s" to your wanted list.' % params.get('title', '') message = 'Successfully added "%s" to your wanted list.' % params.get('title', '')
else: else:
@@ -184,17 +72,118 @@ class ShowBase(MediaBase):
message = 'Successfully added "%s" to your wanted list.' % title message = 'Successfully added "%s" to your wanted list.' % title
else: else:
message = 'Successfully added to your wanted list.' message = 'Successfully added to your wanted list.'
fireEvent('notify.frontend', type = 'show.added', data = movie_dict, message = message)
fireEvent('notify.frontend', type = 'show.added', data = result, message = message)
return movie_dict return result
except: except:
log.error('Failed adding media: %s', traceback.format_exc()) log.error('Failed adding media: %s', traceback.format_exc())
def updateInfo(self, media_id = None, identifiers = None, info = None): def create(self, info, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None):
if not info: info = {} db = get_db()
if not identifiers: identifiers = {}
# Set default title
def_title = self.getDefaultTitle(info)
# Default profile and category
default_profile = {}
if not params.get('profile_id'):
default_profile = fireEvent('profile.default', single = True)
cat_id = params.get('category_id')
media = {
'_t': 'media',
'type': 'show',
'title': def_title,
'identifiers': info.get('identifiers'),
'status': status if status else 'active',
'profile_id': params.get('profile_id', default_profile.get('_id')),
'category_id': cat_id if cat_id is not None and len(cat_id) > 0 and cat_id != '-1' else None
}
identifiers = info.pop('identifiers', {})
seasons = info.pop('seasons', {})
# Update media with info
self.updateInfo(media, info)
new = False
try:
m = fireEvent('media.with_identifiers', params.get('identifiers'), with_doc = True, single = True)['doc']
except:
new = True
m = db.insert(media)
# Update dict to be usable
m.update(media)
added = True
do_search = False
search_after = search_after and self.conf('search_on_add', section = 'showsearcher')
onComplete = None
if new:
if search_after:
onComplete = self.createOnComplete(m['_id'])
search_after = False
elif force_readd:
# Clean snatched history
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'
db.update(release)
else:
fireEvent('release.delete', release['_id'], single = True)
m['profile_id'] = params.get('profile_id', default_profile.get('id'))
m['category_id'] = media.get('category_id')
m['last_edit'] = int(time.time())
do_search = True
db.update(m)
else:
params.pop('info', None)
log.debug('Show already exists, not updating: %s', params)
added = False
# Create episodes
self.createEpisodes(m, seasons)
# Trigger update info
if added and update_after:
# Do full update to get images etc
fireEventAsync('show.update_extras', m, info, store = True, on_complete = onComplete)
# Remove releases
for rel in fireEvent('release.for_media', m['_id'], single = True):
if rel['status'] is 'available':
db.delete(rel)
if do_search and search_after:
onComplete = self.createOnComplete(m['_id'])
onComplete()
return m, added
def createEpisodes(self, m, seasons_info):
# Add Seasons
for season_nr in seasons_info:
season_info = seasons_info[season_nr]
episodes = season_info.get('episodes', {})
season = fireEvent('show.season.add', m.get('_id'), season_info, update_after = False, single = True)
# Add Episodes
for episode_nr in episodes:
episode_info = episodes[episode_nr]
episode_info['season_number'] = season_nr
fireEvent('show.episode.add', season.get('_id'), episode_info, update_after = False, single = True)
def update(self, media_id = None, media = None, identifiers = None, info = None):
""" """
Update movie information inside media['doc']['info'] Update movie information inside media['doc']['info']
@@ -209,41 +198,30 @@ class ShowBase(MediaBase):
@return: dict, with media @return: dict, with media
""" """
if not info: info = {}
if not identifiers: identifiers = {}
db = get_db()
if self.shuttingDown(): if self.shuttingDown():
return return
if media is None and media_id:
media = db.get('id', media_id)
else:
log.error('missing "media" and "media_id" parameters, unable to update')
return
if not info:
info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True)
try: try:
db = get_db() identifiers = info.pop('identifiers', {})
seasons = info.pop('seasons', {})
if media_id: self.updateInfo(media, info)
media = db.get('id', media_id) self.updateEpisodes(media, seasons)
else: self.updateExtras(media, info)
media = db.get('media', identifiers, with_doc = True)['doc']
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']
except: pass
if not info or len(info) == 0:
log.error('Could not update, no show info to work with: %s', media.get('identifier'))
return False
# Update basic info
media['info'] = info
# Update image file
image_urls = info.get('images', [])
self.getPoster(media, image_urls)
db.update(media) db.update(media)
return media return media
@@ -251,3 +229,61 @@ class ShowBase(MediaBase):
log.error('Failed update media: %s', traceback.format_exc()) log.error('Failed update media: %s', traceback.format_exc())
return {} return {}
def updateInfo(self, media, info):
db = get_db()
# Remove season info for later use (save separately)
info.pop('in_wanted', None)
info.pop('in_library', None)
if not info or len(info) == 0:
log.error('Could not update, no show info to work with: %s', media.get('identifier'))
return False
# Update basic info
media['info'] = info
def updateEpisodes(self, media, seasons):
# Fetch current season/episode tree
show_tree = fireEvent('library.tree', media_id = media['_id'], single = True)
# Update seasons
for season_num in seasons:
season_info = seasons[season_num]
episodes = season_info.get('episodes', {})
# Find season that matches number
season = find(lambda s: s.get('info', {}).get('number', 0) == season_num, show_tree.get('seasons', []))
if not season:
log.warning('Unable to find season "%s"', season_num)
continue
# Update season
fireEvent('show.season.update', season['_id'], info = season_info, single = True)
# Update episodes
for episode_num in episodes:
episode_info = episodes[episode_num]
episode_info['season_number'] = season_num
# Find episode that matches number
episode = find(lambda s: s.get('info', {}).get('number', 0) == episode_num, season.get('episodes', []))
if not episode:
log.debug('Creating new episode %s in season %s', (episode_num, season_num))
fireEvent('show.episode.add', season.get('_id'), episode_info, update_after = False, single = True)
continue
fireEvent('show.episode.update', episode['_id'], info = episode_info, single = True)
def updateExtras(self, media, info, store=False):
db = get_db()
# Update image file
image_urls = info.get('images', [])
self.getPoster(media, image_urls)
if store:
db.update(media)
+29 -16
View File
@@ -14,14 +14,17 @@ class Episode(MediaBase):
def __init__(self): def __init__(self):
addEvent('show.episode.add', self.add) addEvent('show.episode.add', self.add)
addEvent('show.episode.update_info', self.updateInfo) addEvent('show.episode.update', self.update)
addEvent('show.episode.update_extras', self.updateExtras)
def add(self, parent_id, info = None, update_after = True, status = None): def add(self, parent_id, info = None, update_after = True, status = None):
if not info: info = {} if not info: info = {}
identifiers = info.get('identifiers') identifiers = info.pop('identifiers', None)
try: del info['identifiers']
except: pass if not identifiers:
log.warning('Unable to add episode, missing identifiers (info provider mismatch?)')
return
# Add Season # Add Season
episode_info = { episode_info = {
@@ -41,6 +44,7 @@ class Episode(MediaBase):
if existing_episode: if existing_episode:
s = existing_episode['doc'] s = existing_episode['doc']
s.update(episode_info) s.update(episode_info)
episode = db.update(s) episode = db.update(s)
else: else:
episode = db.insert(episode_info) episode = db.insert(episode_info)
@@ -48,11 +52,11 @@ class Episode(MediaBase):
# Update library info # Update library info
if update_after is not False: if update_after is not False:
handle = fireEventAsync if update_after is 'async' else fireEvent handle = fireEventAsync if update_after is 'async' else fireEvent
handle('show.season.update_info', episode.get('_id'), info = info, single = True) handle('show.episode.update_extras', episode, info, store = True, single = True)
return episode return episode
def updateInfo(self, media_id = None, info = None, force = False): def update(self, media_id = None, identifiers = None, info = None):
if not info: info = {} if not info: info = {}
if self.shuttingDown(): if self.shuttingDown():
@@ -69,26 +73,35 @@ class Episode(MediaBase):
info = fireEvent( info = fireEvent(
'episode.info', show.get('identifiers'), { 'episode.info', show.get('identifiers'), {
'season_identifier': season.get('info', {}).get('number'), 'season_identifiers': season.get('identifiers'),
'episode_identifier': episode.get('identifiers') 'season_number': season.get('info', {}).get('number'),
'episode_identifiers': episode.get('identifiers'),
'episode_number': episode.get('info', {}).get('number'),
'absolute_number': episode.get('info', {}).get('absolute_number')
}, },
merge = True merge = True
) )
identifiers = info.pop('identifiers', None) or identifiers
# Update/create media # Update/create media
if force: episode['identifiers'].update(identifiers)
episode.update({'info': info})
episode['identifiers'].update(info['identifiers']) self.updateExtras(episode, info)
if 'identifiers' in info:
del info['identifiers']
episode.update({'info': info}) db.update(episode)
e = db.update(episode) return episode
episode.update(e)
def updateExtras(self, episode, info, store=False):
db = get_db()
# Get images # Get images
image_urls = info.get('images', []) image_urls = info.get('images', [])
existing_files = episode.get('files', {}) existing_files = episode.get('files', {})
self.getPoster(image_urls, existing_files) self.getPoster(image_urls, existing_files)
return episode if store:
db.update(episode)
@@ -60,8 +60,9 @@ class TheTVDb(ShowProvider):
self.tvdb_api_parms['language'] = language self.tvdb_api_parms['language'] = language
self._setup() self._setup()
search_string = simplifyString(q) query = q
cache_key = 'thetvdb.cache.search.%s.%s' % (search_string, limit) #query = simplifyString(query)
cache_key = 'thetvdb.cache.search.%s.%s' % (query, limit)
results = self.getCache(cache_key) results = self.getCache(cache_key)
if not results: if not results:
@@ -69,9 +70,9 @@ class TheTVDb(ShowProvider):
raw = None raw = None
try: try:
raw = self.tvdb.search(search_string) raw = self.tvdb.search(query)
except (tvdb_exceptions.tvdb_error, IOError), e: except (tvdb_exceptions.tvdb_error, IOError), e:
log.error('Failed searching TheTVDB for "%s": %s', (search_string, traceback.format_exc())) log.error('Failed searching TheTVDB for "%s": %s', (query, traceback.format_exc()))
return False return False
results = [] results = []
@@ -129,22 +130,17 @@ class TheTVDb(ShowProvider):
return result or {} return result or {}
def getSeasonInfo(self, identifier = None, params = {}): def getSeasonInfo(self, identifiers = None, params = {}):
"""Either return a list of all seasons or a single season by number. """Either return a list of all seasons or a single season by number.
identifier is the show 'id' identifier is the show 'id'
""" """
if not identifier: if not identifiers or not identifiers.get('thetvdb'):
return False return None
season_identifier = params.get('season_identifier', None) season_number = params.get('season_number', None)
identifier = tryInt(identifiers.get('thetvdb'))
# season_identifier must contain the 'show id : season number' since there is no tvdb id cache_key = 'thetvdb.cache.%s.%s' % (identifier, season_number)
# for season and we need a reference to both the show id and season number
if season_identifier:
try: season_identifier = int(season_identifier.split(':')[1])
except: return False
cache_key = 'thetvdb.cache.%s.%s' % (identifier, season_identifier)
log.debug('Getting SeasonInfo: %s', cache_key) log.debug('Getting SeasonInfo: %s', cache_key)
result = self.getCache(cache_key) or {} result = self.getCache(cache_key) or {}
if result: if result:
@@ -158,12 +154,12 @@ class TheTVDb(ShowProvider):
result = [] result = []
for number, season in show.items(): for number, season in show.items():
if season_identifier is not None and number == season_identifier: if season_number is not None and number == season_number:
result = self._parseSeason(show, (number, season)) result = self._parseSeason(show, number, season)
self.setCache(cache_key, result) self.setCache(cache_key, result)
return result return result
else: else:
result.append(self._parseSeason(show, (number, season))) result.append(self._parseSeason(show, number, season))
self.setCache(cache_key, result) self.setCache(cache_key, result)
return result return result
@@ -172,22 +168,22 @@ class TheTVDb(ShowProvider):
"""Either return a list of all episodes or a single episode. """Either return a list of all episodes or a single episode.
If episode_identifer contains an episode number to search for If episode_identifer contains an episode number to search for
""" """
season_identifier = self.getIdentifier(params.get('season_identifier', None)) season_number = self.getIdentifier(params.get('season_number', None))
episode_identifier = self.getIdentifier(params.get('episode_identifier', None)) episode_identifier = self.getIdentifier(params.get('episode_identifiers', None))
identifier = self.getIdentifier(identifier) identifier = self.getIdentifier(identifier)
if not identifier and season_identifier is None: if not identifier and season_number is None:
return False return False
# season_identifier must contain the 'show id : season number' since there is no tvdb id # season_identifier must contain the 'show id : season number' since there is no tvdb id
# for season and we need a reference to both the show id and season number # for season and we need a reference to both the show id and season number
if not identifier and season_identifier: if not identifier and season_number:
try: try:
identifier, season_identifier = season_identifier.split(':') identifier, season_number = season_number.split(':')
season_identifier = int(season_identifier) season_number = int(season_number)
except: return None except: return None
cache_key = 'thetvdb.cache.%s.%s.%s' % (identifier, episode_identifier, season_identifier) cache_key = 'thetvdb.cache.%s.%s.%s' % (identifier, episode_identifier, season_number)
log.debug('Getting EpisodeInfo: %s', cache_key) log.debug('Getting EpisodeInfo: %s', cache_key)
result = self.getCache(cache_key) or {} result = self.getCache(cache_key) or {}
if result: if result:
@@ -201,7 +197,7 @@ class TheTVDb(ShowProvider):
result = [] result = []
for number, season in show.items(): for number, season in show.items():
if season_identifier is not None and number != season_identifier: if season_number is not None and number != season_number:
continue continue
for episode in season.values(): for episode in season.values():
+72 -50
View File
@@ -5,6 +5,8 @@ from couchpotato.core.media.show.providers.base import ShowProvider
log = CPLog(__name__) log = CPLog(__name__)
autoload = 'Xem'
class Xem(ShowProvider): class Xem(ShowProvider):
''' '''
@@ -75,76 +77,69 @@ class Xem(ShowProvider):
self.config['url_names'] = u"%(base_url)s/map/names?" % self.config self.config['url_names'] = u"%(base_url)s/map/names?" % self.config
self.config['url_all_names'] = u"%(base_url)s/map/allNames?" % self.config self.config['url_all_names'] = u"%(base_url)s/map/allNames?" % self.config
# TODO: Also get show aliases (store as titles) def getShowInfo(self, identifiers = None):
def getShowInfo(self, identifier = None):
if self.isDisabled(): if self.isDisabled():
return {} return {}
identifier = identifiers.get('thetvdb')
if not identifier:
return {}
cache_key = 'xem.cache.%s' % identifier cache_key = 'xem.cache.%s' % identifier
log.debug('Getting showInfo: %s', cache_key) log.debug('Getting showInfo: %s', cache_key)
result = self.getCache(cache_key) or {} result = self.getCache(cache_key) or {}
if result: if result:
return result return result
result['seasons'] = {}
# Create season/episode and absolute mappings # Create season/episode and absolute mappings
url = self.config['url_all'] + "id=%s&origin=tvdb" % tryUrlencode(identifier) url = self.config['url_all'] + "id=%s&origin=tvdb" % tryUrlencode(identifier)
response = self.getJsonData(url) response = self.getJsonData(url)
if response:
if response.get('result') == 'success': if response and response.get('result') == 'success':
data = response.get('data', None) data = response.get('data', None)
result = self._parse(data) self.parseMaps(result, data)
# Create name alias mappings # Create name alias mappings
url = self.config['url_names'] + "id=%s&origin=tvdb" % tryUrlencode(identifier) url = self.config['url_names'] + "id=%s&origin=tvdb" % tryUrlencode(identifier)
response = self.getJsonData(url) response = self.getJsonData(url)
if response:
if response.get('result') == 'success': if response and response.get('result') == 'success':
data = response.get('data', None) data = response.get('data', None)
result.update({'map_names': data}) self.parseNames(result, data)
self.setCache(cache_key, result) self.setCache(cache_key, result)
return result return result
def getEpisodeInfo(self, identifier = None, params = {}): def getEpisodeInfo(self, identifiers = None, params = {}):
episode = params.get('episode', None) episode_num = params.get('episode_number', None)
if episode is None: if episode_num is None:
return False return False
season_identifier = params.get('season_identifier', None) season_num = params.get('season_number', None)
if season_identifier is None: if season_num is None:
return False return False
episode_identifier = params.get('episode_identifier', None) result = self.getShowInfo(identifiers)
absolute = params.get('absolute', None)
# season_identifier must contain the 'show id : season number' since there is no tvdb id if not result:
# for season and we need a reference to both the show id and season number return False
if season_identifier:
try:
identifier, season_identifier = season_identifier.split(':')
season = int(season_identifier)
except: return False
result = self.getShowInfo(identifier) # Find season
map = {} if season_num not in result['seasons']:
if result: return False
map_episode = result.get('map_episode', {}).get(season, {}).get(episode, {})
if map_episode:
map.update({'map_episode': map_episode})
if absolute: season = result['seasons'][season_num]
map_absolute = result.get('map_absolute', {}).get(absolute, {})
if map_absolute:
map.update({'map_absolute': map_absolute})
map_names = result.get('map_names', {}).get(toUnicode(season), {}) # Find episode
if map_names: if episode_num not in season['episodes']:
map.update({'map_names': map_names}) return False
return map return season['episodes'][episode_num]
def parseMaps(self, result, data, master = 'tvdb'):
def _parse(self, data, master = 'tvdb'):
'''parses xem map and returns a custom formatted dict map '''parses xem map and returns a custom formatted dict map
To retreive map for scene: To retreive map for scene:
@@ -152,17 +147,44 @@ class Xem(ShowProvider):
print map['map_episode'][1][1]['scene']['season'] print map['map_episode'][1][1]['scene']['season']
''' '''
if not isinstance(data, list): if not isinstance(data, list):
return {} return
map = {'map_episode': {}, 'map_absolute': {}} for episode_map in data:
for maps in data: origin = episode_map.pop(master, None)
origin = maps.pop(master, None)
if origin is None: if origin is None:
continue # No master origin to map to continue # No master origin to map to
map.get('map_episode').setdefault(origin['season'], {}).setdefault(origin['episode'], maps.copy())
map.get('map_absolute').setdefault(origin['absolute'], maps.copy())
return map o_season = origin['season']
o_episode = origin['episode']
# Create season info
if o_season not in result['seasons']:
result['seasons'][o_season] = {}
season = result['seasons'][o_season]
if 'episodes' not in season:
season['episodes'] = {}
# Create episode info
if o_episode not in season['episodes']:
season['episodes'][o_episode] = {}
episode = season['episodes'][o_episode]
episode['episode_map'] = episode_map
def parseNames(self, result, data):
result['title_map'] = data.pop('all', None)
for season, title_map in data.items():
season = int(season)
# Create season info
if season not in result['seasons']:
result['seasons'][season] = {}
season = result['seasons'][season]
season['title_map'] = title_map
def isDisabled(self): def isDisabled(self):
if __name__ == '__main__': if __name__ == '__main__':
+24 -17
View File
@@ -14,16 +14,14 @@ class Season(MediaBase):
def __init__(self): def __init__(self):
addEvent('show.season.add', self.add) addEvent('show.season.add', self.add)
addEvent('show.season.update_info', self.updateInfo) addEvent('show.season.update', self.update)
addEvent('show.season.update_extras', self.updateExtras)
def add(self, parent_id, info = None, update_after = True, status = None): def add(self, parent_id, info = None, update_after = True, status = None):
if not info: info = {} if not info: info = {}
identifiers = info.get('identifiers') identifiers = info.pop('identifiers', None)
try: del info['identifiers'] info.pop('episodes', None)
except: pass
try: del info['episodes']
except: pass
# Add Season # Add Season
season_info = { season_info = {
@@ -43,6 +41,7 @@ class Season(MediaBase):
if existing_season: if existing_season:
s = existing_season['doc'] s = existing_season['doc']
s.update(season_info) s.update(season_info)
season = db.update(s) season = db.update(s)
else: else:
season = db.insert(season_info) season = db.insert(season_info)
@@ -50,11 +49,11 @@ class Season(MediaBase):
# Update library info # Update library info
if update_after is not False: if update_after is not False:
handle = fireEventAsync if update_after is 'async' else fireEvent handle = fireEventAsync if update_after is 'async' else fireEvent
handle('show.season.update_info', season.get('_id'), info = info, single = True) handle('show.season.update_extras', season, info, store = True, single = True)
return season return season
def updateInfo(self, media_id = None, info = None, force = False): def update(self, media_id = None, identifiers = None, info = None):
if not info: info = {} if not info: info = {}
if self.shuttingDown(): if self.shuttingDown():
@@ -63,25 +62,33 @@ class Season(MediaBase):
db = get_db() db = get_db()
season = db.get('id', media_id) season = db.get('id', media_id)
show = db.get('id', season['parent_id'])
# Get new info # Get new info
if not info: if not info:
info = fireEvent('season.info', season.get('identifiers'), merge = True) info = fireEvent('season.info', show.get('identifiers'), {
'season_number': season.get('info', {}).get('number', 0)
}, merge = True)
identifiers = info.pop('identifiers', None) or identifiers
info.pop('episodes', None)
# Update/create media # Update/create media
if force: season['identifiers'].update(identifiers)
season.update({'info': info})
season['identifiers'].update(info['identifiers']) self.updateExtras(season, info)
if 'identifiers' in info:
del info['identifiers']
season.update({'info': info}) db.update(season)
s = db.update(season) return season
season.update(s)
def updateExtras(self, season, info, store=False):
db = get_db()
# Get images # Get images
image_urls = info.get('images', []) image_urls = info.get('images', [])
existing_files = season.get('files', {}) existing_files = season.get('files', {})
self.getPoster(image_urls, existing_files) self.getPoster(image_urls, existing_files)
return season if store:
db.update(season)
+1 -1
View File
@@ -62,7 +62,7 @@ class Dashboard(Plugin):
for media_id in active_ids: for media_id in active_ids:
media = db.get('id', media_id) media = db.get('id', media_id)
pp = profile_pre.get(media['profile_id']) pp = profile_pre.get(media.get('profile_id'))
if not pp: continue if not pp: continue
eta = media['info'].get('release_date', {}) or {} eta = media['info'].get('release_date', {}) or {}
+1 -1
View File
@@ -219,7 +219,7 @@ class Manage(Plugin):
# Add it to release and update the info # Add it to release and update the info
fireEvent('release.add', group = group, update_info = False) fireEvent('release.add', group = group, update_info = False)
fireEvent('movie.update_info', identifier = group['identifier'], on_complete = self.createAfterUpdate(folder, group['identifier'])) fireEvent('movie.update', identifier = group['identifier'], on_complete = self.createAfterUpdate(folder, group['identifier']))
return addToLibrary return addToLibrary
+1 -1
View File
@@ -247,7 +247,7 @@ class Renamer(Plugin):
'profile_id': None 'profile_id': None
}, search_after = False, status = 'done', single = True) }, search_after = False, status = 'done', single = True)
else: else:
group['media'] = fireEvent('movie.update_info', media_id = group['media'].get('_id'), single = True) group['media'] = fireEvent('movie.update', media_id = group['media'].get('_id'), single = True)
if not group['media'] or not group['media'].get('_id'): if not group['media'] or not group['media'].get('_id'):
log.error('Could not rename, no library item to work with: %s', group_identifier) log.error('Could not rename, no library item to work with: %s', group_identifier)
Regular → Executable
+1 -1
View File
@@ -705,7 +705,7 @@ class Tvdb:
for k, v in banners[btype][btype2][bid].items(): for k, v in banners[btype][btype2][bid].items():
if k.endswith("path"): if k.endswith("path"):
new_key = "_%s" % (k) new_key = "_%s" % (k)
log().debug("Transforming %s to %s" % (k, new_key)) #log().debug("Transforming %s to %s" % (k, new_key))
new_url = self.config['url_artworkPrefix'] % (v) new_url = self.config['url_artworkPrefix'] % (v)
banners[btype][btype2][bid][new_key] = new_url banners[btype][btype2][bid][new_key] = new_url