class TMDBMovie(TMDBContainer, Base): __tablename__ = 'tmdb_movies' id = Column(Integer, primary_key=True, autoincrement=False, nullable=False) updated = Column(DateTime, default=datetime.now, nullable=False) popularity = Column(Integer) translated = Column(Boolean) adult = Column(Boolean) language = Column(String) original_name = Column(Unicode) name = Column(Unicode) alternative_name = Column(Unicode) movie_type = Column(String) imdb_id = Column(String) url = Column(String) votes = Column(Integer) rating = Column(Float) certification = Column(String) overview = Column(Unicode) runtime = Column(Integer) tagline = Column(Unicode) budget = Column(Integer) revenue = Column(Integer) homepage = Column(String) trailer = Column(String) _released = Column('released', DateTime) released = text_date_synonym('_released') year = year_property('released') posters = relation('TMDBPoster', backref='movie', cascade='all, delete, delete-orphan') genres = relation('TMDBGenre', secondary=genres_table, backref='movies')
class TMDBMovie(TMDBContainer, Base): __tablename__ = 'tmdb_movies' id = Column(Integer, primary_key=True, autoincrement=False, nullable=False) updated = Column(DateTime, default=datetime.now, nullable=False) popularity = Column(Integer) translated = Column(Boolean) adult = Column(Boolean) language = Column(String) original_name = Column(Unicode) name = Column(Unicode) alternative_name = Column(Unicode) movie_type = Column(String) imdb_id = Column(String) url = Column(String) votes = Column(Integer) rating = Column(Float) certification = Column(String) overview = Column(Unicode) runtime = Column(Integer) tagline = Column(Unicode) budget = Column(Integer) revenue = Column(Integer) homepage = Column(String) trailer = Column(String) _released = Column('released', DateTime) released = text_date_synonym('_released') year = year_property('released') posters = relation('TMDBPoster', backref='movie', cascade='all, delete, delete-orphan') genres = relation('TMDBGenre', secondary=genres_table, backref='movies') def update_from_object(self, update_object): try: TMDBContainer.update_from_object(self, update_object) self.translated = len(update_object.translations) > 0 if len(update_object.languages) > 0: self.language = update_object.languages[0].code # .code or .name ? self.original_name = update_object.originaltitle self.name = update_object.title try: if len(update_object.alternate_titles) > 0: # maybe we could choose alternate title from movie country only self.alternative_name = update_object.alternate_titles[0].title except UnicodeEncodeError: # Bug in tmdb3 library, see #2437. Just don't set alternate_name when it fails pass self.imdb_id = update_object.imdb self.url = update_object.homepage self.rating = update_object.userrating if len(update_object.youtube_trailers) > 0: self.trailer = update_object.youtube_trailers[0].source # unicode: ooNSm6Uug3g elif len(update_object.apple_trailers) > 0: self.trailer = update_object.apple_trailers[0].source self.released = update_object.releasedate except tmdb3.TMDBError as e: raise LookupError('Error updating data from tmdb: %s' % e)
class ReleaseDate(Base): __tablename__ = 'rottentomatoes_releasedates' db_id = Column(Integer, primary_key=True) movie_id = Column(Integer, ForeignKey('rottentomatoes_movies.id')) name = Column(String) date = text_date_synonym('_date') _date = Column('date', DateTime) def __init__(self, name, date): self.name = name self.date = date
class TVDBSeries(TVDBContainer, Base): __tablename__ = "tvdb_series" id = Column(Integer, primary_key=True, autoincrement=False) lastupdated = Column(Integer) expired = Column(Boolean) seriesname = Column(Unicode) language = Column(Unicode) rating = Column(Float) status = Column(Unicode) runtime = Column(Integer) airs_time = Column(Unicode) airs_dayofweek = Column(Unicode) contentrating = Column(Unicode) network = Column(Unicode) imdb_id = Column(String) zap2it_id = Column(String) banner = Column(String) fanart = Column(String) poster = Column(String) poster_file = Column(Unicode) _genre = Column('genre', Unicode) genre = pipe_list_synonym('_genre') _firstaired = Column('firstaired', DateTime) firstaired = text_date_synonym('_firstaired') episodes = relation('TVDBEpisode', backref='series', cascade='all, delete, delete-orphan') def update(self): if not self.id: raise LookupError('Cannot update a series without a tvdb id.') url = get_mirror() + api_key + '/series/%s/%s.xml' % (self.id, language) try: data = requests.get(url).content except RequestException, e: raise LookupError('Request failed %s' % url) result = BeautifulStoneSoup( data, convertEntities=BeautifulStoneSoup.HTML_ENTITIES).find('series') if result: self.update_from_bss(result) else: raise LookupError('Could not retrieve information from thetvdb')
class TVDBEpisode(TVDBContainer, Base): __tablename__ = 'tvdb_episodes' id = Column(Integer, primary_key=True, autoincrement=False) expired = Column(Boolean) lastupdated = Column(Integer) seasonnumber = Column(Integer) episodenumber = Column(Integer) absolute_number = Column(Integer) episodename = Column(Unicode) overview = Column(Unicode) _director = Column('director', Unicode) director = pipe_list_synonym('_director') _writer = Column('writer', Unicode) writer = pipe_list_synonym('_writer') _gueststars = Column('gueststars', Unicode) gueststars = pipe_list_synonym('_gueststars') rating = Column(Float) filename = Column(Unicode) _firstaired = Column('firstaired', DateTime) firstaired = text_date_synonym('_firstaired') series_id = Column(Integer, ForeignKey('tvdb_series.id'), nullable=False) def update(self): if not self.id: raise LookupError( 'Cannot update an episode without an episode id.') url = get_mirror() + api_key + '/episodes/%s/%s.xml' % (self.id, language) try: data = requests.get(url).content except RequestException as e: raise LookupError('Request failed %s' % url) result = BeautifulStoneSoup( data, convertEntities=BeautifulStoneSoup.HTML_ENTITIES).find('episode') if result: self.update_from_bss(result) else: raise LookupError('Could not retrieve information from thetvdb') def __repr__(self): return '<TVDBEpisode series=%s,season=%s,episode=%s>' %\ (self.series.seriesname, self.seasonnumber, self.episodenumber)
class TVDBEpisode(Base): __tablename__ = 'tvdb_episodes' id = Column(Integer, primary_key=True, autoincrement=False) expired = Column(Boolean) last_updated = Column(Integer) season_number = Column(Integer) episode_number = Column(Integer) absolute_number = Column(Integer) name = Column(Unicode) overview = Column(Unicode) rating = Column(Float) director = Column(Unicode) _image = Column(Unicode) _first_aired = Column('firstaired', DateTime) first_aired = text_date_synonym('_first_aired') series_id = Column(Integer, ForeignKey('tvdb_series.id'), nullable=False) def __init__(self, id): """ Looks up movie on tvdb and creates a new database model for it. These instances should only be added to a session via `session.merge`. """ self.id = id try: episode = TVDBRequest().get('episodes/%s' % self.id) except requests.RequestException as e: raise LookupError('Error updating data from tvdb: %s' % e) self.id = episode['id'] self.last_updated = episode['lastUpdated'] self.season_number = episode['airedSeason'] self.episode_number = episode['airedEpisodeNumber'] self.absolute_number = episode['absoluteNumber'] self.name = episode['episodeName'] self.overview = episode['overview'] self.director = episode['director'] self._image = episode['filename'] self.rating = episode['siteRating'] self.first_aired = episode['firstAired'] def __repr__(self): return '<TVDBEpisode series=%s,season=%s,episode=%s>' % \ (self.series.name, self.season_number, self.episode_number) def to_dict(self): return { 'id': self.id, 'expired': self.expired, 'last_update': self.last_updated, 'season_number': self.season_number, 'episode_number': self.episode_number, 'absolute_number': self.absolute_number, 'episode_name': self.name, 'overview': self.overview, 'director': self.director, 'rating': self.rating, 'image': self.image, 'first_aired': self.first_aired, 'series_id': self.series_id } @property def image(self): if self._image: return TVDBRequest.BANNER_URL + self._image
class TVDBSeries(Base): __tablename__ = "tvdb_series" id = Column(Integer, primary_key=True, autoincrement=False) last_updated = Column(Integer) expired = Column(Boolean) name = Column(Unicode) language = Column(Unicode) rating = Column(Float) status = Column(Unicode) runtime = Column(Integer) airs_time = Column(Unicode) airs_dayofweek = Column(Unicode) content_rating = Column(Unicode) network = Column(Unicode) overview = Column(Unicode) imdb_id = Column(Unicode) zap2it_id = Column(Unicode) _banner = Column('banner', Unicode) _first_aired = Column('first_aired', DateTime) first_aired = text_date_synonym('_first_aired') _aliases = Column('aliases', Unicode) aliases = json_synonym('_aliases') _actors = Column('actors', Unicode) actors_list = json_synonym('_actors') _posters = Column('posters', Unicode) posters_list = json_synonym('_posters') _genres = relation('TVDBGenre', secondary=genres_table) genres = association_proxy('_genres', 'name') episodes = relation('TVDBEpisode', backref='series', cascade='all, delete, delete-orphan') def __init__(self, tvdb_id): """ Looks up movie on tvdb and creates a new database model for it. These instances should only be added to a session via `session.merge`. """ self.id = tvdb_id try: series = TVDBRequest().get('series/%s' % self.id) except requests.RequestException as e: raise LookupError('Error updating data from tvdb: %s' % e) self.id = series['id'] self.language = 'en' self.last_updated = series['lastUpdated'] self.name = series['seriesName'] self.rating = float( series['siteRating']) if series['siteRating'] else 0.0 self.status = series['status'] self.runtime = int(series['runtime']) if series['runtime'] else 0 self.airs_time = series['airsTime'] self.airs_dayofweek = series['airsDayOfWeek'] self.content_rating = series['rating'] self.network = series['network'] self.overview = series['overview'] self.imdb_id = series['imdbId'] self.zap2it_id = series['zap2itId'] self.first_aired = series['firstAired'] self.expired = False self.aliases = series['aliases'] self._banner = series['banner'] self._genres = [TVDBGenre( id=name) for name in series['genre']] if series['genre'] else [] # Actors and Posters are lazy populated self._actors = None self._posters = None def __repr__(self): return '<TVDBSeries name=%s,tvdb_id=%s>' % (self.name, self.id) @property def banner(self): if self._banner: return TVDBRequest.BANNER_URL + self._banner @property def actors(self): return self.get_actors() @property def posters(self): return self.get_posters() def get_actors(self): if not self._actors: log.debug('Looking up actors for series %s' % self.name) try: actors_query = TVDBRequest().get('series/%s/actors' % self.id) self.actors_list = [a['name'] for a in actors_query ] if actors_query else [] except requests.RequestException as e: if None is not e.response and e.response.status_code == 404: self.actors_list = [] else: raise LookupError('Error updating actors from tvdb: %s' % e) return self.actors_list def get_posters(self): if not self._posters: log.debug('Getting top 5 posters for series %s' % self.name) try: poster_query = TVDBRequest().get('series/%s/images/query' % self.id, keyType='poster') self.posters_list = [p['fileName'] for p in poster_query[:5] ] if poster_query else [] except requests.RequestException as e: if None is not e.response and e.response.status_code == 404: self.posters_list = [] else: raise LookupError('Error updating posters from tvdb: %s' % e) return [TVDBRequest.BANNER_URL + p for p in self.posters_list] def to_dict(self): return { 'tvdb_id': self.id, 'last_updated': datetime.fromtimestamp( self.last_updated).strftime('%Y-%m-%d %H:%M:%S'), 'expired': self.expired, 'series_name': self.name, 'language': self.language, 'rating': self.rating, 'status': self.status, 'runtime': self.runtime, 'airs_time': self.airs_time, 'airs_dayofweek': self.airs_dayofweek, 'content_rating': self.content_rating, 'network': self.network, 'overview': self.overview, 'imdb_id': self.imdb_id, 'zap2it_id': self.zap2it_id, 'banner': self.banner, 'posters': self.posters, 'genres': [g for g in self.genres], 'actors': self.actors, 'first_aired': self.first_aired, }
class TVDBSeries(TVDBContainer, Base): __tablename__ = "tvdb_series" id = Column(Integer, primary_key=True, autoincrement=False) lastupdated = Column(Integer) expired = Column(Boolean) seriesname = Column(Unicode) language = Column(Unicode) rating = Column(Float) status = Column(Unicode) runtime = Column(Integer) airs_time = Column(Unicode) airs_dayofweek = Column(Unicode) contentrating = Column(Unicode) network = Column(Unicode) imdb_id = Column(String) zap2it_id = Column(String) banner = Column(String) fanart = Column(String) poster = Column(String) poster_file = Column(Unicode) _genre = Column('genre', Unicode) genre = pipe_list_synonym('_genre') _firstaired = Column('firstaired', DateTime) firstaired = text_date_synonym('_firstaired') episodes = relation('TVDBEpisode', backref='series', cascade='all, delete, delete-orphan') def update(self): if not self.id: raise LookupError('Cannot update a series without a tvdb id.') url = get_mirror() + api_key + '/series/%s/%s.xml' % (self.id, language) try: data = requests.get(url).content except RequestException as e: raise LookupError('Request failed %s' % url) result = BeautifulStoneSoup( data, convertEntities=BeautifulStoneSoup.HTML_ENTITIES).find('series') if result: self.update_from_bss(result) else: raise LookupError('Could not retrieve information from thetvdb') def get_poster(self, only_cached=False): """Downloads this poster to a local cache and returns the path""" from flexget.manager import manager base_dir = os.path.join(manager.config_base, 'userstatic') if os.path.isfile(os.path.join(base_dir, self.poster_file or '')): return self.poster_file elif only_cached: return # If we don't already have a local copy, download one. url = get_mirror('banner') + self.poster log.debug('Downloading poster %s' % url) dirname = os.path.join('tvdb', 'posters') # Create folders if the don't exist fullpath = os.path.join(base_dir, dirname) if not os.path.isdir(fullpath): os.makedirs(fullpath) filename = os.path.join(dirname, posixpath.basename(self.poster)) thefile = file(os.path.join(base_dir, filename), 'wb') thefile.write(requests.get(url).content) self.poster_file = filename # If we are detached from a session, update the db if not Session.object_session(self): session = Session() session.query(TVDBSeries).filter(TVDBSeries.id == self.id).update( values={'poster_file': filename}) session.close() return filename def __repr__(self): return '<TVDBSeries name=%s,tvdb_id=%s>' % (self.seriesname, self.id)
class TVDBSeriesSearchResult(Base): """ This table will hold a single result that results from the /search/series endpoint, which return a series with a minimal set of parameters. """ __tablename__ = 'tvdb_series_search_results' id = Column(Integer, primary_key=True, autoincrement=False) lookup_term = Column(Unicode) name = Column(Unicode) status = Column(Unicode) network = Column(Unicode) overview = Column(Unicode) _banner = Column('banner', Unicode) _first_aired = Column('first_aired', DateTime) first_aired = text_date_synonym('_first_aired') _aliases = Column('aliases', Unicode) aliases = json_synonym('_aliases') created_at = Column(DateTime) search_name = Column(Unicode) def __init__(self, series, lookup_term=None): self.lookup_term = lookup_term self.id = series['id'] self.name = series['seriesName'] self.first_aired = series['firstAired'] self.network = series['network'] self.overview = series['overview'] self.status = series['status'] self._banner = series['banner'] self.aliases = series['aliases'] self.created_at = datetime.now() @property def banner(self): if self._banner: return TVDBRequest.BANNER_URL + self._banner def to_dict(self): return { 'aliases': [a for a in self.aliases], 'banner': self.banner, 'first_aired': self.first_aired, 'tvdb_id': self.id, 'network': self.network, 'overview': self.overview, 'series_name': self.name, 'status': self.status, } @property def expired(self): logger.debug('checking series {} for expiration', self.original_name) if datetime.now() - self.created_at >= timedelta( days=SEARCH_RESULT_EXPIRATION_DAYS): logger.debug('series {} is expires, should re-fetch', self.original_name) return True logger.debug('series {} is not expired', self.original_name) return False
class TMDBMovie(Base): __tablename__ = 'tmdb_movies' id = Column(Integer, primary_key=True, autoincrement=False, nullable=False) imdb_id = Column(Unicode) url = Column(Unicode) name = Column(Unicode) original_name = Column(Unicode) alternative_name = Column(Unicode) _released = Column('released', DateTime) released = text_date_synonym('_released') year = year_property('released') certification = Column(Unicode) runtime = Column(Integer) language = Column(Unicode) overview = Column(Unicode) tagline = Column(Unicode) rating = Column(Float) votes = Column(Integer) popularity = Column(Integer) adult = Column(Boolean) budget = Column(Integer) revenue = Column(Integer) homepage = Column(Unicode) posters = relation('TMDBPoster', backref='movie', cascade='all, delete, delete-orphan') _genres = relation('TMDBGenre', secondary=genres_table, backref='movies') genres = association_proxy('_genres', 'name') updated = Column(DateTime, default=datetime.now, nullable=False) def __init__(self, id): """ Looks up movie on tmdb and creates a new database model for it. These instances should only be added to a session via `session.merge`. """ self.id = id try: movie = tmdb_request( 'movie/{}'.format(self.id), append_to_response='alternative_titles,images') except requests.RequestException as e: raise LookupError('Error updating data from tmdb: %s' % e) self.imdb_id = movie['imdb_id'] self.name = movie['title'] self.original_name = movie['original_title'] self.released = movie['release_date'] self.runtime = movie['runtime'] self.language = movie['original_language'] self.overview = movie['overview'] self.tagline = movie['tagline'] self.rating = movie['vote_average'] self.votes = movie['vote_count'] self.popularity = movie['popularity'] self.adult = movie['adult'] self.budget = movie['budget'] self.revenue = movie['revenue'] self.homepage = movie['homepage'] self.alternative_name = None try: self.alternative_name = movie['alternative_titles']['titles'][0][ 'title'] except (KeyError, IndexError): pass # No alternate titles self._genres = [TMDBGenre(**g) for g in movie['genres']] # Just grab the top 5 posters self.posters = [ TMDBPoster(**p) for p in movie['images']['posters'][:5] ] self.updated = datetime.now()
class TVDBSeries(TVDBContainer, Base): __tablename__ = "tvdb_series" id = Column(Integer, primary_key=True, autoincrement=False) lastupdated = Column(Integer) expired = Column(Boolean) seriesname = Column(Unicode) language = Column(Unicode) rating = Column(Float) status = Column(Unicode) runtime = Column(Integer) airs_time = Column(Unicode) airs_dayofweek = Column(Unicode) contentrating = Column(Unicode) network = Column(Unicode) overview = Column(Unicode) imdb_id = Column(String) zap2it_id = Column(String) banner = Column(String) fanart = Column(String) poster = Column(String) poster_file = Column(Unicode) _genre = Column('genre', Unicode) genre = pipe_list_synonym('_genre') _firstaired = Column('firstaired', DateTime) firstaired = text_date_synonym('_firstaired') _actors = Column('actors', Unicode) actors = pipe_list_synonym('_actors') episodes = relation('TVDBEpisode', backref='series', cascade='all, delete, delete-orphan') def update(self, tvdb_id=None): tvdb_id = tvdb_id or self.id url = get_mirror() + api_key + '/series/%s/%s.xml' % (tvdb_id, language) try: data = requests.get(url).content except RequestException as e: raise LookupError('Request failed %s' % url) result = ElementTree.fromstring(data).find('Series') if result is not None: self.update_from_xml(result) else: raise LookupError('Could not retrieve information from thetvdb') def get_poster(self, only_cached=False): """Downloads this poster to a local cache and returns the path""" from flexget.manager import manager base_dir = os.path.join(manager.config_base, 'userstatic') if os.path.isfile(os.path.join(base_dir, self.poster_file or '')): return self.poster_file elif only_cached: return # If we don't already have a local copy, download one. url = get_mirror('banner') + self.poster log.debug('Downloading poster %s', url) dirname = os.path.join('tvdb', 'posters') # Create folders if the don't exist fullpath = os.path.join(base_dir, dirname) if not os.path.isdir(fullpath): os.makedirs(fullpath) filename = os.path.join(dirname, posixpath.basename(self.poster)) thefile = file(os.path.join(base_dir, filename), 'wb') thefile.write(requests.get(url).content) self.poster_file = filename # If we are detached from a session, update the db if not Session.object_session(self): with Session() as session: session.query(TVDBSeries).filter( TVDBSeries.id == self.id).update( values={'poster_file': filename}) return filename def __repr__(self): return '<TVDBSeries name=%s,tvdb_id=%s>' % (self.seriesname, self.id) def to_dict(self): return { 'TVDB_id': self.id, 'last_updated': datetime.fromtimestamp( self.lastupdated).strftime('%Y-%m-%d %H:%M:%S'), 'expired': self.expired, 'series_name': self.seriesname, 'language': self.language, 'rating': self.rating, 'status': self.status, 'runtime': self.runtime, 'airs_time': self.airs_time, 'airs_dayofweek': self.airs_dayofweek, 'content_rating': self.contentrating, 'network': self.network, 'overview': self.overview, 'imdb_id': self.imdb_id, 'zap2it_id': self.zap2it_id, 'banner': self.banner, 'fan_art': self.fanart, 'poster': self.poster, 'poster_file': self.poster_file, 'genres': self.genre, 'first_aired': self.firstaired, 'actors': self.actors }