예제 #1
0
    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(
            ignore_case=show.api.config['ignore_case'], **data)
        self.data['banner_url'] = self.mirror + u"/banners/" + self.BannerPath
예제 #2
0
    def test_clear(self):
        """It should be possible to clear a dict"""
        d = InsensitiveDictionary()

        d['foo'] = 'baar'
        self.assertEqual(len(d), 1)

        d.clear()
        self.assertEqual(len(d), 0)
예제 #3
0
    def __init__(self, data, api, language, config):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.actor_objects = list()
        self.banner_objects = list()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142
예제 #4
0
    def test_get_method(self):
        """
        The dict should support the get method
        """
        d = InsensitiveDictionary(ignore_case=True)

        d['HELLO'] = 'hello'

        self.assertEqual(d.get('HELLO'), d['HELLO'])
        self.assertEqual(d.get('HELLO'), d.get('hello'))
예제 #5
0
    def __init__(self, data, api, language, config, full_data=None):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

        self.data['actor_objects'] = list()
        self.data['banner_objects'] = list()

        if full_data is not None:
            self._populate_data(full_data)
예제 #6
0
    def test_create_insensitive_dict(self):
        """
        It should be possible to create a case insensitive dictionary
        """
        d = InsensitiveDictionary(ignore_case=True)

        d['HELLO'] = 'hello'

        self.assertEqual(d['HELLO'], d['hello'])
        self.assertEqual(d['HelLO'], d['HellO'])

        d2 = InsensitiveDictionary([('Test', 'test')], ignore_case=True)
        self.assertEqual(d2['TEST'], d2['test'])
예제 #7
0
    def test_values(self):
        """It should be possible to use the values() method on the dict"""

        d = InsensitiveDictionary()

        # Create the dict
        keys = ['foo', 'baaz', 'blaa', 2]
        values = ['baar', 'woo', 'blug', 'wow']

        for i in zip(keys, values):
            d[i[0]] = i[1]

        # Test dict
        for v in d.values():
            self.assertTrue(v in values)
예제 #8
0
    def test_equality(self):
        """
        The dictionary should support equality tests
        """
        d = InsensitiveDictionary(ignore_case=True)
        d['HELLO'] = 'hello'

        d2 = InsensitiveDictionary(ignore_case=True)
        d2['HELLO'] = 'hello'

        d3 = InsensitiveDictionary(ignore_case=True)
        d3['Foo'] = 'baar'

        self.assertEqual(d == d2, True)
        self.assertEqual(d != d2, False)
        self.assertEqual(d != d3, True)
예제 #9
0
    def test_items(self):
        """It should be possible to use the items() method on the dict"""

        d = InsensitiveDictionary()

        # Create the dict
        keys = ['foo', 'baaz', 'blaa', 2]
        values = ['baar', 'woo', 'blug', 'wow']
        items = zip(keys, values)

        for i in items:
            d[i[0]] = i[1]

        # Test dict
        for i in d.items():
            self.assertTrue(i[0] in keys)
            self.assertTrue(i[1] in values)
예제 #10
0
class Actor(object):
    """
    Representing an Actor as provided by `thetvdb.com <http://thetvdb.com>`_.
    It Will contain all attributes as delivered from
    `thetvdb.com <http://thetvdb.com>`_, the attributes are described in
    more detail `here <http://www.thetvdb.com/wiki/index.php/API:actors.xml>`_.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("dexter", "en")
        >>> show = result[0]

        >>> show.load_actors()

        >>> actor = show.actor_objects[0]
        >>> print(actor.image_url)
        http://thetvdb.com/banners/actors/70947.jpg

        >>> for actor in show.actor_objects: #doctest: +ELLIPSIS
        ...     print(u"{0} - {1}".format(actor.Name, actor.Role))
        ...
        Michael C. Hall - Dexter Morgan
        Jennifer Carpenter - Debra Morgan
        James Remar - Harry Morgan
        ...
        Jimmy Smits - Miguel Prado
        Jaime Murray - Lila Tournay
        John Lithgow - Arthur Mitchell
        ...
    """
    data = {}

    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(
            ignore_case=show.api.config['ignore_case'], **data)
        self.data['image_url'] = self.mirror + u"/banners/" + self.Image

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise TVDBAttributeError(
                u"Actor has no {0} attribute".format(item))

    def __dir__(self):
        return list(self.data.keys())

    def __str__(self):
        return u'<{0} - {1}>'.format(self.__class__.__name__, self.Name)

    def __repr__(self):
        return self.__str__()
예제 #11
0
    def __init__(self, data, api, language, config):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.actor_objects = list()
        self.banner_objects = list()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142
예제 #12
0
class Actor(object):
    """
    Representing an Actor as provided by `thetvdb.com <http://thetvdb.com>`_.
    It Will contain all attributes as delivered from
    `thetvdb.com <http://thetvdb.com>`_, the attributes are described in
    more detail `here <http://www.thetvdb.com/wiki/index.php/API:actors.xml>`_.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("dexter", "en")
        >>> show = result[0]

        >>> show.load_actors()

        >>> actor = show.actor_objects[0]
        >>> print(actor.image_url)
        http://thetvdb.com/banners/actors/70947.jpg

        >>> for actor in show.actor_objects: #doctest: +ELLIPSIS
        ...     print(u"{0} - {1}".format(actor.Name, actor.Role))
        ...
        Michael C. Hall - Dexter Morgan
        Jennifer Carpenter - Debra Morgan
        James Remar - Harry Morgan
        ...
        Jimmy Smits - Miguel Prado
        Jaime Murray - Lila Tournay
        John Lithgow - Arthur Mitchell
        ...
    """
    data = {}

    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(ignore_case=show.api.config['ignore_case'], **data)
        self.data['image_url'] = self.mirror + u"/banners/" + self.Image

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise TVDBAttributeError(u"Actor has no {0} attribute".format(item))

    def __dir__(self):
        return list(self.data.keys())

    def __str__(self):
        return u'<{0} - {1}>'.format(self.__class__.__name__, self.Name)

    def __repr__(self):
        return self.__str__()
예제 #13
0
    def test_contains(self):
        """
        The dictionary should support the "in" syntax
        """
        d = InsensitiveDictionary(ignore_case=True)
        d['HELLO'] = 'hello'

        self.assertEqual('HELLO' in d, True)
        self.assertEqual('hello' in d, True)
        self.assertEqual('HeLlO' in d, True)
        self.assertEqual('foo' in d, False)
예제 #14
0
    def test_create_sensitive_dictionary(self):
        """
        It should be possible to create a case sensitive dictionary
        """

        d = InsensitiveDictionary(ignore_case=False)

        d['HELLO'] = 'hello'

        self.assertEqual(d['HELLO'], 'hello')
        self.assertEqual(d['HELLO'], d['HELLO'])
        self.assertRaises(KeyError, d.__getitem__, 'hello')
