def get_series(self, series_id, language, cache=True): """ .. versionadded:: 0.4 :param series_id: The Show Id to fetch :param language: The language abbreviation to search for. E.g. "en" :param cache: If False, the local cache will not be used and the resources will be reloaded from server. :return: A :class:`Show()` instance :raise: :exc:`pytvdbapi.error.TVDBValueError`, :exc:`pytvdbapi.error.TVDBIdError` Provided a valid Show ID, the data for the show is fetched and a corresponding :class:`Show()` object is returned. Example:: >>> from pytvdbapi import api >>> db = api.TVDB("B43FF87DE395DF56") >>> show = db.get_series( 79349, "en" ) # Load Dexter >>> print(show.SeriesName) Dexter """ logger.debug(u"Getting series with id {0} with language {1}".format( series_id, language)) if language != 'all' and language not in __LANGUAGES__: raise error.TVDBValueError( u"{0} is not a valid language".format(language)) context = { 'seriesid': series_id, "language": language, 'mirror': self.mirrors.get_mirror(TypeMask.XML).url, 'api_key': self.config['api_key'] } url = __series__.format(**context) logger.debug(u'Getting series from {0}'.format(url)) try: data = self.loader.load(url, cache) except error.TVDBNotFoundError: raise error.TVDBIdError( u"Series id {0} not found".format(series_id)) if data.strip(): data = generate_tree(data) else: raise error.BadData("Bad data received") series = parse_xml(data, "Series") if len(series) == 0: raise error.BadData("Bad data received") else: return Show(series[0], self, language, self.config)
def generate_tree(xml_data): """ Converts the xml data into an element tree """ try: return ET.fromstring(xml_data.encode('utf-8')) except ParseError: raise error.BadData("Bad XML data received")
def get_episode_by_air_date(self, series_id, language, air_date, cache=True): """ .. versionadded:: 0.5 :param series_id: The TVDB series id of the episode :param language: The language to search for. Should be a two letter abbreviation e.g. *en*. :param air_date: The air date to search for. Should be of type :class:`datetime.date` :type air_date: datetime.date :param cache: If False, the local cache will not be used and the resources will be reloaded from server. :return: If found, an :class:`Episode` instance :raise: :exc:`pytvdbapi.error.TVDBValueError` .. Note:: When the :class:`Episode()` is loaded using :func:`get_episode_by_air_date` the *season* attribute used to link the episode with a season will be None. """ if type(air_date) not in (datetime.date, ): raise error.TVDBValueError( "air_date should be of type datetime.date") elif language != 'all' and language not in __LANGUAGES__: raise error.TVDBValueError( u"{0} is not a valid language".format(language)) context = { 'seriesid': series_id, 'airdate': air_date, "language": language, 'mirror': self.mirrors.get_mirror(TypeMask.XML).url, 'api_key': self.config['api_key'] } url = airdate.format(**context) logger.debug(u'Getting episode from {0}'.format(url)) data = self.loader.load(url, cache) data = generate_tree(data) # The xml has an "Error" element in it if no episode was found if has_element(data, 'Error'): raise error.TVDBNotFoundError(u"".format()) episodes = parse_xml(data, "Episode") if len(episodes) == 0: raise error.BadData("Bad data received") else: return Episode(episodes[0], None, self.config)
def generate_tree(xml_data): """ :param xml_data: A file like object containing the xml data :return: A new ElementTree :raise: :class:`pytvdbapi.error.BadData` Converts the xml data into an element tree """ try: return eTree.parse(xml_data) except ParseError: raise error.BadData(u"Bad XML data received")
def generate_tree(xml_data): """ :param xml_data: The string xml data to generate the tree from :return: A new ElementTree :raise: :class:`pytvdbapi.error.BadData` Converts the xml data into an element tree """ try: return eTree.fromstring(make_bytes(xml_data, 'utf-8')) except ParseError: raise error.BadData(u"Bad XML data received")
def get_episode(self, episode_id, language, cache=True): """ .. versionadded:: 0.4 :param episode_id: The Episode Id to fetch :param language: The language abbreviation to search for. E.g. "en" :param cache: If False, the local cache will not be used and the resources will be reloaded from server. :return: An :class:`Episode()` instance :raise: :exc:`pytvdbapi.error.TVDBIdError` if no episode is found with the given Id Given a valid episode Id the corresponding episode data is fetched and the :class:`Episode()` instance is returned. Example:: >>> from pytvdbapi import api >>> db = api.TVDB("B43FF87DE395DF56") >>> episode = db.get_episode(308834, "en") # Load an episode of dexter >>> print(episode.id) 308834 >>> print(episode.EpisodeName) Crocodile .. Note:: When the :class:`Episode()` is loaded using :func:`get_episode()` the *season* attribute used to link the episode with a season will be None. """ logger.debug(u"Getting episode with id {0} with language {1}".format( episode_id, language)) if language != 'all' and language not in __LANGUAGES__: raise error.TVDBValueError( u"{0} is not a valid language".format(language)) context = { 'episodeid': episode_id, "language": language, 'mirror': self.mirrors.get_mirror(TypeMask.XML).url, 'api_key': self.config['api_key'] } url = __episode__.format(**context) logger.debug(u'Getting episode from {0}'.format(url)) try: data = self.loader.load(url, cache) except error.TVDBNotFoundError: raise error.TVDBIdError( u"No Episode with id {0} found".format(episode_id)) if data.strip(): data = generate_tree(data) else: raise error.BadData("Bad data received") episodes = parse_xml(data, "Episode") if len(episodes) == 0: raise error.BadData("Bad data received") else: return Episode(episodes[0], None, self.config)
def get_episode(self, language, method="id", cache=True, **kwargs): """ .. versionadded:: 0.4 .. versionchanged:: 0.5 Added the possibility to get an episode using *default*, *dvd*, and *absolute* sort order :param episode_id: *Deprecated in 0.5* Use the *episodeid* keyword argument with the *id* method instead :param language: The language abbreviation to search for. E.g. "en" :param cache: If False, the local cache will not be used and the resources will be reloaded from server. :param method: (default=id) Specify what method should be used to get the episode. Depending on what method is specified, different parameters must be passed as keyword arguments. Should be one of (id, default, dvd, absolute). :param kwargs: *episodeid*, *seriesid*, *seasonnumber*, *episodenumber* and *absolutenumber*. See the examples for information on how to use them. :return: An :class:`Episode()` instance :raise: :exc:`pytvdbapi.error.TVDBValueError`, :exc:`pytvdbapi.error.BadData` Retrieves a single episode. Depending on what method is specified different criteria can be used to retrieve the episode. Examples: Load an episode using the episode id >>> from pytvdbapi import api >>> db = api.TVDB("B43FF87DE395DF56") >>> ep = db.get_episode("en", episodeid=308834) # id is the default method >>> print(ep.EpisodeName) Crocodile Load an episode using dvd and default sort order >>> ep = db.get_episode("en", "dvd", seasonnumber=2, episodenumber=5, seriesid=79349) >>> print(ep.EpisodeName) The Dark Defender >>> ep = db.get_episode("en", "default", seasonnumber=2, episodenumber=6, seriesid=79349) >>> print(ep.EpisodeName) Dex, Lies, and Videotape Load an episode using the absolute number >>> ep = db.get_episode("en", "absolute", absolutenumber=19, seriesid=79349) >>> print(ep.EpisodeName) That Night, A Forest Grew Under some circumstances the backend server fails to return a proper **404** file not found error response when the requested episode can not be found, but instead returns a valid HTML file with the content *404 file not found*. For this reason it is required to check for both :exc:`pytvdbapi.error.TVDBValueError` and :exc:`pytvdbapi.error.BadData` to detect an issue downloading the episode. >>> from pytvdbapi.error import BadData >>> from pytvdbapi.error import TVDBNotFoundError >>> try: ... ep = db.get_episode("en", episodeid=308834) ... except TVDBNotFoundError: ... # this is the standard 404 error code returned from the server ... pass ... except BadData: ... # This is when the server returns a 200 code but with a HTML page saying 404 Nothing found ... pass .. Note:: When the :class:`Episode()` is loaded using :func:`get_episode()` the *season* attribute used to link the episode with a season will be None. """ methods = { "default": default_order, "dvd": dvd_order, "absolute": absolute_order, "id": episode } if language != 'all' and language not in __LANGUAGES__: raise error.TVDBValueError( u"{0} is not a valid language".format(language)) context = { "language": language, 'mirror': self.mirrors.get_mirror(TypeMask.XML).url, 'api_key': self.config['api_key'] } kwargs.update(context) try: url = methods[method] except KeyError: raise error.TVDBValueError( u"{0} is not a valid get method".format(method)) try: url = url.format(**kwargs) except KeyError: raise error.TVDBValueError( "Missing arguments for method {0}".format(method)) logger.debug(u'Getting episode from {0}'.format(url)) data = self.loader.load(url, cache) data = generate_tree(data) episodes = parse_xml(data, "Episode") if len(episodes) == 0: raise error.BadData("Bad data received") else: return Episode(episodes[0], None, self.config)
def get_series(self, series_id, language, id_type='tvdb', cache=True): """ .. versionadded:: 0.4 .. versionchanged:: 0.5 Added *id_type* parameter :param series_id: The Show Id to fetch :param language: The language abbreviation to search for. E.g. "en" :param id_type: Information about what kind of id is provided. Should be one of *('tvdb', 'imdb', 'zap2it')* :param cache: If False, the local cache will not be used and the resources will be reloaded from server. :return: A :class:`Show()` instance :raise: :exc:`pytvdbapi.error.TVDBValueError`, :exc:`pytvdbapi.error.TVDBIdError` Provided a valid Show ID, the data for the show is fetched and a corresponding :class:`Show()` object is returned. Example:: >>> from pytvdbapi import api >>> db = api.TVDB("B43FF87DE395DF56") >>> show = db.get_series( 79349, "en" ) # Load Dexter >>> print(show.SeriesName) Dexter """ if id_type not in ('tvdb', 'imdb', 'zap2it'): raise error.TVDBValueError("Invalid id type") elif language != 'all' and language not in __LANGUAGES__: raise error.TVDBValueError( u"{0} is not a valid language".format(language)) # Map id type to url template __url__ = {'tvdb': series, 'imdb': imdbid, 'zap2it': zap2itid} try: series_id = text_type(series_id) except ValueError: raise error.TVDBValueError( "Invalid id type, expected {0} or {1}, got {2}".format( text_type, int_types, type(series_id))) if id_type == 'imdb': series_id = series_id[2:] if series_id.startswith( 'tt') else series_id elif id_type == 'zap2it': series_id = series_id if series_id.startswith( 'EP') else u'EP' + series_id.rjust(8, '0') logger.debug( u"Getting series with id {0}({2}) with language {1}".format( series_id, language, id_type)) context = { 'seriesid': series_id, "language": language, 'mirror': self.mirrors.get_mirror(TypeMask.XML).url, 'api_key': self.config['api_key'], 'imdbid': series_id, 'zap2itid': series_id } url = __url__[id_type].format(**context) logger.debug(u'Getting series from {0}'.format(url)) try: data = self.loader.load(url, cache) except error.TVDBNotFoundError: raise error.TVDBIdError( u"Series id {0} not found".format(series_id)) data = generate_tree(data) series_data = parse_xml(data, "Series") if len(series) == 0: raise error.BadData("Bad data received") else: return Show(series_data[0], self, language, self.config, data)