thetvdb.py 7.44 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# ##############################################################################
#  Author: echel0n <[email protected]>
#  URL: https://sickrage.ca/
#  Git: https://git.sickrage.ca/SiCKRAGE/sickrage.git
#  -
#  This file is part of SiCKRAGE.
#  -
#  SiCKRAGE is free software: you can redistribute it and/or modify
#  it under the terms of the GNU General Public License as published by
#  the Free Software Foundation, either version 3 of the License, or
#  (at your option) any later version.
#  -
#  SiCKRAGE is distributed in the hope that it will be useful,
#  but WITHOUT ANY WARRANTY; without even the implied warranty of
#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#  GNU General Public License for more details.
#  -
#  You should have received a copy of the GNU General Public License
#  along with SiCKRAGE.  If not, see <http://www.gnu.org/licenses/>.
# ##############################################################################


from operator import itemgetter
24
from urllib.parse import quote
25
26
27
28
29
30

import sickrage
from sickrage.core.enums import SeriesProviderID
from sickrage.series_providers import SeriesProvider


31
class SeriesProviderActors(list):
32
33
34
35
36
    """Holds all Actor instances for a show
    """
    pass


37
class SeriesProviderActor(dict):
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
    """Represents a single actor. Should contain..

    id,
    image,
    name,
    role,
    sortorder
    """

    def __repr__(self):
        return "<Actor \"{}\">".format(self.get("name"))


class TheTVDB(SeriesProvider):
    """Create easy-to-use interface to name of season/episode name
    """

    def __init__(self):
        super(TheTVDB, self).__init__(SeriesProviderID.THETVDB)
        self.trakt_id = 'tvdb'
        self.xem_origin = 'tvdb'
        self.icon = 'thetvdb16.png'
        self.show_url = 'http://thetvdb.com/?tab=series&id='
        self.dvd_order = False

63
    def search(self, query, language='eng'):
64
65
        """
        This searches TheTVDB.com for the series by name and returns the result list
66
67
        """

68
        sickrage.app.log.debug(f"Searching for show using query term: {query}")
69

70
        search_results = sickrage.app.api.series_provider.search(provider=self.slug, query=quote(query), language=language)
71
        if not search_results or 'error' in search_results:
72
            sickrage.app.log.debug(f'Series search using query term {query} returned zero results, cannot find series on {self.name}')
73

74
75
76
77
78
79
80
81
82
        return search_results

    def search_by_id(self, remote_id, language='eng'):
        """
        This searches TheTVDB.com for the seriesid, imdbid, or zap2itid  and returns the result list
        """

        sickrage.app.log.debug(f"Searching for show using remote id: {remote_id}")

83
84
85
86
        if not isinstance(remote_id, int):
            remote_id = quote(remote_id)

        search_result = sickrage.app.api.series_provider.search_by_id(provider=self.slug, remote_id=remote_id, language=language)
87
        if not search_result or 'error' in search_result:
88
89
            sickrage.app.log.debug(f'Series search using remote id {remote_id} returned zero results, cannot find series on {self.name}')

90
91
        return search_result

92
    def get_series_info(self, sid, language='eng', dvd_order=False, enable_cache=True):
93
94
        """
        Takes a series id, gets the episodes URL and parses the TVDB
95
96
        """

97
98
99
100
101
        # check if series is in cache
        if sid in self.cache and enable_cache:
            search_result = self.cache[sid]
            if search_result:
                return search_result
102
103

        # get series data
104
        sickrage.app.log.debug(f"[{sid}]: Getting series info from {self.name}")
105

106
        resp = sickrage.app.api.series_provider.get_series_info(provider=self.slug, series_id=sid, language=language)
107
        if not resp or 'error' in resp:
108
109
            sickrage.app.log.debug(f"[{sid}]: Unable to get series info from {self.name}")
            return None
110

111
112
113
114
115
116
117
        # add season data to cache
        for season in resp['seasons']:
            season_number = int(float(season.get('seasonNumber')))

            for k, v in season.items():
                self.cache.add_season_data(sid, season_number, k, v)

118
        # add series data to cache
119
        [self.cache.add_show_data(sid, k, v) for k, v in resp.items() if k != 'seasons']
120

121
122
        # get season and episode data
        sickrage.app.log.debug(f'[{sid}]: Getting episode data from {self.name}')
123

124
        season_type = 'dvd' if dvd_order else 'official'
125
        resp = sickrage.app.api.series_provider.get_episodes_info(provider=self.slug, series_id=sid, season_type=season_type, language=language)
126
        if not resp or 'error' in resp:
127
            sickrage.app.log.debug(f"[{sid}]: Unable to get episode data from {self.name}")
128
129
            return None

130
131
        # add episode data to cache
        episode_incomplete = False
132
        for episode in resp:
133
134
            season_number, episode_number = episode.get('seasonNumber'), episode.get('episodeNumber')
            if season_number is None or episode_number is None:
135
136
137
                episode_incomplete = True
                continue

138
139
            season_number = int(float(season_number))
            episode_number = int(float(episode_number))
140

141
142
            for k, v in episode.items():
                self.cache.add_episode_data(sid, season_number, episode_number, k, v)
143
144

        if episode_incomplete:
145
            sickrage.app.log.debug(f"{sid}: Series has incomplete season/episode numbers")
146
147

        # set last updated
148
        # self.cache.add_show_data(sid, 'last_updated', int(time.mktime(datetime.now().timetuple())))
149
150
151

        return self.cache[int(sid)]

152
153
154
155
156
157
158
159
160
161
162
163
164
    def image_types(self):
        return {
            'series': {
                'banner': 1,
                'poster': 2,
                'fanart': 3
            },
            'season': {
                'banner': 6,
                'poster': 7,
                'fanart': 8
            }
        }
165

166
167
    def images(self, sid, key_type='poster', season=None, language='eng'):
        sickrage.app.log.debug(f'Getting {key_type} images for {sid}')
168
169
170

        images = []

171
172
        series_info = self.get_series_info(sid=sid, language=language)
        if not series_info:
173
174
            return []

175
176
177
178
179
180
181
182
183
184
185
186
187
188
        season_map = {}
        for season_number in series_info:
            season_map[season_number] = series_info[season_number]['id']

        for item in sorted(series_info.artworks, key=itemgetter("score"), reverse=True):
            if season and season_map[season] == item['seasonId'] and item['type'] == self.image_types()['season'][key_type]:
                images.append(item)
            elif not season and item['type'] == self.image_types()['series'][key_type]:
                images.append(item)

        if not images and key_type == 'poster':
            if season:
                image_url = series_info[season].imageUrl
                if image_url != '':
189
                    images.append({'image': image_url})
190
191
192
            else:
                image_url = series_info.imageUrl
                if image_url != '':
193
                    images.append({'image': image_url})
194

195
        return images
196

197
198
    def updates(self, since):
        resp = sickrage.app.api.series_provider.updates(provider=self.slug, since=since)
199
        if resp and 'error' not in resp:
200
            return resp
201
202

    def languages(self):
203
        resp = sickrage.app.api.series_provider.languages(provider=self.slug)
204
205
206
207
        if not resp or 'error' in resp:
            return {}

        return sorted(resp, key=lambda i: i['name'])
208
209
210

    def __repr__(self):
        return repr(self.cache)