예제 #15
0
파일: api.py 프로젝트: fuzzycode/pytvdbapi
    def __init__(self, data, api, language, config, full_data=None):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

        self.data['actor_objects'] = list()
        self.data['banner_objects'] = list()

        if full_data is not None:
            self._populate_data(full_data)
예제 #16
0
    def _populate_data(self, data=None):
        """
        Populates the Show object with data. This will hit the network to
        download the XML data from `thetvdb.com <http://thetvdb.com>`_.
        :class:`Season` and `:class:Episode` objects will be created and
        added as needed.

        .. Note: This function is not intended to be used by clients of the
        API and should only be used internally by the Show class to manage its
        structure.
        """
        logger.debug(u"Populating season data from URL.")

        if data is None:
            context = {
                'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                'api_key': self.config['api_key'],
                'seriesid': self.id,
                'language': self.lang
            }
            url = series.format(**context)
            data = self.api.loader.load(url)
            data = generate_tree(data)

        episodes = [d for d in parse_xml(data, "Episode")]

        show_data = parse_xml(data, "Series")
        assert len(show_data) == 1, u"Should only have 1 Show section"

        self.data.update(
            InsensitiveDictionary(show_data[0], ignore_case=self.ignore_case))

        for episode_data in episodes:
            season_nr = int(episode_data['SeasonNumber'])
            if season_nr not in self.seasons:
                self.seasons[season_nr] = Season(season_nr, self)

            episode_instance = Episode(episode_data, self.seasons[season_nr],
                                       self.config)
            self.seasons[season_nr].append(episode_instance)

        # If requested, load the extra actors data
        if self.config.get('actors', False):
            self.load_actors()

        # if requested, load the extra banners data
        if self.config.get('banners', False):
            self.load_banners()
