Merge branch 'tv_xem' into tv
This commit is contained in:
Regular → Executable
+8
@@ -380,3 +380,11 @@ def getFreeSpace(directories):
|
||||
free_space[folder] = size
|
||||
|
||||
return free_space
|
||||
|
||||
|
||||
def find(func, iterable):
|
||||
for item in iterable:
|
||||
if func(item):
|
||||
return item
|
||||
|
||||
return None
|
||||
|
||||
@@ -78,13 +78,18 @@ class Library(LibraryBase):
|
||||
|
||||
return cur
|
||||
|
||||
def tree(self, media):
|
||||
result = media
|
||||
|
||||
def tree(self, media = None, media_id = None):
|
||||
db = get_db()
|
||||
|
||||
if media:
|
||||
result = media
|
||||
elif media_id:
|
||||
result = db.get('id', media_id, with_doc = True)
|
||||
else:
|
||||
return None
|
||||
|
||||
# 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 = []
|
||||
|
||||
# Build children arrays
|
||||
@@ -94,6 +99,8 @@ class Library(LibraryBase):
|
||||
|
||||
if key not in result:
|
||||
result[key] = {}
|
||||
elif type(result[key]) is not dict:
|
||||
result[key] = {}
|
||||
|
||||
if key not in keys:
|
||||
keys.append(key)
|
||||
@@ -105,6 +112,6 @@ class Library(LibraryBase):
|
||||
result[key] = result[key].values()
|
||||
|
||||
# Include releases
|
||||
result['releases'] = fireEvent('release.for_media', media['_id'], single = True)
|
||||
result['releases'] = fireEvent('release.for_media', result['_id'], single = True)
|
||||
|
||||
return result
|
||||
|
||||
Regular → Executable
+9
-2
@@ -109,7 +109,7 @@ class MediaPlugin(MediaBase):
|
||||
|
||||
try:
|
||||
media = get_db().get('id', media_id)
|
||||
event = '%s.update_info' % media.get('type')
|
||||
event = '%s.update' % media.get('type')
|
||||
|
||||
def handler():
|
||||
fireEvent(event, media_id = media_id, on_complete = self.createOnComplete(media_id))
|
||||
@@ -160,10 +160,13 @@ class MediaPlugin(MediaBase):
|
||||
'media': media,
|
||||
}
|
||||
|
||||
def withStatus(self, status, with_doc = True):
|
||||
def withStatus(self, status, types = None, with_doc = True):
|
||||
|
||||
db = get_db()
|
||||
|
||||
if types and not isinstance(types, (list, tuple)):
|
||||
types = [types]
|
||||
|
||||
status = list(status if isinstance(status, (list, tuple)) else [status])
|
||||
|
||||
for s in status:
|
||||
@@ -171,6 +174,10 @@ class MediaPlugin(MediaBase):
|
||||
if with_doc:
|
||||
try:
|
||||
doc = db.get('id', ms['_id'])
|
||||
|
||||
if types and doc.get('type') not in types:
|
||||
continue
|
||||
|
||||
yield doc
|
||||
except RecordNotFound:
|
||||
log.debug('Record not found, skipping: %s', ms['_id'])
|
||||
|
||||
@@ -46,7 +46,7 @@ class MovieBase(MovieTypeBase):
|
||||
})
|
||||
|
||||
addEvent('movie.add', self.add)
|
||||
addEvent('movie.update_info', self.updateInfo)
|
||||
addEvent('movie.update', self.update)
|
||||
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):
|
||||
@@ -172,7 +172,7 @@ class MovieBase(MovieTypeBase):
|
||||
# Trigger update info
|
||||
if added and update_after:
|
||||
# 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
|
||||
for rel in fireEvent('release.for_media', m['_id'], single = True):
|
||||
@@ -256,7 +256,7 @@ class MovieBase(MovieTypeBase):
|
||||
'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']
|
||||
|
||||
@@ -337,7 +337,7 @@ class MovieBase(MovieTypeBase):
|
||||
media = db.get('id', media_id)
|
||||
|
||||
if not media.get('info'):
|
||||
media = self.updateInfo(media_id)
|
||||
media = self.update(media_id)
|
||||
dates = media.get('info', {}).get('release_date')
|
||||
else:
|
||||
dates = media.get('info').get('release_date')
|
||||
|
||||
Regular → Executable
+1
-1
@@ -28,7 +28,7 @@ class MovieMetaData(MetaDataBase):
|
||||
|
||||
# Update library to get latest info
|
||||
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:
|
||||
log.error('Failed to update movie, before creating metadata: %s', traceback.format_exc())
|
||||
|
||||
|
||||
Regular → Executable
+1
-1
@@ -94,7 +94,7 @@ class MovieSearcher(SearcherBase, MovieTypeBase):
|
||||
self.single(media, search_protocols, manual = manual)
|
||||
except IndexError:
|
||||
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:
|
||||
log.error('Search failed for %s: %s', (getIdentifier(media), traceback.format_exc()))
|
||||
|
||||
|
||||
Regular → Executable
+1
-1
@@ -27,7 +27,7 @@ class Suggestion(Plugin):
|
||||
else:
|
||||
|
||||
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]
|
||||
|
||||
if not ignored or len(ignored) == 0:
|
||||
|
||||
@@ -5,7 +5,7 @@ from couchpotato import get_db
|
||||
from couchpotato.api import addApiView
|
||||
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
|
||||
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.media import MediaBase
|
||||
from qcond import QueryCondenser
|
||||
@@ -32,7 +32,8 @@ class ShowBase(MediaBase):
|
||||
})
|
||||
|
||||
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):
|
||||
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):
|
||||
if not params: params = {}
|
||||
|
||||
db = get_db()
|
||||
|
||||
# Identifiers
|
||||
if not params.get('identifiers'):
|
||||
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):
|
||||
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
|
||||
try:
|
||||
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
|
||||
}
|
||||
|
||||
# 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)
|
||||
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:
|
||||
@@ -184,17 +72,118 @@ class ShowBase(MediaBase):
|
||||
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)
|
||||
|
||||
fireEvent('notify.frontend', type = 'show.added', data = result, message = message)
|
||||
|
||||
return movie_dict
|
||||
return result
|
||||
except:
|
||||
log.error('Failed adding media: %s', traceback.format_exc())
|
||||
|
||||
def updateInfo(self, media_id = None, identifiers = None, info = None):
|
||||
if not info: info = {}
|
||||
if not identifiers: identifiers = {}
|
||||
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
|
||||
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']
|
||||
|
||||
@@ -209,41 +198,30 @@ class ShowBase(MediaBase):
|
||||
@return: dict, with media
|
||||
"""
|
||||
|
||||
if not info: info = {}
|
||||
if not identifiers: identifiers = {}
|
||||
|
||||
db = get_db()
|
||||
|
||||
if self.shuttingDown():
|
||||
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:
|
||||
db = get_db()
|
||||
identifiers = info.pop('identifiers', {})
|
||||
seasons = info.pop('seasons', {})
|
||||
|
||||
if media_id:
|
||||
media = db.get('id', media_id)
|
||||
else:
|
||||
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)
|
||||
self.updateInfo(media, info)
|
||||
self.updateEpisodes(media, seasons)
|
||||
self.updateExtras(media, info)
|
||||
|
||||
db.update(media)
|
||||
return media
|
||||
@@ -251,3 +229,61 @@ class ShowBase(MediaBase):
|
||||
log.error('Failed update media: %s', traceback.format_exc())
|
||||
|
||||
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)
|
||||
|
||||
@@ -14,14 +14,17 @@ class Episode(MediaBase):
|
||||
|
||||
def __init__(self):
|
||||
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):
|
||||
if not info: info = {}
|
||||
|
||||
identifiers = info.get('identifiers')
|
||||
try: del info['identifiers']
|
||||
except: pass
|
||||
identifiers = info.pop('identifiers', None)
|
||||
|
||||
if not identifiers:
|
||||
log.warning('Unable to add episode, missing identifiers (info provider mismatch?)')
|
||||
return
|
||||
|
||||
# Add Season
|
||||
episode_info = {
|
||||
@@ -41,6 +44,7 @@ class Episode(MediaBase):
|
||||
if existing_episode:
|
||||
s = existing_episode['doc']
|
||||
s.update(episode_info)
|
||||
|
||||
episode = db.update(s)
|
||||
else:
|
||||
episode = db.insert(episode_info)
|
||||
@@ -48,11 +52,11 @@ class Episode(MediaBase):
|
||||
# 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'), info = info, single = True)
|
||||
handle('show.episode.update_extras', episode, info, store = True, single = True)
|
||||
|
||||
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 self.shuttingDown():
|
||||
@@ -69,26 +73,35 @@ class Episode(MediaBase):
|
||||
|
||||
info = fireEvent(
|
||||
'episode.info', show.get('identifiers'), {
|
||||
'season_identifier': season.get('info', {}).get('number'),
|
||||
'episode_identifier': episode.get('identifiers')
|
||||
'season_identifiers': season.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
|
||||
)
|
||||
|
||||
identifiers = info.pop('identifiers', None) or identifiers
|
||||
|
||||
# Update/create media
|
||||
if force:
|
||||
episode['identifiers'].update(identifiers)
|
||||
episode.update({'info': info})
|
||||
|
||||
episode['identifiers'].update(info['identifiers'])
|
||||
if 'identifiers' in info:
|
||||
del info['identifiers']
|
||||
self.updateExtras(episode, info)
|
||||
|
||||
episode.update({'info': info})
|
||||
e = db.update(episode)
|
||||
episode.update(e)
|
||||
db.update(episode)
|
||||
return episode
|
||||
|
||||
def updateExtras(self, episode, info, store=False):
|
||||
db = get_db()
|
||||
|
||||
# Get images
|
||||
image_urls = info.get('images', [])
|
||||
existing_files = episode.get('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._setup()
|
||||
|
||||
search_string = simplifyString(q)
|
||||
cache_key = 'thetvdb.cache.search.%s.%s' % (search_string, limit)
|
||||
query = q
|
||||
#query = simplifyString(query)
|
||||
cache_key = 'thetvdb.cache.search.%s.%s' % (query, limit)
|
||||
results = self.getCache(cache_key)
|
||||
|
||||
if not results:
|
||||
@@ -69,9 +70,9 @@ class TheTVDb(ShowProvider):
|
||||
|
||||
raw = None
|
||||
try:
|
||||
raw = self.tvdb.search(search_string)
|
||||
raw = self.tvdb.search(query)
|
||||
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
|
||||
|
||||
results = []
|
||||
@@ -129,22 +130,17 @@ class TheTVDb(ShowProvider):
|
||||
|
||||
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.
|
||||
identifier is the show 'id'
|
||||
"""
|
||||
if not identifier:
|
||||
return False
|
||||
if not identifiers or not identifiers.get('thetvdb'):
|
||||
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
|
||||
# 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)
|
||||
cache_key = 'thetvdb.cache.%s.%s' % (identifier, season_number)
|
||||
log.debug('Getting SeasonInfo: %s', cache_key)
|
||||
result = self.getCache(cache_key) or {}
|
||||
if result:
|
||||
@@ -158,12 +154,12 @@ class TheTVDb(ShowProvider):
|
||||
|
||||
result = []
|
||||
for number, season in show.items():
|
||||
if season_identifier is not None and number == season_identifier:
|
||||
result = self._parseSeason(show, (number, season))
|
||||
if season_number is not None and number == season_number:
|
||||
result = self._parseSeason(show, number, season)
|
||||
self.setCache(cache_key, result)
|
||||
return result
|
||||
else:
|
||||
result.append(self._parseSeason(show, (number, season)))
|
||||
result.append(self._parseSeason(show, number, season))
|
||||
|
||||
self.setCache(cache_key, result)
|
||||
return result
|
||||
@@ -172,22 +168,22 @@ class TheTVDb(ShowProvider):
|
||||
"""Either return a list of all episodes or a single episode.
|
||||
If episode_identifer contains an episode number to search for
|
||||
"""
|
||||
season_identifier = self.getIdentifier(params.get('season_identifier', None))
|
||||
episode_identifier = self.getIdentifier(params.get('episode_identifier', None))
|
||||
season_number = self.getIdentifier(params.get('season_number', None))
|
||||
episode_identifier = self.getIdentifier(params.get('episode_identifiers', None))
|
||||
identifier = self.getIdentifier(identifier)
|
||||
|
||||
if not identifier and season_identifier is None:
|
||||
if not identifier and season_number is None:
|
||||
return False
|
||||
|
||||
# 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 not identifier and season_identifier:
|
||||
if not identifier and season_number:
|
||||
try:
|
||||
identifier, season_identifier = season_identifier.split(':')
|
||||
season_identifier = int(season_identifier)
|
||||
identifier, season_number = season_number.split(':')
|
||||
season_number = int(season_number)
|
||||
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)
|
||||
result = self.getCache(cache_key) or {}
|
||||
if result:
|
||||
@@ -201,7 +197,7 @@ class TheTVDb(ShowProvider):
|
||||
|
||||
result = []
|
||||
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
|
||||
|
||||
for episode in season.values():
|
||||
|
||||
Regular → Executable
+72
-50
@@ -5,6 +5,8 @@ from couchpotato.core.media.show.providers.base import ShowProvider
|
||||
|
||||
log = CPLog(__name__)
|
||||
|
||||
autoload = 'Xem'
|
||||
|
||||
|
||||
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_all_names'] = u"%(base_url)s/map/allNames?" % self.config
|
||||
|
||||
# TODO: Also get show aliases (store as titles)
|
||||
def getShowInfo(self, identifier = None):
|
||||
def getShowInfo(self, identifiers = None):
|
||||
if self.isDisabled():
|
||||
return {}
|
||||
|
||||
identifier = identifiers.get('thetvdb')
|
||||
|
||||
if not identifier:
|
||||
return {}
|
||||
|
||||
cache_key = 'xem.cache.%s' % identifier
|
||||
log.debug('Getting showInfo: %s', cache_key)
|
||||
result = self.getCache(cache_key) or {}
|
||||
if result:
|
||||
return result
|
||||
|
||||
result['seasons'] = {}
|
||||
|
||||
# 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)
|
||||
if response:
|
||||
if response.get('result') == 'success':
|
||||
data = response.get('data', None)
|
||||
result = self._parse(data)
|
||||
|
||||
if response and response.get('result') == 'success':
|
||||
data = response.get('data', None)
|
||||
self.parseMaps(result, data)
|
||||
|
||||
# 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)
|
||||
if response:
|
||||
if response.get('result') == 'success':
|
||||
data = response.get('data', None)
|
||||
result.update({'map_names': data})
|
||||
|
||||
if response and response.get('result') == 'success':
|
||||
data = response.get('data', None)
|
||||
self.parseNames(result, data)
|
||||
|
||||
self.setCache(cache_key, result)
|
||||
return result
|
||||
|
||||
def getEpisodeInfo(self, identifier = None, params = {}):
|
||||
episode = params.get('episode', None)
|
||||
if episode is None:
|
||||
def getEpisodeInfo(self, identifiers = None, params = {}):
|
||||
episode_num = params.get('episode_number', None)
|
||||
if episode_num is None:
|
||||
return False
|
||||
|
||||
season_identifier = params.get('season_identifier', None)
|
||||
if season_identifier is None:
|
||||
season_num = params.get('season_number', None)
|
||||
if season_num is None:
|
||||
return False
|
||||
|
||||
episode_identifier = params.get('episode_identifier', None)
|
||||
absolute = params.get('absolute', None)
|
||||
result = self.getShowInfo(identifiers)
|
||||
|
||||
# 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
|
||||
if not result:
|
||||
return False
|
||||
|
||||
result = self.getShowInfo(identifier)
|
||||
map = {}
|
||||
if result:
|
||||
map_episode = result.get('map_episode', {}).get(season, {}).get(episode, {})
|
||||
if map_episode:
|
||||
map.update({'map_episode': map_episode})
|
||||
# Find season
|
||||
if season_num not in result['seasons']:
|
||||
return False
|
||||
|
||||
if absolute:
|
||||
map_absolute = result.get('map_absolute', {}).get(absolute, {})
|
||||
if map_absolute:
|
||||
map.update({'map_absolute': map_absolute})
|
||||
season = result['seasons'][season_num]
|
||||
|
||||
map_names = result.get('map_names', {}).get(toUnicode(season), {})
|
||||
if map_names:
|
||||
map.update({'map_names': map_names})
|
||||
# Find episode
|
||||
if episode_num not in season['episodes']:
|
||||
return False
|
||||
|
||||
return map
|
||||
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
|
||||
|
||||
To retreive map for scene:
|
||||
@@ -152,17 +147,44 @@ class Xem(ShowProvider):
|
||||
print map['map_episode'][1][1]['scene']['season']
|
||||
'''
|
||||
if not isinstance(data, list):
|
||||
return {}
|
||||
return
|
||||
|
||||
map = {'map_episode': {}, 'map_absolute': {}}
|
||||
for maps in data:
|
||||
origin = maps.pop(master, None)
|
||||
for episode_map in data:
|
||||
origin = episode_map.pop(master, None)
|
||||
if origin is None:
|
||||
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())
|
||||
continue # No master origin to map to
|
||||
|
||||
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):
|
||||
if __name__ == '__main__':
|
||||
|
||||
@@ -14,16 +14,14 @@ class Season(MediaBase):
|
||||
|
||||
def __init__(self):
|
||||
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):
|
||||
if not info: info = {}
|
||||
|
||||
identifiers = info.get('identifiers')
|
||||
try: del info['identifiers']
|
||||
except: pass
|
||||
try: del info['episodes']
|
||||
except: pass
|
||||
identifiers = info.pop('identifiers', None)
|
||||
info.pop('episodes', None)
|
||||
|
||||
# Add Season
|
||||
season_info = {
|
||||
@@ -43,6 +41,7 @@ class Season(MediaBase):
|
||||
if existing_season:
|
||||
s = existing_season['doc']
|
||||
s.update(season_info)
|
||||
|
||||
season = db.update(s)
|
||||
else:
|
||||
season = db.insert(season_info)
|
||||
@@ -50,11 +49,11 @@ class Season(MediaBase):
|
||||
# Update library info
|
||||
if update_after is not False:
|
||||
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
|
||||
|
||||
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 self.shuttingDown():
|
||||
@@ -63,25 +62,33 @@ class Season(MediaBase):
|
||||
db = get_db()
|
||||
|
||||
season = db.get('id', media_id)
|
||||
show = db.get('id', season['parent_id'])
|
||||
|
||||
# Get new 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
|
||||
if force:
|
||||
season['identifiers'].update(identifiers)
|
||||
season.update({'info': info})
|
||||
|
||||
season['identifiers'].update(info['identifiers'])
|
||||
if 'identifiers' in info:
|
||||
del info['identifiers']
|
||||
self.updateExtras(season, info)
|
||||
|
||||
season.update({'info': info})
|
||||
s = db.update(season)
|
||||
season.update(s)
|
||||
db.update(season)
|
||||
return season
|
||||
|
||||
def updateExtras(self, season, info, store=False):
|
||||
db = get_db()
|
||||
|
||||
# Get images
|
||||
image_urls = info.get('images', [])
|
||||
existing_files = season.get('files', {})
|
||||
self.getPoster(image_urls, existing_files)
|
||||
|
||||
return season
|
||||
if store:
|
||||
db.update(season)
|
||||
|
||||
@@ -62,7 +62,7 @@ class Dashboard(Plugin):
|
||||
for media_id in active_ids:
|
||||
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
|
||||
|
||||
eta = media['info'].get('release_date', {}) or {}
|
||||
|
||||
Regular → Executable
+1
-1
@@ -219,7 +219,7 @@ class Manage(Plugin):
|
||||
|
||||
# Add it to release and update the info
|
||||
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
|
||||
|
||||
|
||||
Regular → Executable
+1
-1
@@ -247,7 +247,7 @@ class Renamer(Plugin):
|
||||
'profile_id': None
|
||||
}, search_after = False, status = 'done', single = True)
|
||||
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'):
|
||||
log.error('Could not rename, no library item to work with: %s', group_identifier)
|
||||
|
||||
Regular → Executable
+1
-1
@@ -705,7 +705,7 @@ class Tvdb:
|
||||
for k, v in banners[btype][btype2][bid].items():
|
||||
if k.endswith("path"):
|
||||
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)
|
||||
banners[btype][btype2][bid][new_key] = new_url
|
||||
|
||||
|
||||
Reference in New Issue
Block a user