Browse Source

Merge branch 'tv_xem' into tv

pull/3730/merge
Dean Gardiner 11 years ago
parent
commit
a06bfcb3bf
  1. 8
      couchpotato/core/helpers/variable.py
  2. 17
      couchpotato/core/media/_base/library/main.py
  3. 11
      couchpotato/core/media/_base/media/main.py
  4. 8
      couchpotato/core/media/movie/_base/main.py
  5. 2
      couchpotato/core/media/movie/providers/metadata/base.py
  6. 2
      couchpotato/core/media/movie/searcher.py
  7. 2
      couchpotato/core/media/movie/suggestion/main.py
  8. 328
      couchpotato/core/media/show/_base/main.py
  9. 45
      couchpotato/core/media/show/episode.py
  10. 48
      couchpotato/core/media/show/providers/info/thetvdb.py
  11. 122
      couchpotato/core/media/show/providers/info/xem.py
  12. 41
      couchpotato/core/media/show/season.py
  13. 2
      couchpotato/core/plugins/dashboard.py
  14. 2
      couchpotato/core/plugins/manage.py
  15. 2
      couchpotato/core/plugins/renamer.py
  16. 2
      libs/tvdb_api/tvdb_api.py

8
couchpotato/core/helpers/variable.py

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

17
couchpotato/core/media/_base/library/main.py

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

11
couchpotato/core/media/_base/media/main.py

@ -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'])

8
couchpotato/core/media/movie/_base/main.py

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

2
couchpotato/core/media/movie/providers/metadata/base.py

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

2
couchpotato/core/media/movie/searcher.py

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

2
couchpotato/core/media/movie/suggestion/main.py

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

328
couchpotato/core/media/show/_base/main.py

@ -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,6 +57,31 @@ 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'))
# Add Show
try:
m, added = self.create(info, params, force_readd, search_after, update_after)
result = fireEvent('media.get', m['_id'], single = True)
if added and notify_after:
if params.get('title'):
message = 'Successfully added "%s" to your wanted list.' % params.get('title', '')
else:
title = getTitle(m)
if title:
message = 'Successfully added "%s" to your wanted list.' % title
else:
message = 'Successfully added to your wanted list.'
fireEvent('notify.frontend', type = 'show.added', data = result, message = message)
return result
except:
log.error('Failed adding media: %s', traceback.format_exc())
def create(self, info, params = None, force_readd = True, search_after = True, update_after = True, notify_after = True, status = None):
db = get_db()
# Set default title # Set default title
def_title = self.getDefaultTitle(info) def_title = self.getDefaultTitle(info)
@ -65,136 +89,101 @@ class ShowBase(MediaBase):
default_profile = {} default_profile = {}
if not params.get('profile_id'): if not params.get('profile_id'):
default_profile = fireEvent('profile.default', single = True) default_profile = fireEvent('profile.default', single = True)
cat_id = params.get('category_id') cat_id = params.get('category_id')
# Add Show 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: try:
media = { m = fireEvent('media.with_identifiers', params.get('identifiers'), with_doc = True, single = True)['doc']
'_t': 'media', except:
'type': 'show', new = True
'title': def_title, m = db.insert(media)
'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 # Update dict to be usable
# Can we make a base function to do this stuff? m.update(media)
# Remove season info for later use (save separately) added = True
seasons_info = info.get('seasons', {}) do_search = False
identifiers = info.get('identifiers', {}) search_after = search_after and self.conf('search_on_add', section = 'showsearcher')
onComplete = None
# Make sure we don't nest in_wanted data
del info['identifiers'] if new:
try: del info['in_wanted'] if search_after:
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 = self.createOnComplete(m['_id'])
onComplete()
# Add Seasons search_after = False
for season_nr in seasons_info: 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)
season_info = seasons_info[season_nr] m['profile_id'] = params.get('profile_id', default_profile.get('id'))
episodes = season_info.get('episodes', {}) m['category_id'] = media.get('category_id')
m['last_edit'] = int(time.time())
season = fireEvent('show.season.add', m.get('_id'), season_info, single = True) do_search = True
db.update(m)
else:
params.pop('info', None)
log.debug('Show already exists, not updating: %s', params)
added = False
# Add Episodes # Create episodes
for episode_nr in episodes: self.createEpisodes(m, seasons)
episode_info = episodes[episode_nr] # Trigger update info
episode_info['season_number'] = season_nr if added and update_after:
fireEvent('show.episode.add', season.get('_id'), episode_info, single = True) # 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 added and notify_after: if do_search and search_after:
onComplete = self.createOnComplete(m['_id'])
onComplete()
if params.get('title'): return m, added
message = 'Successfully added "%s" to your wanted list.' % params.get('title', '')
else:
title = getTitle(m)
if title:
message = 'Successfully added "%s" to your wanted list.' % title
else:
message = 'Successfully added to your wanted list.'
fireEvent('notify.frontend', type = 'show.added', data = movie_dict, message = message)
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', {})
return movie_dict season = fireEvent('show.season.add', m.get('_id'), season_info, update_after = False, single = True)
except:
log.error('Failed adding media: %s', traceback.format_exc())
def updateInfo(self, media_id = None, identifiers = None, info = None): # Add Episodes
if not info: info = {} for episode_nr in episodes:
if not identifiers: identifiers = {} 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 self.shuttingDown(): if not info: info = {}
return if not identifiers: identifiers = {}
try:
db = get_db()
if media_id:
media = db.get('id', media_id)
else:
media = db.get('media', identifiers, with_doc = True)['doc']
if not info: db = get_db()
info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True)
# Don't need those here if self.shuttingDown():
try: del info['seasons'] return
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: if media is None and media_id:
log.error('Could not update, no show info to work with: %s', media.get('identifier')) media = db.get('id', media_id)
return False else:
log.error('missing "media" and "media_id" parameters, unable to update')
return
# Update basic info if not info:
media['info'] = info info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True)
# Update image file try:
image_urls = info.get('images', []) identifiers = info.pop('identifiers', {})
seasons = info.pop('seasons', {})
self.getPoster(media, image_urls) self.updateInfo(media, info)
self.updateEpisodes(media, seasons)
self.updateExtras(media, info)
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)