예제 #17
0
파일: api.py 프로젝트: fuzzycode/pytvdbapi
class Show(Sequence):
    # pylint: disable=R0902
    """
    :raise: :exc:`pytvdbapi.error.TVDBAttributeError`, :exc:`pytvdbapi.error.TVDBIndexError`

    Holds attributes about a single show and contains all seasons associated
    with a show. The attributes are named exactly as returned from
    thetvdb.com_. This object should be considered a read only container of
    data provided from the server. Some type conversion of of the attributes
    will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    The Show uses lazy evaluation and will only load the full data set from
    the server when this data is needed. This is to speed up the searches and
    to reduce the workload of the servers. This way,
    data will only be loaded when actually needed.

    The Show supports iteration to iterate over the Seasons contained in the
    Show. You can also index individual seasons with the [ ] syntax.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("dexter", "en")
        >>> show = result[0]

        >>> dir(show)  # List the set of basic attributes # doctest: +NORMALIZE_WHITESPACE
        ['AliasNames', 'FirstAired', 'IMDB_ID', 'Network',
         'Overview', 'SeriesName', 'actor_objects', 'api',
         'banner', 'banner_objects', 'id', 'lang', 'language',
         'seriesid', 'zap2it_id']

        >>> show.update()  # Load the full data set from the server
        >>> dir(show)  # List the full set of attributes # doctest: +NORMALIZE_WHITESPACE
        ['Actors', 'Airs_DayOfWeek', 'Airs_Time', 'AliasNames',
         'ContentRating', 'FirstAired', 'Genre', 'IMDB_ID', 'Language',
         'Network', 'NetworkID', 'Overview', 'Rating', 'RatingCount', 'Runtime',
         'SeriesID', 'SeriesName', 'Status', 'actor_objects', 'added', 'addedBy',
         'api', 'banner', 'banner_objects', 'fanart', 'id', 'lang', 'language',
         'lastupdated', 'poster', 'seriesid', 'tms_wanted_old', 'zap2it_id']

    .. note:: When searching, thetvdb.com_ provides a basic set of attributes
        for the show. When the full data set is loaded thetvdb.com_ provides a
        complete set of attributes for the show. The full data set is loaded
        when accessing the season data of the show. If you need access to the
        full set of attributes you can force the loading of the full data set
        by calling the :func:`update()` function.

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, api, language, config, full_data=None):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

        self.data['actor_objects'] = list()
        self.data['banner_objects'] = list()

        if full_data is not None:
            self._populate_data(full_data)

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(u"Show has no attribute named {0}".format(item))

    def __dir__(self):
        attributes = [d for d in list(self.__dict__.keys())
                      if d not in ('data', 'config', 'ignore_case', 'seasons')]
        return list(self.data.keys()) + attributes

    def __iter__(self):
        if not self.seasons:
            self._populate_data()

        return iter(sorted(list(self.seasons.values()), key=lambda season: season.season_number))

    def __len__(self):
        if not len(self.seasons):
            self._populate_data()

        return len(self.seasons)

    def __reversed__(self):
        for i in sorted(self.seasons.keys(), reverse=True):
            yield self[i]

    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")

    def __str__(self):
        return u'<{0} - {1}>'.format(self.__class__.__name__, self.SeriesName)

    def __repr__(self):
        return self.__str__()

    def update(self):
        """
        Updates the data structure with data from the server.
        """
        self._populate_data()

    def _populate_data(self, data=None):
        """
        Populates the Show object with data. This will hit the network to
        download the XML data from `thetvdb.com <http://thetvdb.com>`_.
        :class:`Season` and `:class:Episode` objects will be created and
        added as needed.

        .. Note: This function is not intended to be used by clients of the
        API and should only be used internally by the Show class to manage its
        structure.
        """
        logger.debug(u"Populating season data from URL.")

        if data is None:
            context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                       'api_key': self.config['api_key'],
                       'seriesid': self.id,
                       'language': self.lang}
            url = series.format(**context)
            data = self.api.loader.load(url)
            data = generate_tree(data)

        episodes = [d for d in parse_xml(data, "Episode")]

        show_data = parse_xml(data, "Series")
        assert len(show_data) == 1, u"Should only have 1 Show section"

        self.data.update(InsensitiveDictionary(show_data[0], ignore_case=self.ignore_case))

        for episode_data in episodes:
            season_nr = int(episode_data['SeasonNumber'])
            if season_nr not in self.seasons:
                self.seasons[season_nr] = Season(season_nr, self)

            episode_instance = Episode(episode_data, self.seasons[season_nr], self.config)
            self.seasons[season_nr].append(episode_instance)

        # If requested, load the extra actors data
        if self.config.get('actors', False):
            self.load_actors()

        # if requested, load the extra banners data
        if self.config.get('banners', False):
            self.load_banners()

    def load_actors(self):
        """
        .. versionadded:: 0.4

        Loads the extended actor information into a list of :class:`pytvdbapi.actor.Actor` objects.
        They are available through the *actor_objects* attribute of the show.

        If you have used the `actors=True` keyword when creating the :class:`TVDB` instance
        the actors will be loaded automatically and there is no need to use this
        function.

        .. seealso::
          :class:`TVDB` for information on how to use the *actors* keyword
          argument.
        """
        context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                   'api_key': self.config['api_key'],
                   'seriesid': self.id}
        url = actors.format(**context)

        logger.debug(u'Loading Actors data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))

        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        # generate all the Actor objects
        # pylint: disable=W0201
        self.actor_objects = [Actor(mirror, d, self)
                              for d in parse_xml(data, 'Actor')]

    def load_banners(self):
        """
        .. versionadded:: 0.4

        Loads the extended banner information into a list of :class:`pytvdbapi.banner.Banner` objects.
        They are available through the *banner_objects* attribute of the show.

        If you have used the `banners=True` keyword when creating the :class:`TVDB` instance the
        banners will be loaded automatically and there is no need to use this
        function.

        .. seealso::
          :class:`TVDB` for information on how to use the *banners* keyword
          argument.
        """
        context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                   'api_key': self.config['api_key'],
                   'seriesid': self.id}

        url = banners.format(**context)
        logger.debug(u'Loading Banner data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))
        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        # pylint: disable=W0201
        self.banner_objects = [Banner(mirror, b, self) for b in parse_xml(data, "Banner")]

    def find(self, key):
        """
        .. versionadded:: 0.5

        :param key: A callable taking an :class:`Episode` instance as argument and returns a boolean
        :returns: An :class:`Episode` instance or None

        Finds the first :class:`Episode` for witch :code:`key` returns :code:`True`.

        .. note::
            The order in which the :class:`Episode` instances are searched is not guaranteed and the first
            match found is not necessarily the first one in a chronological sense.

        .. seealso:: :func:`Season.find` for information on finding an episode in a specific season
        """
        for season in self:
            _episode = season.find(key=key)
            if _episode is not None:
                return _episode
        return None

    def filter(self, key):
        """
        .. versionadded:: 0.5

        :param key: A callable taking an :class:`Episode` instance as argument and returns a boolean
        :returns: A list of 0 or more :class:`Episode` instances

        Finds all :class:`Episode` instances for witch :code:`key` returns :code:`True`.

        .. seealso:: :func:`Season.filter` for information on filtering episodes in a specific season
        """
        result = list()
        for season in self:
            result.extend(season.filter(key=key))
        return result
예제 #18
0
class Show(Mapping):
    # pylint: disable=R0924, R0902
    """
    :raise: :class:`pytvdbapi.error.TVDBAttributeError`, :class:`pytvdbapi.error.TVDBIndexError`

    Holds attributes about a single show and contains all seasons associated
    with a show. The attributes are named exactly as returned from
    thetvdb.com_. This object should be considered a read only container of
    data provided from the server. Some type conversion of of the attributes
    will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    The Show uses lazy evaluation and will only load the full data set from
    the server when this data is needed. This is to speed up the searches and
    to reduce the workload of the servers. This way,
    data will only be loaded when actually needed.

    The Show supports iteration to iterate over the Seasons contained in the
    Show. You can also index individual seasons with the [ ] syntax.

    .. note:: When searching, thetvdb.com_ provides a basic set of attributes
        for the show. When the full data set is loaded thetvdb.com_ provides a
        complete set of attributes for the show. The full data set is loaded
        when accessing the season data of the show. If you need access to the
        full set of attributes you can force the loading of the full data set
        by calling the :func:`update()` function.


    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> search = db.search("Dexter", "en")
        >>> show = search[0]
        >>> dir(show) #doctest: +NORMALIZE_WHITESPACE
        ['AliasNames', 'FirstAired', 'IMDB_ID', 'Network', 'Overview',
          'SeriesName', 'actor_objects', 'api', 'banner', 'banner_objects',
           'id', 'lang', 'language', 'seasons', 'seriesid', 'zap2it_id']

        >>> show.update()

        >>> dir(show) #doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
        ['Actors', 'Airs_DayOfWeek', 'Airs_Time', 'AliasNames',
         'ContentRating', 'FirstAired', 'Genre', 'IMDB_ID',
        'Language', 'Network', 'NetworkID', 'Overview', 'Rating',
         'RatingCount', 'Runtime', 'SeriesID', 'SeriesName',
        'Status', 'actor_objects', 'added', 'addedBy', 'api',
         'banner', 'banner_objects', 'fanart', 'id', 'lang',
        'language', 'lastupdated', 'poster', 'seasons', 'seriesid',
         ...]

        >>> len(show)
        9

       >>> show[5]
       <Season 005>

        >>> for season in show:
        ...     print(season)
        ...
        <Season 000>
        <Season 001>
        <Season 002>
        <Season 003>
        <Season 004>
        <Season 005>
        <Season 006>
        <Season 007>
        <Season 008>


    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, api, language, config):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.actor_objects = list()
        self.banner_objects = list()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError("Show has no attribute named {0}".format(item))

    def __repr__(self):
        return "<Show - {0}>".format(self.SeriesName)

    def __dir__(self):
        attributes = [d for d in list(self.__dict__.keys()) if d not in ('data', 'config', 'ignore_case')]
        return list(self.data.keys()) + attributes

    def __iter__(self):
        if not self.seasons:
            self._populate_data()

        return iter(sorted(list(self.seasons.values()), key=lambda season: season.season_number))

    def __len__(self):
        if not len(self.seasons):
            self._populate_data()

        return len(self.seasons)

    def __getitem__(self, item):
        if not item in self.seasons:
            self._populate_data()

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

    def update(self):
        """
        Updates the data structure with data from the server.
        """
        self._populate_data()

    def _populate_data(self):
        """
        Populates the Show object with data. This will hit the network to
        downlaod the XML data from `thetvdb.com <http://thetvdb.com>`_.
        :class:`Season` and `:class:Episode` objects will be created and
        added as needed.

        .. Note: This function is not intended to be used by clients of the
        API and should only be used internally by the Show class to manage its
        structure.
        """
        logger.debug("Populating season data from URL.")

        context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                   'api_key': self.config['api_key'],
                   'seriesid': self.id,
                   'language': self.lang}

        url = __series__.format(**context)
        data = generate_tree(self.api.loader.load(url))
        episodes = [d for d in parse_xml(data, "Episode")]

        show_data = parse_xml(data, "Series")
        assert len(show_data) == 1, "Should only have 1 Show section"

        self.data = merge(self.data, InsensitiveDictionary(show_data[0], ignore_case=self.ignore_case))

        for episode_data in episodes:
            season_nr = int(episode_data['SeasonNumber'])
            if not season_nr in self.seasons:
                self.seasons[season_nr] = Season(season_nr, self)

            episode = Episode(episode_data, self.seasons[season_nr], self.config)
            self.seasons[season_nr].append(episode)

        #If requested, load the extra actors data
        if self.config.get('actors', False):
            self.load_actors()

        #if requested, load the extra banners data
        if self.config.get('banners', False):
            self.load_banners()

    def load_actors(self):
        """
        .. versionadded:: 0.4

        Loads the extended actor information into a list of :class:`pytvdbapi.actor.Actor` objects.
        They are available through the *actor_objects* attribute of the show.

        If you have used the :code:`actors=True` keyword when creating the :class:`TVDB` instance
        the actors will be loaded automatically and there is no need to use this function.

        .. note::
          The :class:`Show` instance always contain a list of actor names. If that is all you need, do not
          use this function to avoid unnecessary network traffic.

        .. seealso::
          :class:`TVDB` for information on how to use the *actors* keyword argument.

        """
        context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                   'api_key': self.config['api_key'],
                   'seriesid': self.id}
        url = __actors__.format(**context)

        logger.debug('Loading Actors data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))

        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        #generate all the Actor objects
        self.actor_objects = [Actor(mirror, d, self)
                              for d in parse_xml(data, 'Actor')]

    def load_banners(self):
        """
        .. versionadded:: 0.4

        Loads the extended banner information into a list of :class:`pytvdbapi.banner.Banner` objects.
        They are available through the *banner_objects* attribute of the show.

        If you have used the :code:`banners=True` keyword when creating the :class:`TVDB` instance the
        banners will be loaded automatically and there is no need to use this function.

        .. seealso::
          :class:`TVDB` for information on how to use the *banners* keyword argument.

        """
        context = {'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                   'api_key': self.config['api_key'],
                   'seriesid': self.id}

        url = __banners__.format(**context)
        logger.debug('Loading Banner data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))
        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        self.banner_objects = [Banner(mirror, b, self) for b in parse_xml(data, "Banner")]
예제 #19
0
class Show(Sequence):
    # pylint: disable=R0902
    """
    :raise: :exc:`pytvdbapi.error.TVDBAttributeError`, :exc:`pytvdbapi.error.TVDBIndexError`

    Holds attributes about a single show and contains all seasons associated
    with a show. The attributes are named exactly as returned from
    thetvdb.com_. This object should be considered a read only container of
    data provided from the server. Some type conversion of of the attributes
    will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    The Show uses lazy evaluation and will only load the full data set from
    the server when this data is needed. This is to speed up the searches and
    to reduce the workload of the servers. This way,
    data will only be loaded when actually needed.

    The Show supports iteration to iterate over the Seasons contained in the
    Show. You can also index individual seasons with the [ ] syntax.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("dexter", "en")
        >>> show = result[0]

        >>> dir(show)  # List the set of basic attributes # doctest: +NORMALIZE_WHITESPACE
        ['AliasNames', 'FirstAired', 'IMDB_ID', 'Network',
         'Overview', 'SeriesName', 'actor_objects', 'api',
         'banner', 'banner_objects', 'id', 'lang', 'language',
         'seriesid', 'zap2it_id']

        >>> show.update()  # Load the full data set from the server
        >>> dir(show)  # List the full set of attributes # doctest: +NORMALIZE_WHITESPACE
        ['Actors', 'Airs_DayOfWeek', 'Airs_Time', 'AliasNames',
         'ContentRating', 'FirstAired', 'Genre', 'IMDB_ID', 'Language',
         'Network', 'NetworkID', 'Overview', 'Rating', 'RatingCount', 'Runtime',
         'SeriesID', 'SeriesName', 'Status', 'actor_objects', 'added', 'addedBy',
         'api', 'banner', 'banner_objects', 'fanart', 'id', 'lang', 'language',
         'lastupdated', 'poster', 'seriesid', 'tms_wanted_old', 'zap2it_id']

    .. note:: When searching, thetvdb.com_ provides a basic set of attributes
        for the show. When the full data set is loaded thetvdb.com_ provides a
        complete set of attributes for the show. The full data set is loaded
        when accessing the season data of the show. If you need access to the
        full set of attributes you can force the loading of the full data set
        by calling the :func:`update()` function.

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, api, language, config, full_data=None):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

        self.data['actor_objects'] = list()
        self.data['banner_objects'] = list()

        if full_data is not None:
            self._populate_data(full_data)

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                u"Show has no attribute named {0}".format(item))

    def __dir__(self):
        attributes = [
            d for d in list(self.__dict__.keys())
            if d not in ('data', 'config', 'ignore_case', 'seasons')
        ]
        return list(self.data.keys()) + attributes

    def __iter__(self):
        if not self.seasons:
            self._populate_data()

        return iter(
            sorted(list(self.seasons.values()),
                   key=lambda season: season.season_number))

    def __len__(self):
        if not len(self.seasons):
            self._populate_data()

        return len(self.seasons)

    def __reversed__(self):
        for i in sorted(self.seasons.keys(), reverse=True):
            yield self[i]

    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")

    def __str__(self):
        return u'<{0} - {1}>'.format(self.__class__.__name__, self.SeriesName)

    def __repr__(self):
        return self.__str__()

    def update(self):
        """
        Updates the data structure with data from the server.
        """
        self._populate_data()

    def _populate_data(self, data=None):
        """
        Populates the Show object with data. This will hit the network to
        download the XML data from `thetvdb.com <http://thetvdb.com>`_.
        :class:`Season` and `:class:Episode` objects will be created and
        added as needed.

        .. Note: This function is not intended to be used by clients of the
        API and should only be used internally by the Show class to manage its
        structure.
        """
        logger.debug(u"Populating season data from URL.")

        if data is None:
            context = {
                'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
                'api_key': self.config['api_key'],
                'seriesid': self.id,
                'language': self.lang
            }
            url = series.format(**context)
            data = self.api.loader.load(url)
            data = generate_tree(data)

        episodes = [d for d in parse_xml(data, "Episode")]

        show_data = parse_xml(data, "Series")
        assert len(show_data) == 1, u"Should only have 1 Show section"

        self.data.update(
            InsensitiveDictionary(show_data[0], ignore_case=self.ignore_case))

        for episode_data in episodes:
            season_nr = int(episode_data['SeasonNumber'])
            if season_nr not in self.seasons:
                self.seasons[season_nr] = Season(season_nr, self)

            episode_instance = Episode(episode_data, self.seasons[season_nr],
                                       self.config)
            self.seasons[season_nr].append(episode_instance)

        # If requested, load the extra actors data
        if self.config.get('actors', False):
            self.load_actors()

        # if requested, load the extra banners data
        if self.config.get('banners', False):
            self.load_banners()

    def load_actors(self):
        """
        .. versionadded:: 0.4

        Loads the extended actor information into a list of :class:`pytvdbapi.actor.Actor` objects.
        They are available through the *actor_objects* attribute of the show.

        If you have used the `actors=True` keyword when creating the :class:`TVDB` instance
        the actors will be loaded automatically and there is no need to use this
        function.

        .. seealso::
          :class:`TVDB` for information on how to use the *actors* keyword
          argument.
        """
        context = {
            'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
            'api_key': self.config['api_key'],
            'seriesid': self.id
        }
        url = actors.format(**context)

        logger.debug(u'Loading Actors data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))

        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        # generate all the Actor objects
        # pylint: disable=W0201
        self.actor_objects = [
            Actor(mirror, d, self) for d in parse_xml(data, 'Actor')
        ]

    def load_banners(self):
        """
        .. versionadded:: 0.4

        Loads the extended banner information into a list of :class:`pytvdbapi.banner.Banner` objects.
        They are available through the *banner_objects* attribute of the show.

        If you have used the `banners=True` keyword when creating the :class:`TVDB` instance the
        banners will be loaded automatically and there is no need to use this
        function.

        .. seealso::
          :class:`TVDB` for information on how to use the *banners* keyword
          argument.
        """
        context = {
            'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
            'api_key': self.config['api_key'],
            'seriesid': self.id
        }

        url = banners.format(**context)
        logger.debug(u'Loading Banner data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))
        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        # pylint: disable=W0201
        self.banner_objects = [
            Banner(mirror, b, self) for b in parse_xml(data, "Banner")
        ]

    def find(self, key):
        """
        .. versionadded:: 0.5

        :param key: A callable taking an :class:`Episode` instance as argument and returns a boolean
        :returns: An :class:`Episode` instance or None

        Finds the first :class:`Episode` for witch :code:`key` returns :code:`True`.

        .. note::
            The order in which the :class:`Episode` instances are searched is not guaranteed and the first
            match found is not necessarily the first one in a chronological sense.

        .. seealso:: :func:`Season.find` for information on finding an episode in a specific season
        """
        for season in self:
            _episode = season.find(key=key)
            if _episode is not None:
                return _episode
        return None

    def filter(self, key):
        """
        .. versionadded:: 0.5

        :param key: A callable taking an :class:`Episode` instance as argument and returns a boolean
        :returns: A list of 0 or more :class:`Episode` instances

        Finds all :class:`Episode` instances for witch :code:`key` returns :code:`True`.

        .. seealso:: :func:`Season.filter` for information on filtering episodes in a specific season
        """
        result = list()
        for season in self:
            result.extend(season.filter(key=key))
        return result
예제 #20
0
class Episode(object):
    """
    :raise: :class:`pytvdbapi.error.TVDBAttributeError`

    Holds all information about an individual episode. This should be treated
    as a read-only object to obtain the attributes of the episode.

    All episode values returned from thetvdb.com_ are
    accessible as attributes of the episode object. The attributes will be
    named exactly as returned from thetvdb.com_ and are case sensitive.
    TVDBAttributeError will be raised if accessing an invalid attribute. Some
    type conversions of the attributes will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    It is possible to obtain the containing season through the Episode.season
    attribute.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> search = db.search("Dexter", "en")
        >>> show = search[0]
        >>> episode = show[1][5]

        >>> dir(episode) #doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
        ['Combined_episodenumber', 'Combined_season', 'DVD_chapter',
        'DVD_discid', 'DVD_episodenumber', 'DVD_season', 'Director',
        'EpImgFlag', 'EpisodeName', 'EpisodeNumber', 'FirstAired',
        'GuestStars', 'IMDB_ID', 'Language', 'Overview', 'ProductionCode',
        'Rating', 'RatingCount', 'SeasonNumber', 'Writer', 'absolute_number',
        'filename', 'id', 'lastupdated', 'season', 'seasonid', 'seriesid',
        ...]

        >>> episode.EpisodeName
        'Love American Style'

        >>> episode.GuestStars #doctest: +NORMALIZE_WHITESPACE
        ['Terry Woodberry', 'Carmen Olivares', 'Ashley Rose Orr',
        'Demetrius Grosse', 'Monique Curnen', 'June Angela',
        'Valerie Dillman', 'Brad Henke', 'Jose Zuniga', 'Allysa Tacher',
        'Lizette Carrion', 'Norma Fontana', 'Minerva Garcia',
        'Josh Daugherty', 'Geoffrey Rivas']

        >>> episode.FirstAired
        datetime.date(2006, 10, 29)

        >>> episode.season
        <Season 001>

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError("Episode has no attribute {0}".format(item))

    def __dir__(self):
        attributes = [d for d in list(self.__dict__.keys()) if d not in ('data', 'config')]
        return list(self.data.keys()) + attributes

    def __repr__(self):
        try:
            return "<Episode S{0:03d}E{1:03d} - {2}>".format(int(self.SeasonNumber),
                                                             int(self.EpisodeNumber),
                                                             self.EpisodeName)
        except error.TVDBAttributeError:
            return "<Episode>"
예제 #21
0
class Show(Mapping):
    # pylint: disable=R0924, R0902
    """
    :raise: :class:`pytvdbapi.error.TVDBAttributeError`, :class:`pytvdbapi.error.TVDBIndexError`

    Holds attributes about a single show and contains all seasons associated
    with a show. The attributes are named exactly as returned from
    thetvdb.com_. This object should be considered a read only container of
    data provided from the server. Some type conversion of of the attributes
    will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    The Show uses lazy evaluation and will only load the full data set from
    the server when this data is needed. This is to speed up the searches and
    to reduce the workload of the servers. This way,
    data will only be loaded when actually needed.

    The Show supports iteration to iterate over the Seasons contained in the
    Show. You can also index individual seasons with the [ ] syntax.

    .. note:: When searching, thetvdb.com_ provides a basic set of attributes
        for the show. When the full data set is loaded thetvdb.com_ provides a
        complete set of attributes for the show. The full data set is loaded
        when accessing the season data of the show. If you need access to the
        full set of attributes you can force the loading of the full data set
        by calling the :func:`update()` function.


    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> search = db.search("Dexter", "en")
        >>> show = search[0]
        >>> dir(show) #doctest: +NORMALIZE_WHITESPACE
        ['AliasNames', 'FirstAired', 'IMDB_ID', 'Network', 'Overview',
          'SeriesName', 'actor_objects', 'api', 'banner', 'banner_objects',
           'id', 'lang', 'language', 'seasons', 'seriesid', 'zap2it_id']

        >>> show.update()

        >>> dir(show) #doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
        ['Actors', 'Airs_DayOfWeek', 'Airs_Time', 'AliasNames',
         'ContentRating', 'FirstAired', 'Genre', 'IMDB_ID',
        'Language', 'Network', 'NetworkID', 'Overview', 'Rating',
         'RatingCount', 'Runtime', 'SeriesID', 'SeriesName',
        'Status', 'actor_objects', 'added', 'addedBy', 'api',
         'banner', 'banner_objects', 'fanart', 'id', 'lang',
        'language', 'lastupdated', 'poster', 'seasons', 'seriesid',
         ...]

        >>> len(show)
        9

       >>> show[5]
       <Season 005>

        >>> for season in show:
        ...     print(season)
        ...
        <Season 000>
        <Season 001>
        <Season 002>
        <Season 003>
        <Season 004>
        <Season 005>
        <Season 006>
        <Season 007>
        <Season 008>


    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, api, language, config):
        self.api, self.lang, self.config = api, language, config
        self.seasons = dict()

        self.actor_objects = list()
        self.banner_objects = list()

        self.ignore_case = self.config.get('ignore_case', False)
        self.data = InsensitiveDictionary(ignore_case=self.ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                "Show has no attribute named {0}".format(item))

    def __repr__(self):
        return "<Show - {0}>".format(self.SeriesName)

    def __dir__(self):
        attributes = [
            d for d in list(self.__dict__.keys())
            if d not in ('data', 'config', 'ignore_case')
        ]
        return list(self.data.keys()) + attributes

    def __iter__(self):
        if not self.seasons:
            self._populate_data()

        return iter(
            sorted(list(self.seasons.values()),
                   key=lambda season: season.season_number))

    def __len__(self):
        if not len(self.seasons):
            self._populate_data()

        return len(self.seasons)

    def __getitem__(self, item):
        if not item in self.seasons:
            self._populate_data()

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

    def update(self):
        """
        Updates the data structure with data from the server.
        """
        self._populate_data()

    def _populate_data(self):
        """
        Populates the Show object with data. This will hit the network to
        downlaod the XML data from `thetvdb.com <http://thetvdb.com>`_.
        :class:`Season` and `:class:Episode` objects will be created and
        added as needed.

        .. Note: This function is not intended to be used by clients of the
        API and should only be used internally by the Show class to manage its
        structure.
        """
        logger.debug("Populating season data from URL.")

        context = {
            'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
            'api_key': self.config['api_key'],
            'seriesid': self.id,
            'language': self.lang
        }

        url = __series__.format(**context)
        data = generate_tree(self.api.loader.load(url))
        episodes = [d for d in parse_xml(data, "Episode")]

        show_data = parse_xml(data, "Series")
        assert len(show_data) == 1, "Should only have 1 Show section"

        self.data = merge(
            self.data,
            InsensitiveDictionary(show_data[0], ignore_case=self.ignore_case))

        for episode_data in episodes:
            season_nr = int(episode_data['SeasonNumber'])
            if not season_nr in self.seasons:
                self.seasons[season_nr] = Season(season_nr, self)

            episode = Episode(episode_data, self.seasons[season_nr],
                              self.config)
            self.seasons[season_nr].append(episode)

        #If requested, load the extra actors data
        if self.config.get('actors', False):
            self.load_actors()

        #if requested, load the extra banners data
        if self.config.get('banners', False):
            self.load_banners()

    def load_actors(self):
        """
        .. versionadded:: 0.4

        Loads the extended actor information into a list of :class:`pytvdbapi.actor.Actor` objects.
        They are available through the *actor_objects* attribute of the show.

        If you have used the :code:`actors=True` keyword when creating the :class:`TVDB` instance
        the actors will be loaded automatically and there is no need to use this function.

        .. note::
          The :class:`Show` instance always contain a list of actor names. If that is all you need, do not
          use this function to avoid unnecessary network traffic.

        .. seealso::
          :class:`TVDB` for information on how to use the *actors* keyword argument.

        """
        context = {
            'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
            'api_key': self.config['api_key'],
            'seriesid': self.id
        }
        url = __actors__.format(**context)

        logger.debug('Loading Actors data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))

        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        #generate all the Actor objects
        self.actor_objects = [
            Actor(mirror, d, self) for d in parse_xml(data, 'Actor')
        ]

    def load_banners(self):
        """
        .. versionadded:: 0.4

        Loads the extended banner information into a list of :class:`pytvdbapi.banner.Banner` objects.
        They are available through the *banner_objects* attribute of the show.

        If you have used the :code:`banners=True` keyword when creating the :class:`TVDB` instance the
        banners will be loaded automatically and there is no need to use this function.

        .. seealso::
          :class:`TVDB` for information on how to use the *banners* keyword argument.

        """
        context = {
            'mirror': self.api.mirrors.get_mirror(TypeMask.XML).url,
            'api_key': self.config['api_key'],
            'seriesid': self.id
        }

        url = __banners__.format(**context)
        logger.debug('Loading Banner data from {0}'.format(url))

        data = generate_tree(self.api.loader.load(url))
        mirror = self.api.mirrors.get_mirror(TypeMask.BANNER).url

        self.banner_objects = [
            Banner(mirror, b, self) for b in parse_xml(data, "Banner")
        ]
예제 #22
0
    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142
예제 #23
0
class Episode(object):
    """
    :raise: :class:`pytvdbapi.error.TVDBAttributeError`

    Holds all information about an individual episode. This should be treated
    as a read-only object to obtain the attributes of the episode.

    All episode values returned from thetvdb.com_ are
    accessible as attributes of the episode object. The attributes will be
    named exactly as returned from thetvdb.com_ and are case sensitive.
    TVDBAttributeError will be raised if accessing an invalid attribute. Some
    type conversions of the attributes will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    It is possible to obtain the containing season through the Episode.season
    attribute.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> search = db.search("Dexter", "en")
        >>> show = search[0]
        >>> episode = show[1][5]

        >>> dir(episode) #doctest: +NORMALIZE_WHITESPACE, +ELLIPSIS
        ['Combined_episodenumber', 'Combined_season', 'DVD_chapter',
        'DVD_discid', 'DVD_episodenumber', 'DVD_season', 'Director',
        'EpImgFlag', 'EpisodeName', 'EpisodeNumber', 'FirstAired',
        'GuestStars', 'IMDB_ID', 'Language', 'Overview', 'ProductionCode',
        'Rating', 'RatingCount', 'SeasonNumber', 'Writer', 'absolute_number',
        'filename', 'id', 'lastupdated', 'season', 'seasonid', 'seriesid',
        ...]

        >>> episode.EpisodeName
        'Love American Style'

        >>> episode.GuestStars #doctest: +NORMALIZE_WHITESPACE
        ['Terry Woodberry', 'Carmen Olivares', 'Ashley Rose Orr',
        'Demetrius Grosse', 'Monique Curnen', 'June Angela',
        'Valerie Dillman', 'Brad Henke', 'Jose Zuniga', 'Allysa Tacher',
        'Lizette Carrion', 'Norma Fontana', 'Minerva Garcia',
        'Josh Daugherty', 'Geoffrey Rivas']

        >>> episode.FirstAired
        datetime.date(2006, 10, 29)

        >>> episode.season
        <Season 001>

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                "Episode has no attribute {0}".format(item))

    def __dir__(self):
        attributes = [
            d for d in list(self.__dict__.keys())
            if d not in ('data', 'config')
        ]
        return list(self.data.keys()) + attributes

    def __repr__(self):
        try:
            return "<Episode S{0:03d}E{1:03d} - {2}>".format(
                int(self.SeasonNumber), int(self.EpisodeNumber),
                self.EpisodeName)
        except error.TVDBAttributeError:
            return "<Episode>"
예제 #24
0
파일: api.py 프로젝트: fuzzycode/pytvdbapi
class Episode(object):
    """
    :raise: :exc:`pytvdbapi.error.TVDBAttributeError`

    Holds all information about an individual episode. This should be treated
    as a read-only object to obtain the attributes of the episode.

    All episode values returned from thetvdb.com_ are
    accessible as attributes of the episode object.
    TVDBAttributeError will be raised if accessing an invalid attribute. Some
    type conversions of the attributes will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    It is possible to obtain the containing season through the *Episode.season*
    attribute.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("Dexter", "en")
        >>> show = result[0]
        >>> episode = show[1][2]  # Get episode S01E02

        >>> print(episode.season)
        <Season 001>

        >>> print(episode.EpisodeNumber)
        2

        >>> print(episode.EpisodeName)
        Crocodile

        >>> episode.FirstAired
        datetime.date(2006, 10, 8)

        >>> dir(episode) #doctest: +NORMALIZE_WHITESPACE
        ['Combined_episodenumber',
         'Combined_season', 'DVD_chapter', 'DVD_discid', 'DVD_episodenumber',
         'DVD_season', 'Director', 'EpImgFlag', 'EpisodeName', 'EpisodeNumber',
         'FirstAired', 'GuestStars', 'IMDB_ID', 'Language', 'Overview',
         'ProductionCode', 'Rating', 'RatingCount', 'SeasonNumber', 'Writer',
         'absolute_number', 'filename', 'id', 'lastupdated', 'season',
         'seasonid', 'seriesid', 'thumb_added', 'thumb_height', 'thumb_width']

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(u"Episode has no attribute {0}".format(item))

    def __dir__(self):
        attributes = [d for d in list(self.__dict__.keys()) if d not in ('data', 'config')]
        return list(self.data.keys()) + attributes

    def __str__(self):
        return u'<{0} - S{1:03d}E{2:03d}>'.format(
            self.__class__.__name__, self.SeasonNumber, self.EpisodeNumber)

    def __repr__(self):
        return self.__str__()
예제 #25
0
class Episode(object):
    """
    :raise: :exc:`pytvdbapi.error.TVDBAttributeError`

    Holds all information about an individual episode. This should be treated
    as a read-only object to obtain the attributes of the episode.

    All episode values returned from thetvdb.com_ are
    accessible as attributes of the episode object.
    TVDBAttributeError will be raised if accessing an invalid attribute. Some
    type conversions of the attributes will take place as follows:

    * Strings of the format yyyy-mm-dd will be converted into a\
        :class:`datetime.date` object.
    * Pipe separated strings will be converted into a list. E.g "foo | bar" =>\
        ["foo", "bar"]
    * Numbers with a decimal point will be converted to float
    * A number will be converted into an int


    It is possible to obtain the containing season through the *Episode.season*
    attribute.

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB("B43FF87DE395DF56")
        >>> result = db.search("Dexter", "en")
        >>> show = result[0]
        >>> episode = show[1][2]  # Get episode S01E02

        >>> print(episode.season)
        <Season 001>

        >>> print(episode.EpisodeNumber)
        2

        >>> print(episode.EpisodeName)
        Crocodile

        >>> episode.FirstAired
        datetime.date(2006, 10, 8)

        >>> dir(episode) #doctest: +NORMALIZE_WHITESPACE
        ['Combined_episodenumber',
         'Combined_season', 'DVD_chapter', 'DVD_discid', 'DVD_episodenumber',
         'DVD_season', 'Director', 'EpImgFlag', 'EpisodeName', 'EpisodeNumber',
         'FirstAired', 'GuestStars', 'IMDB_ID', 'Language', 'Overview',
         'ProductionCode', 'Rating', 'RatingCount', 'SeasonNumber', 'Writer',
         'absolute_number', 'filename', 'id', 'lastupdated', 'season',
         'seasonid', 'seriesid', 'thumb_added', 'thumb_height', 'thumb_width']

    .. _thetvdb.com: http://thetvdb.com
    """

    data = {}

    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                u"Episode has no attribute {0}".format(item))

    def __dir__(self):
        attributes = [
            d for d in list(self.__dict__.keys())
            if d not in ('data', 'config')
        ]
        return list(self.data.keys()) + attributes

    def __str__(self):
        return u'<{0} - S{1:03d}E{2:03d}>'.format(self.__class__.__name__,
                                                  self.SeasonNumber,
                                                  self.EpisodeNumber)

    def __repr__(self):
        return self.__str__()
예제 #26
0
파일: api.py 프로젝트: fuzzycode/pytvdbapi
    def __init__(self, data, season, config):
        self.season, self.config = season, config
        ignore_case = self.config.get('ignore_case', False)

        self.data = InsensitiveDictionary(ignore_case=ignore_case, **data)  # pylint: disable=W0142
예제 #27
0
class Banner(object):
    """
    Representing a Banner as provided by `thetvdb.com <http://thetvdb.com>`_. More information about the
    data provided for a Banner can be found `here <http://thetvdb.com/wiki/index.php/API:banners.xml>`__.

    **Attributes:**

    The number and types of attributes that the Banner has is dependent on
    the type of Banner it is. Below is a description of the different
    attributes.

    Note: Wherever 'text' is given as the attribute type, this means that on Python 2.X it will be of type
    :class:`unicode` and on Python 3.X :class:`str`.

    *Common*:

    These attributes are present for all Banner objects.

    * BannerPath (text). The last part of the URL pointing to the image.\
        This is appended to the correct mirror address to form the full URL.
    * BannerType (text). This could be any of **fanart**, **season** or \
        **poster**. This value controls what other attributes are available \
        as described below.
    * BannerType2 (text). What this attribute contains will depend on the \
        type of Banner and will be described in each sub section below.
    * Language (text).
    * Rating (float).
    * RatingCount (int).
    * id (int).
    * banner_url (text). This is generated by **pytvdbapi** and is the full \
        URL for the banner.

    *fanart:*

    Additional to the common attributes, the following attributes are included
    on objects of type **fanart**.

    * BannerType2 (text). Contains the dimension of the image as text.
    * Colors (list).
    * SeriesName (bool).
    * ThumbnailPath (text).
    * VignettePath (text).

    *poster:*

    **poster** type does not contain any additional attributes.

    * BannerType2 (text). Contains the dimension of the image as a string.

    *season:*

    Additional to the common attributes, the following attributes are included
    on objects of type **season**.

    * BannerType2 (text). Contains the word 'season'
    * Season (int).

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB('B43FF87DE395DF56', banners=True)
        >>> show = db.get( 79349, "en" )  # Dexter
        >>> show.update()

        >>> assert len(show.banner_objects) > 0
        >>> banner = show.banner_objects[0]

        >>> print(banner.banner_url) #doctest: +ELLIPSIS
        http://thetvdb.com/banners/fanart/original/79349-...jpg

        >>> print(banner.Language)
        en

        Showing the different banner types and their attributes.

        >>> fanart = [b for b in show.banner_objects if b.BannerType == "fanart"]
        >>> dir(fanart[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Colors', 'Language',
        'Rating', 'RatingCount', 'SeriesName', 'ThumbnailPath', 'VignettePath',
        'banner_url', 'id']

        >>> print(fanart[0].BannerType2)
        1920x1080


        >>> posters = [b for b in show.banner_objects if b.BannerType == "poster"]
        >>> dir(posters[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Language', 'Rating',
        'RatingCount', 'banner_url', 'id']

        >>> print(posters[0].BannerType2)
        680x1000


        >>> seasons = [b for b in show.banner_objects if b.BannerType == "season"]
        >>> dir(seasons[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Language', 'Rating',
        'RatingCount', 'Season', 'banner_url', 'id']

        >>> print(seasons[0].BannerType2)
        season
    """

    data = {}

    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(
            ignore_case=show.api.config['ignore_case'], **data)
        self.data['banner_url'] = self.mirror + u"/banners/" + self.BannerPath

    def __str__(self):
        return u'<Banner({1}) - {0}>'.format(self.id, self.BannerType)

    def __repr__(self):
        return self.__str__()

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                u"Banner has no {0} attribute".format(item))

    def __dir__(self):
        return list(self.data.keys())
예제 #28
0
파일: actor.py 프로젝트: adamcw/pytvdbapi
    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(ignore_case=show.api.config['ignore_case'], **data)
        self.data['image_url'] = self.mirror + u"/banners/" + self.Image
예제 #29
0
class Banner(object):
    """
    Representing a Banner as provided by `thetvdb.com <http://thetvdb.com>`_. More information about the
    data provided for a Banner can be found `here <http://thetvdb.com/wiki/index.php/API:banners.xml>`__.

    **Attributes:**

    The number and types of attributes that the Banner has is dependent on
    the type of Banner it is. Below is a description of the different
    attributes.

    Note: Wherever 'text' is given as the attribute type, this means that on Python 2.X it will be of type
    :class:`unicode` and on Python 3.X :class:`str`.

    *Common*:

    These attributes are present for all Banner objects.

    * BannerPath (text). The last part of the URL pointing to the image.\
        This is appended to the correct mirror address to form the full URL.
    * BannerType (text). This could be any of **fanart**, **season** or \
        **poster**. This value controls what other attributes are available \
        as described below.
    * BannerType2 (text). What this attribute contains will depend on the \
        type of Banner and will be described in each sub section below.
    * Language (text).
    * Rating (float).
    * RatingCount (int).
    * id (int).
    * banner_url (text). This is generated by **pytvdbapi** and is the full \
        URL for the banner.

    *fanart:*

    Additional to the common attributes, the following attributes are included
    on objects of type **fanart**.

    * BannerType2 (text). Contains the dimension of the image as text.
    * Colors (list).
    * SeriesName (bool).
    * ThumbnailPath (text).
    * VignettePath (text).

    *poster:*

    **poster** type does not contain any additional attributes.

    * BannerType2 (text). Contains the dimension of the image as a string.

    *season:*

    Additional to the common attributes, the following attributes are included
    on objects of type **season**.

    * BannerType2 (text). Contains the word 'season'
    * Season (int).

    Example::

        >>> from pytvdbapi import api
        >>> db = api.TVDB('B43FF87DE395DF56', banners=True)
        >>> show = db.get_series( 79349, "en" )  # Dexter
        >>> show.update()

        >>> assert len(show.banner_objects) > 0
        >>> banner = show.banner_objects[0]

        >>> print(banner.banner_url) #doctest: +ELLIPSIS
        http://thetvdb.com/banners/fanart/original/79349-...jpg

        >>> print(banner.Language)
        en

        Showing the different banner types and their attributes.

        >>> fanart = [b for b in show.banner_objects if b.BannerType == "fanart"]
        >>> dir(fanart[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Colors', 'Language',
        'Rating', 'RatingCount', 'SeriesName', 'ThumbnailPath', 'VignettePath',
        'banner_url', 'id']

        >>> print(fanart[0].BannerType2)
        1280x720


        >>> posters = [b for b in show.banner_objects if b.BannerType == "poster"]
        >>> dir(posters[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Language', 'Rating',
        'RatingCount', 'banner_url', 'id']

        >>> print(posters[0].BannerType2)
        680x1000


        >>> seasons = [b for b in show.banner_objects if b.BannerType == "season"]
        >>> dir(seasons[0])  # doctest: +NORMALIZE_WHITESPACE
        ['BannerPath', 'BannerType', 'BannerType2', 'Language', 'Rating',
        'RatingCount', 'Season', 'banner_url', 'id']

        >>> print(seasons[0].BannerType2)
        season
    """

    data = {}

    def __init__(self, mirror, data, show):
        self.mirror, self.show = mirror, show

        # pylint: disable=W0142
        self.data = InsensitiveDictionary(ignore_case=show.api.config['ignore_case'], **data)
        self.data['banner_url'] = self.mirror + u"/banners/" + self.BannerPath

    def __str__(self):
        return u'<Banner({1}) - {0}>'.format(self.id, self.BannerType)

    def __repr__(self):
        return self.__str__()

    def __getattr__(self, item):
        try:
            return self.data[item]
        except KeyError:
            raise error.TVDBAttributeError(
                u"Banner has no {0} attribute".format(item))

    def __dir__(self):
        return list(self.data.keys())