Passed
Push — beta ( 91a9ed...2462f8 )
by Dean
02:58
created

Mapper.request_movie()   A

Complexity

Conditions 2

Size

Total Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 9
ccs 0
cts 5
cp 0
rs 9.6666
c 1
b 0
f 0
cc 2
crap 6
1
from oem.media.movie import MovieMatch
2
from oem.media.show import EpisodeMatch
3
4
from plugin.core.environment import Environment
5
from plugin.modules.core.base import Module
6
7
from oem import OemClient
8
from oem.media.show.identifier import EpisodeIdentifier
9
from oem.providers import IncrementalReleaseProvider
10
from oem_storage_codernitydb.main import CodernityDbStorage
11
from plex_metadata import Guid
12
import logging
13
import os
14
15
log = logging.getLogger(__name__)
16
17
18
class Mapper(Module):
19
    __key__ = 'mapper'
20
21
    services = {
22
        'anidb': ['imdb', 'tvdb']  # Try match against imdb database first
23
    }
24
25
    def __init__(self):
26
        self._client = None
27
28
    def start(self):
29
        # Construct oem client
30
        self._client = OemClient(
31
            provider=IncrementalReleaseProvider(
32
                fmt='minimize+msgpack',
33
                storage=CodernityDbStorage(os.path.join(
34
                    Environment.path.plugin_caches,
35
                    'oem'
36
                ))
37
            )
38
        )
39
40
    #
41
    # Movie
42
    #
43
44
    def map_movie(self, guid, movie):
45
        # Ensure guid has been parsed
46
        if type(guid) is str:
47
            guid = Guid.parse(guid)
48
49
        # Try match movie against database
50
        return self.map(guid.service, guid.id)
51
52
    def request_movie(self, guid, movie):
53
        # Try match movie against database
54
        supported, match = self.map_movie(guid, movie)
55
56
        if not match:
57
            return supported, None
58
59
        # Build request for Trakt.tv
60
        return supported, self._build_movie_request(match, movie)
61
62
    #
63
    # Shows
64
    #
65
66
    def map_episode(self, guid, season_num, episode_num):
67
        # Ensure guid has been parsed
68
        if type(guid) is str:
69
            guid = Guid.parse(guid)
70
71
        # Build episode identifier
72
        identifier = EpisodeIdentifier(
73
            season_num=season_num,
74
            episode_num=episode_num
75
        )
76
77
        # Try match episode against database
78
        return self.map(guid.service, guid.id, identifier)
79
80
    def request_episode(self, guid, episode):
81
        # Try match episode against database
82
        supported, match = self.map_episode(guid, episode.season.index, episode.index)
83
84
        if not match:
85
            return supported, None
86
87
        # Build request for Trakt.tv
88
        return supported, self._build_episode_request(match, episode)
89
90
    #
91
    # Helper methods
92
    #
93
94
    def map(self, source, key, identifier=None):
95
        if source not in self.services:
96
            return False, None
97
98
        for target, service in self._iter_services(source):
99
            try:
100
                match = service.map(key, identifier)
101
            except Exception, ex:
102
                log.warn('Unable to retrieve mapping for %r (%s -> %s) - %s', key, source, target, ex, exc_info=True)
103
                continue
104
105
            if match:
106
                return True, match
107
108
        return True, None
109
110
    def match(self, source, key):
111
        if source not in self.services:
112
            return False, None
113
114
        for target, service in self._iter_services(source):
115
            try:
116
                result = service.get(key)
117
            except Exception, ex:
118
                log.warn('Unable to retrieve item for %r (%s -> %s) - %s', key, source, target, ex, exc_info=True)
119
                continue
120
121
            if result:
122
                return True, result
123
124
        log.warn('Unable to find item for %s: %r', source, key)
125
        return True, None
126
127
    def _build_episode_request(self, match, episode):
128
        if isinstance(match, MovieMatch):
129
            return {
130
                'movie': {
131
                    'title': episode.show.title,
132
                    'year': episode.show.year,
133
134
                    'ids': match.identifiers
135
                }
136
            }
137
138
        if isinstance(match, EpisodeMatch):
139
            if match.absolute_num is not None:
140
                # TODO support for absolute episode scrobbling
141
                log.info('Absolute season mappings are not supported yet')
142
                return None
143
144
            if match.season_num is None or match.episode_num is None:
145
                log.warn('Missing season or episode number in %r', match)
146
                return None
147
148
            return {
149
                'show': {
150
                    'title': episode.show.title,
151
                    'year': episode.year,
152
153
                    'ids': match.identifiers
154
                },
155
                'episode': {
156
                    'title': episode.title,
157
158
                    'season': match.season_num,
159
                    'number': match.episode_num
160
                }
161
            }
162
163
        log.warn('Unknown match returned: %r', match)
164
        return None
165
    
166
    def _build_movie_request(self, match, movie):
167
        if not isinstance(match, MovieMatch):
168
            log.warn('Invalid match returned for movie: %r')
169
            return None
170
171
        return {
172
            'movie': {
173
                'title': movie.title,
174
                'year': movie.year,
175
176
                'ids': match.identifiers
177
            }
178
        }
179
180
    def _iter_services(self, source):
181
        if source not in self.services:
182
            return
183
184
        for target in self.services[source]:
185
            try:
186
                service = self._client[source].to(target)
187
            except KeyError:
188
                log.warn('Unable to find service: %s -> %s', source, target)
189
                continue
190
            except Exception, ex:
191
                log.warn('Unable to retrieve service: %s -> %s - %s', source, target, ex, exc_info=True)
192
                continue
193
194
            yield target, service
195