Ejemplo n.º 1
0
    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)
Ejemplo n.º 2
0
    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)
Ejemplo n.º 3
0
    def search(self, show, language, cache=True):
        """
        :param show: The show name to search for
        :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:`Search()` instance
        :raise: :exc:`pytvdbapi.error.TVDBValueError`

        Searches the server for a show with the provided show name in the
        provided language. The language should be one of the supported
        language abbreviations or it could be set to *all* to search all
        languages. It will raise :class:`pytvdbapi.error.TVDBValueError` if
        an invalid language is provided.

        Searches are always cached within a session to make subsequent
        searches with the same parameters fast. If *cache*
        is set to True searches will also be cached across sessions,
        this is recommended to increase speed and to reduce the workload of
        the servers.

        Example::

            >>> from pytvdbapi import api
            >>> db = api.TVDB("B43FF87DE395DF56")
            >>> result = db.search("House", "en")

            >>> print(result[0])
            <Show - House>

            >>> for show in result:
            ...     print(show) # doctest: +ELLIPSIS
            <Show - House>
            ...
            <Show - House Of Cards (2013)>
            ...
        """

        logger.debug(u"Searching for {0} using language {1}".format(
            show, language))

        if language != u'all' and language not in __LANGUAGES__:
            raise error.TVDBValueError(
                u"{0} is not a valid language".format(language))

        if (show, language) not in self.search_buffer or not cache:
            context = {'series': quote(make_bytes(show)), "language": language}
            data = generate_tree(
                self.loader.load(__search__.format(**context), cache))
            shows = [
                Show(d, self, language, self.config)
                for d in parse_xml(data, "Series")
            ]

            self.search_buffer[(show, language)] = shows

        return Search(self.search_buffer[(show, language)], show, language)
Ejemplo n.º 4
0
    def __getitem__(self, item):
        if not isinstance(item, int):
            raise error.TVDBValueError(u"Index should be an integer")

        try:
            return self._result[item]
        except (IndexError, TypeError):
            raise error.TVDBIndexError(
                u"Index out of range ({0})".format(item))
Ejemplo n.º 5
0
    def __getitem__(self, item):
        if isinstance(item, int):
            try:
                return self.episodes[item]
            except KeyError:
                raise error.TVDBIndexError(
                    u"Episode {0} not found".format(item))

        elif isinstance(item, slice):
            indices = sorted(self.episodes.keys())[item]  # Slice the keys
            return [self[i] for i in indices]
        else:
            raise error.TVDBValueError(u"Index should be an integer")
Ejemplo n.º 6
0
    def __getitem__(self, item):
        if len(self.seasons) == 0:
            self._populate_data()

        if isinstance(item, int):
            try:
                return self.seasons[item]
            except KeyError:
                raise error.TVDBIndexError(
                    u"Season {0} not found".format(item))

        elif isinstance(item, slice):
            indices = sorted(self.seasons.keys())[item]  # Slice the keys
            return [self[i] for i in indices]
        else:
            raise error.TVDBValueError(u"Index should be an integer or slice")
Ejemplo n.º 7
0
    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: :class:`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.

        .. Note:: When the :class:`Episode()` is loaded using :func:`get_episode()`
            the episode attribute will be None.

        Example::

            >>> from pytvdbapi import api
            >>> db = api.TVDB("B43FF87DE395DF56")
            >>> episode = db.get_episode(308834, "en")
            >>> episode.id
            308834

            >>> episode.EpisodeName
            'Crocodile'

        """

        logger.debug("Getting episode with id {0} with language {1}".format(
            episode_id, language))

        if language != 'all' and language not in __LANGUAGES__:
            raise error.TVDBValueError(
                "{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)

        try:
            data = self.loader.load(url, cache)
        except error.TVDBNotFoundError:
            raise error.TVDBIdError(
                "No Episode with id {0} found".format(episode_id))
        except error.ConnectionError as _error:
            logger.debug("Unable to connect to URL: {0}. {1}".format(
                url, _error))
            raise

        if data.strip():
            data = generate_tree(data)
        else:
            raise error.TVDBIdError(
                "No Episode with id {0} found".format(episode_id))

        episodes = parse_xml(data, "Episode")
        assert len(episodes) <= 1, "Should not find more than one episodes"

        if len(episodes) >= 1:
            return Episode(episodes[0], None, self.config)
        else:
            raise error.TVDBIdError(
                "No Episode with id {0} found".format(episode_id))
Ejemplo n.º 8
0
    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: :class:`pytvdbapi.error.TVDBValueError`, :class:`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( 79349, "en" )
            >>> show.id
            79349

            >>> show.SeriesName
            'Dexter'

        """

        logger.debug("Getting series with id {0} with language {1}".format(
            series_id, language))

        if language != 'all' and language not in __LANGUAGES__:
            raise error.TVDBValueError(
                "{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)
        try:
            data = self.loader.load(url, cache)
        except error.TVDBNotFoundError:
            raise error.TVDBIdError(
                "Series id {0} not found".format(series_id))
        except error.ConnectionError as _error:
            logger.debug("Unable to connect to URL: {0}. {1}".format(
                url, _error))
            raise

        if data.strip():
            data = generate_tree(data)
        else:
            raise error.TVDBIdError(
                "No Show with id {0} found".format(series_id))

        series = parse_xml(data, "Series")
        assert len(series) <= 1, "Should not find more than one series"

        if len(series) >= 1:
            return Show(series[0], self, language, self.config)
        else:
            raise error.TVDBIdError(
                "No Show with id {0} found".format(series_id))
Ejemplo n.º 9
0
    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)
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)