GuidParser.parse()   F
last analyzed

Complexity

Conditions 16

Size

Total Lines 68

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 222.5803

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 68
ccs 2
cts 29
cp 0.069
rs 2.6004
cc 16
crap 222.5803

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Complexity

Complex classes like GuidParser.parse() often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1 1
from oem.media.movie import MovieMatch
2 1
from plugin.core.constants import GUID_SERVICES
3 1
from plugin.core.helpers.variable import try_convert
4 1
from plugin.modules.core.manager import ModuleManager
5 1
from plugin.sync.core.guid.match import GuidMatch
6
7 1
from oem.media.show import EpisodeMatch
8 1
from plex_metadata import Guid
9 1
import logging
10
11 1
log = logging.getLogger(__name__)
12
13
14 1
class GuidParser(object):
15 1
    @classmethod
16 1
    def parse(cls, guid, episode=None):
17
        media = (
18
            GuidMatch.Media.Episode
19
            if episode else GuidMatch.Media.Movie
20
        )
21
22
        # Ensure guid is valid
23
        if not guid or not guid.valid:
24
            return GuidMatch(
25
                media, guid,
26
                invalid=True
27
            )
28
29
        # Process guid episode identifier overrides
30
        if episode and len(episode) == 2:
31
            season_num, episode_num = episode
32
33
            if guid.season is not None:
34
                episode = guid.season, episode_num
35
36
        # Process natively supported guid services
37
        if guid.service in GUID_SERVICES:
38
            episodes = None
39
40
            if episode and len(episode) == 2:
41
                episodes = [episode]
42
43
            return GuidMatch(
44
                media, guid,
45
                episodes=episodes,
46
                supported=True,
47
                found=True
48
            )
49
50
        # Process episode
51
        if episode:
52
            return cls.parse_episode(guid, episode)
53
54
        # Process shows + movies
55
        supported, (service, key) = ModuleManager['mapper'].id(
56
            guid.service, guid.id,
57
            resolve_mappings=False
58
        )
59
60
        # Validate match
61
        if not supported:
62
            return GuidMatch(media, guid)
63
64
        if not service or not key:
65
            return GuidMatch(media, guid, supported=True)
66
67
        # Validate identifier
68
        if type(key) is list:
69
            log.info('[%s/%s] - List keys are not supported', guid.service, guid.id)
70
            return GuidMatch(media, guid, supported=True)
71
72
        if type(key) not in [int, str]:
73
            log.info('[%s/%s] - Unsupported key: %r', guid.service, guid.id, key)
74
            return GuidMatch(media, guid, supported=True)
75
76
        log.debug('[%s/%s] - Mapped to: %s/%s', guid.service, guid.id, service, key)
77
78
        # Return movie/show match
79
        return GuidMatch(
80
            media, Guid.construct(service, key, matched=True),
81
            supported=True,
82
            found=True
83
        )
84
85 1
    @classmethod
86
    def parse_episode(cls, guid, (season_num, episode_num)):
87
        episodes = [(season_num, episode_num)]
88
89
        # Map episode to a supported service (via OEM)
90
        supported, match = ModuleManager['mapper'].map_episode(
91
            guid, season_num, episode_num,
92
            resolve_mappings=False
93
        )
94
95
        # Validate match
96
        if not supported:
97
            return GuidMatch(
98
                GuidMatch.Media.Episode, guid,
99
                episodes=episodes
100
            )
101
102
        if not match or not match.identifiers:
103
            log.debug('Unable to find mapping for %r S%02dE%02d', guid, season_num, episode_num)
104
            return GuidMatch(
105
                GuidMatch.Media.Episode, guid,
106
                episodes=episodes,
107
                supported=True
108
            )
109
110
        # Retrieve identifier
111
        service = match.identifiers.keys()[0]
112
        key = match.identifiers[service]
113
114
        if type(key) is list:
115
            log.info('[%s/%s] - List keys are not supported', guid.service, guid.id)
116
            return GuidMatch(
117
                GuidMatch.Media.Episode, guid,
118
                episodes=episodes,
119
                supported=True
120
            )
121
122
        # Cast `key` numbers to integers
123
        key = try_convert(key, int, key)
124
125
        # Validate show identifier
126
        if type(key) not in [int, str]:
127
            log.info('[%s/%s] - Unsupported key: %r', guid.service, guid.id, key)
128
            return GuidMatch(
129
                GuidMatch.Media.Episode, guid,
130
                episodes=episodes,
131
                supported=True
132
            )
133
134
        # Process episode matches
135
        if isinstance(match, EpisodeMatch):
136
            # Ensure match doesn't include an absolute number
137
            if match.absolute_num is not None:
138
                log.info('[%s/%s] - Episode mappings with absolute numbers are not supported', guid.service, guid.id)
139
                return GuidMatch(
140
                    GuidMatch.Media.Episode, guid,
141
                    episodes=episodes,
142
                    supported=True
143
                )
144
145
            # Update `episodes` list
146
            if match.mappings:
147
                # Use match mappings
148
                episodes = []
149
150
                for mapping in match.mappings:
151
                    log.debug('[%s/%s] (S%02dE%02d) - Mapped to: %r', guid.service, guid.id, season_num, episode_num, mapping)
152
                    episodes.append((
153
                        int(mapping.season),
154
                        int(mapping.number)
155
                    ))
156
            else:
157
                # Use match identifier
158
                log.debug('[%s/%s] (S%02dE%02d) - Mapped to: %r', guid.service, guid.id, season_num, episode_num, match)
159
                episodes = [(
160
                    int(match.season_num),
161
                    int(match.episode_num)
162
                )]
163
164
            # Return episode match
165
            return GuidMatch(
166
                GuidMatch.Media.Episode, Guid.construct(service, key, matched=True),
167
                episodes=episodes,
168
                supported=True,
169
                found=True
170
            )
171
172
        # Process movie matches
173
        if isinstance(match, MovieMatch):
174
            log.debug('[%s/%s] (S%02dE%02d) - Mapped to: %r', guid.service, guid.id, season_num, episode_num, match)
175
176
            # Return movie match
177
            return GuidMatch(
178
                GuidMatch.Media.Movie, Guid.construct(service, key, matched=True),
179
                supported=True,
180
                found=True
181
            )
182
183
        # Unknown value for `match` returned
184
        log.warn('Unknown match returned: %r', match)
185
        return GuidMatch(
186
            GuidMatch.Media.Episode, guid,
187
            episodes=episodes,
188
            supported=True
189
        )
190