This commit is contained in:
Ruud
2014-03-18 22:28:22 +01:00
parent cfc9f524a7
commit 9cfa7fa2a3
5 changed files with 375 additions and 229 deletions
+212 -48
View File
@@ -1,11 +1,14 @@
import time
import traceback
from couchpotato import get_session
from couchpotato import get_db
from couchpotato.api import addApiView
from couchpotato.core.event import fireEvent, fireEventAsync, addEvent
from couchpotato.core.helpers.variable import tryInt
from couchpotato.core.helpers.encoding import simplifyString
from couchpotato.core.helpers.variable import getTitle
from couchpotato.core.logger import CPLog
from couchpotato.core.media import MediaBase
from qcond import QueryCondenser
log = CPLog(__name__)
@@ -30,15 +33,217 @@ class ShowBase(MediaBase):
})
addEvent('show.add', self.add)
addEvent('show.update_info', self.add)
addEvent('show.update_info', self.updateInfo)
addEvent('media.search_query', self.query)
def query(self, library, first = True, condense = True, **kwargs):
if library is list or library.get('type') != 'show':
def addView(self, **kwargs):
add_dict = self.add(params = kwargs)
return {
'success': True if add_dict else False,
'show': add_dict,
}
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.'
log.error(msg)
fireEvent('notify.frontend', type = 'show.no_identifier', message = msg)
return False
info = params.get('info')
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)
season_info = info.get('seasons', [])
# 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 = db.run('media', 'identifiers', params.get('identifiers'), with_doc = 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 db.run('release', 'for_media', m['_id']):
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'], on_complete = onComplete)
# Remove releases
for rel in db.run('release', 'for_media', m['_id']):
if rel['status'] is 'available':
db.delete(rel)
movie_dict = db.run('media', 'to_dict', m['_id'])
if do_search and search_after:
onComplete = self.createOnComplete(m['_id'])
onComplete()
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 = 'movie.added', data = movie_dict, message = message)
return movie_dict
except:
log.error('Failed adding media: %s', traceback.format_exc())
# Add Seasons
for season_info in info.get('seasons', []):
season = fireEvent('show.season.add', media.get('_id'), season_info)
for episode_info in season_info.get('seasons', []):
fireEvent('show.episode.add', season.get('_id'), episode_info)
def updateInfo(self, media_id = None, identifiers = None):
"""
Update movie information inside media['doc']['info']
@param media_id: document id
@param identifiers: identifiers from multiple providers
{
'thetvdb': 123,
'imdb': 'tt123123',
..
}
@param extended: update with extended info (parses more info, actors, images from some info providers)
@return: dict, with media
"""
if self.shuttingDown():
return
titles = [title['title'] for title in library['titles']]
try:
db = get_db()
if media_id:
media = db.get('id', media_id)
else:
media = db.get('media', identifiers, with_doc = True)['doc']
info = fireEvent('show.info', identifiers = media.get('identifiers'), merge = True)
# Don't need those here
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', [])
existing_files = media.get('files', {})
self.getPoster(image_urls, existing_files)
db.update(media)
return media
except:
log.error('Failed update media: %s', traceback.format_exc())
return {}
def query(self, media, first = True, condense = True, **kwargs):
if media.get('type') != 'show':
return
titles = media['info']['titles']
if condense:
# Use QueryCondenser to build a list of optimal search titles
@@ -49,50 +254,9 @@ class ShowBase(MediaBase):
titles = condensed_titles
else:
# Fallback to simplifying titles
titles = [simplify(title) for title in titles]
titles = [simplifyString(title) for title in titles]
if first:
return titles[0] if titles else None
return titles
def addView(self, **kwargs):
add_dict = self.add(params = kwargs)
return {
'success': True if add_dict else False,
'show': add_dict,
}
def add(self, params = {}, force_readd = True, search_after = True, update_library = False, status = None):
db = get_db()
# Add Show
show = {
'identifiers': {
'imdb': 'tt1234',
'thetvdb': 123,
'tmdb': 123,
'rage': 123
},
'status': 'active',
'title': title,
'description': description,
'profile_id': profile_id,
'category_id': category_id,
'primary_provider': 'thetvdb',
'absolute_nr': True,
'info': {}
}
show_info = fireEvent('show.info', show.get('identifiers'))
# Add Seasons
for season_info in show_info.get('seasons', []):
season = fireEvent('show.season.add', show.get('_id'), season_info)
for episode_info in season_info.get('seasons', []):
fireEvent('show.episode.add', season.get('_id'), episode_info)
@@ -98,10 +98,8 @@ Block.Search.ShowItem = new Class({
Api.request('show.add', {
'data': {
'identifier': self.info.id,
'id': self.info.id,
'identifiers': self.info.identifiers,
'type': self.info.type,
'primary_provider': self.info.primary_provider,
'title': self.title_select.get('value'),
'profile_id': self.profile_select.get('value'),
'category_id': self.category_select.get('value')
+49 -47
View File
@@ -16,7 +16,55 @@ class Episode(Plugin):
addEvent('media.identifier', self.identifier)
addEvent('show.episode.add', self.add)
addEvent('show.episode.update_info', self.update)
addEvent('show.episode.update_info', self.updateInfo)
def add(self, parent_id, update_after = True):
# Add Season
season = {
'_t': 'media',
'type': 'episode',
'nr': 1,
'identifiers': {
'imdb': 'tt1234',
'thetvdb': 123,
'tmdb': 123,
'rage': 123
},
'parent': '_id',
'info': {}, # Returned dict by providers
}
episode_exists = True or False
if episode_exists:
pass #update existing
else:
pass # Add Episode
# Update library info
if update_after is not False:
handle = fireEventAsync if update_after is 'async' else fireEvent
handle('show.episode.update_info', season.get('_id'), default_title = toUnicode(attrs.get('title', '')))
return season
def updateInfo(self, media_id = None, default_title = '', force = False):
if self.shuttingDown():
return
# Get new info
fireEvent('episode.info', merge = True)
# Update/create media
# Get images
return info
def query(self, library, first = True, condense = True, include_identifier = True, **kwargs):
if library is list or library.get('type') != 'episode':
@@ -77,49 +125,3 @@ class Episode(Plugin):
identifier['episode'] = tryInt(identifier['episode'], None)
return identifier
def add(self, parent_id, update_after = True):
# Add Season
season = {
'nr': 1,
'identifiers': {
'imdb': 'tt1234',
'thetvdb': 123,
'tmdb': 123,
'rage': 123
},
'parent': '_id',
'info': {}, # Returned dict by providers
}
episode_exists = True or False
if episode_exists:
pass #update existing
else:
pass # Add Episode
# Update library info
if update_after is not False:
handle = fireEventAsync if update_after is 'async' else fireEvent
handle('show.episode.update_info', season.get('_id'), default_title = toUnicode(attrs.get('title', '')))
return season
def update_info(self, media_id = None, default_title = '', force = False):
if self.shuttingDown():
return
# Get new info
fireEvent('episode.info', merge = True)
# Update/create media
# Get images
return info
@@ -1,12 +1,14 @@
from datetime import datetime
import traceback
import os
import traceback
from couchpotato import Env
from couchpotato.core.event import addEvent
from couchpotato.core.helpers.encoding import simplifyString, toUnicode
from couchpotato.core.helpers.variable import splitString, tryInt, tryFloat
from couchpotato.core.logger import CPLog
from couchpotato.core.media.show.providers.base import ShowProvider
from couchpotato.environment import Env
from tvdb_api import tvdb_exceptions
from tvdb_api.tvdb_api import Tvdb
@@ -35,7 +37,7 @@ class TheTVDb(ShowProvider):
'banners': True,
'language': 'en',
'cache': os.path.join(Env.get('cache_dir'), 'thetvdb_api'),
}
}
self._setup()
def _setup(self):
@@ -59,11 +61,12 @@ class TheTVDb(ShowProvider):
self._setup()
search_string = simplifyString(q)
cache_key = 'thetvdb.cache.%s.%s' % (search_string, limit)
cache_key = 'thetvdb.cache.search.%s.%s' % (search_string, limit)
results = self.getCache(cache_key)
if not results:
log.debug('Searching for show: %s', q)
raw = None
try:
raw = self.tvdb.search(search_string)
@@ -76,17 +79,19 @@ class TheTVDb(ShowProvider):
try:
nr = 0
for show_info in raw:
show = self.tvdb[int(show_info['id'])]
results.append(self._parseShow(show))
results.append(self._parseShow(show_info))
nr += 1
if nr == limit:
break
log.info('Found: %s', [result['titles'][0] + ' (' + str(result.get('year', 0)) + ')' for result in results])
self.setCache(cache_key, results)
return results
except (tvdb_exceptions.tvdb_error, IOError), e:
log.error('Failed parsing TheTVDB for "%s": %s', (show, traceback.format_exc()))
log.error('Failed parsing TheTVDB for "%s": %s', (q, traceback.format_exc()))
return False
return results
def getShow(self, identifier = None):
@@ -100,13 +105,20 @@ class TheTVDb(ShowProvider):
return show
def getShowInfo(self, identifier = None):
if not identifier:
def getShowInfo(self, identifiers = None):
"""
@param identifiers: dict with identifiers per provider
@return: Full show info including season and episode info
"""
if not identifiers or not identifiers.get('thetvdb'):
return None
cache_key = 'thetvdb.cache.%s' % identifier
log.debug('Getting showInfo: %s', cache_key)
result = self.getCache(cache_key) or {}
identifier = tryInt(identifiers.get('thetvdb'))
cache_key = 'thetvdb.cache.show.%s' % identifier
result = self.getCache(cache_key)
if result:
return result
@@ -115,7 +127,7 @@ class TheTVDb(ShowProvider):
result = self._parseShow(show)
self.setCache(cache_key, result)
return result
return result or {}
def getSeasonInfo(self, identifier = None, params = {}):
"""Either return a list of all seasons or a single season by number.
@@ -203,65 +215,33 @@ class TheTVDb(ShowProvider):
return result
def _parseShow(self, show):
"""
'actors': u'|Bryan Cranston|Aaron Paul|Dean Norris|RJ Mitte|Betsy Brandt|Anna Gunn|Laura Fraser|Jesse Plemons|Christopher Cousins|Steven Michael Quezada|Jonathan Banks|Giancarlo Esposito|Bob Odenkirk|',
'added': None,
'addedby': None,
'airs_dayofweek': u'Sunday',
'airs_time': u'9:00 PM',
'banner': u'http://thetvdb.com/banners/graphical/81189-g13.jpg',
'contentrating': u'TV-MA',
'fanart': u'http://thetvdb.com/banners/fanart/original/81189-28.jpg',
'firstaired': u'2008-01-20',
'genre': u'|Crime|Drama|Suspense|',
'id': u'81189',
'imdb_id': u'tt0903747',
'language': u'en',
'lastupdated': u'1376620212',
'network': u'AMC',
'networkid': None,
'overview': u"Walter White, a struggling high school chemistry teacher is diagnosed with advanced lung cancer. He turns to a life of crime, producing and selling methamphetamine accompanied by a former student, Jesse Pinkman with the aim of securing his family's financial future before he dies.",
'poster': u'http://thetvdb.com/banners/posters/81189-22.jpg',
'rating': u'9.3',
'ratingcount': u'473',
'runtime': u'60',
'seriesid': u'74713',
'seriesname': u'Breaking Bad',
'status': u'Continuing',
'zap2it_id': u'SH01009396'
"""
#
# NOTE: show object only allows direct access via
# show['id'], not show.get('id')
#
# TODO: Make sure we have a valid show id, not '' or None
#if len (show['id']) is 0:
# return None
def get(name):
return show.get(name) if not hasattr(show, 'search') else show[name]
## Images
poster = show['poster'] or None
backdrop = show['fanart'] or None
poster = get('poster')
backdrop = get('fanart')
genres = [] if show['genre'] is None else show['genre'].strip('|').split('|')
if show['firstaired'] is not None:
try: year = datetime.strptime(show['firstaired'], '%Y-%m-%d').year
genres = splitString(get('genre'), '|')
if get('firstaired') is not None:
try: year = datetime.strptime(get('firstaired'), '%Y-%m-%d').year
except: year = None
else:
year = None
try:
id = int(show['id'])
except:
id = None
show_data = {
'id': id,
'identifiers': {
'thetvdb': tryInt(get('seriesid')),
'imdb': get('imdb_id'),
'zap2it': get('zap2it_id'),
},
'type': 'show',
'primary_provider': 'thetvdb',
'titles': [show['seriesname'] or u'', ],
'original_title': show['seriesname'] or u'',
'titles': [get('seriesname')],
'images': {
'poster': [poster] if poster else [],
'backdrop': [backdrop] if backdrop else [],
@@ -270,37 +250,37 @@ class TheTVDb(ShowProvider):
},
'year': year,
'genres': genres,
'imdb': show['imdb_id'] or None,
'zap2it_id': show['zap2it_id'] or None,
'seriesid': show['seriesid'] or None,
'network': show['network'] or None,
'networkid': show['networkid'] or None,
'airs_dayofweek': show['airs_dayofweek'] or None,
'airs_time': show['airs_time'] or None,
'firstaired': show['firstaired'] or None,
'released': show['firstaired'] or None,
'runtime': show['runtime'] or None,
'contentrating': show['contentrating'] or None,
'rating': show['rating'] or None,
'ratingcount': show['ratingcount'] or None,
'actors': show['actors'] or None,
'lastupdated': show['lastupdated'] or None,
'status': show['status'] or None,
'language': show['language'] or None,
'network': get('network'),
'plot': get('overview'),
'networkid': get('networkid'),
'airs_dayofweek': get('airs_dayofweek'),
'airs_time': get('airs_time'),
'firstaired': get('firstaired'),
'released': get('firstaired'),
'runtime': get('runtime'),
'contentrating': get('contentrating'),
'rating': {
'thetvdb': [tryFloat(get('rating')), tryInt(get('ratingcount'))],
},
'actors': splitString(get('actors'), '|'),
'lastupdated': get('lastupdated'),
'status': get('status'),
'language': get('language'),
}
show_data = dict((k, v) for k, v in show_data.iteritems() if v)
# Add alternative titles
try:
raw = self.tvdb.search(show['seriesname'])
if raw:
for show_info in raw:
if show_info['id'] == show_data['id'] and show_info.get('aliasnames', None):
for alt_name in show_info['aliasnames'].split('|'):
show_data['titles'].append(toUnicode(alt_name))
except (tvdb_exceptions.tvdb_error, IOError), e:
log.error('Failed searching TheTVDB for "%s": %s', (show['seriesname'], traceback.format_exc()))
# try:
# raw = self.tvdb.search(show['seriesname'])
# if raw:
# for show_info in raw:
# print show_info
# if show_info['id'] == show_data['id'] and show_info.get('aliasnames', None):
# for alt_name in show_info['aliasnames'].split('|'):
# show_data['titles'].append(toUnicode(alt_name))
# except (tvdb_exceptions.tvdb_error, IOError), e:
# log.error('Failed searching TheTVDB for "%s": %s', (show['seriesname'], traceback.format_exc()))
return show_data
+49 -47
View File
@@ -18,6 +18,55 @@ class Season(Plugin):
addEvent('show.season.add', self.update)
addEvent('show.season.update_info', self.update)
def add(self, parent_id, update_after = True):
# Add Season
season = {
'_t': 'media',
'type': 'season',
'nr': 1,
'identifiers': {
'imdb': 'tt1234',
'thetvdb': 123,
'tmdb': 123,
'rage': 123
},
'parent': '_id',
'info': {}, # Returned dict by providers
}
# Check if season already exists
season_exists = True or False
if season_exists:
pass #update existing
else:
db.insert(season)
# 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'))
return season
def update_info(self, media_id = None, default_title = '', force = False):
if self.shuttingDown():
return
# Get new info
fireEvent('season.info', merge = True)
# Update/create media
# Get images
return info
def query(self, library, first = True, condense = True, include_identifier = True, **kwargs):
if library is list or library.get('type') != 'season':
return
@@ -65,50 +114,3 @@ class Season(Plugin):
return {
'season': tryInt(library['season_number'], None)
}
def add(self, parent_id, update_after = True):
# Add Season
season = {
'nr': 1,
'identifiers': {
'imdb': 'tt1234',
'thetvdb': 123,
'tmdb': 123,
'rage': 123
},
'parent': '_id',
'info': {}, # Returned dict by providers
}
# Check if season already exists
season_exists = True or False
if season_exists:
pass #update existing
else:
db.insert(season)
# 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'))
return season
def update_info(self, media_id = None, default_title = '', force = False):
if self.shuttingDown():
return
# Get new info
fireEvent('season.info', merge = True)
# Update/create media
# Get images
return info