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