45
couchpotato/core/media/show/episode.py

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

48
couchpotato/core/media/show/providers/info/thetvdb.py

@ -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_identifier must contain the 'show id : season number' since there is no tvdb id season_number = params.get('season_number', None)
# for season and we need a reference to both the show id and season number identifier = tryInt(identifiers.get('thetvdb'))
if season_identifier:
try: season_identifier = int(season_identifier.split(':')[1])
except: return False
cache_key = 'thetvdb.cache.%s.%s' % (identifier, season_identifier) cache_key = 'thetvdb.cache.%s.%s' % (identifier, season_number)
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():

122
couchpotato/core/media/show/providers/info/xem.py

@ -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
# for season and we need a reference to both the show id and season number
if season_identifier:
try:
identifier, season_identifier = season_identifier.split(':')
season = int(season_identifier)
except: return False
result = self.getShowInfo(identifier) if not result:
map = {} return False
if result:
map_episode = result.get('map_episode', {}).get(season, {}).get(episode, {})
if map_episode:
map.update({'map_episode': map_episode})
if absolute: # Find season
map_absolute = result.get('map_absolute', {}).get(absolute, {}) if season_num not in result['seasons']:
if map_absolute: return False
map.update({'map_absolute': map_absolute})
map_names = result.get('map_names', {}).get(toUnicode(season), {}) season = result['seasons'][season_num]
if map_names:
map.update({'map_names': map_names})
return map # Find episode
if episode_num not in season['episodes']:
return False
return season['episodes'][episode_num]
def _parse(self, data, master = 'tvdb'): def parseMaps(self, result, 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()) 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] = {}
return map season = result['seasons'][season]
season['title_map'] = title_map
def isDisabled(self): def isDisabled(self):
if __name__ == '__main__': if __name__ == '__main__':

41
couchpotato/core/media/show/season.py

@ -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})
self.updateExtras(season, info)
season['identifiers'].update(info['identifiers']) db.update(season)
if 'identifiers' in info: return season
del info['identifiers']
season.update({'info': info}) def updateExtras(self, season, info, store=False):
s = db.update(season) db = get_db()
season.update(s)
# 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)

2
couchpotato/core/plugins/dashboard.py

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

2
couchpotato/core/plugins/manage.py

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

2
couchpotato/core/plugins/renamer.py

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

2
libs/tvdb_api/tvdb_api.py

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

Loading…
Cancel
Save