Test Failed
Push — beta ( 7d3e07...a06fd2 )
by Dean
03:10
created

Shows.process_matched_episodes()   D

Complexity

Conditions 10

Size

Total Lines 62

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 97.5094

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 62
ccs 1
cts 23
cp 0.0434
rs 4.6753
cc 10
crap 97.5094

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 Shows.process_matched_episodes() 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 plugin.core.constants import GUID_SERVICES
0 ignored issues
show
Unused Code introduced by
Unused GUID_SERVICES imported from plugin.core.constants
Loading history...
2 1
from plugin.sync.core.enums import SyncMedia, SyncData
3 1
from plugin.sync.modes.core.base import log_unsupported, mark_unsupported
4 1
from plugin.sync.modes.push.base import Base
0 ignored issues
show
Bug introduced by
The name base does not seem to exist in module plugin.sync.modes.push.
Loading history...
Configuration introduced by
Unable to import 'plugin.sync.modes.push.base' (invalid syntax (<string>, line 37))

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
5
6 1
from plex_database.models import MetadataItem, MediaItem, Episode
7 1
from plex_metadata import Guid
8 1
import copy
9 1
import elapsed
10 1
import logging
11
12 1
log = logging.getLogger(__name__)
13
14
15 1
class Shows(Base):
16 1
    data = [
17
        SyncData.Collection,
18
        SyncData.Playback,
19
        SyncData.Ratings,
20
        SyncData.Watched
21
    ]
22
23 1
    def __init__(self, task):
24
        super(Shows, self).__init__(task)
25
26
        # Sections
27
        self.p_sections = None
28
        self.p_sections_map = None
29
30
        # Shows
31
        self.p_shows = None
32
        self.p_shows_count = None
33
        self.p_shows_pending = None
34
        self.p_shows_unsupported = None
35
36
        # Seasons
37
        self.p_seasons = None
38
39
        # Episodes
40
        self.p_episodes = None
41
        self.p_episodes_count = None
42
        self.p_episodes_pending = None
43
44 1
    @elapsed.clock
45
    def construct(self):
46
        # Retrieve movie sections
47
        self.p_sections, self.p_sections_map = self.sections('show')
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named sections.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
48
49
        # Determine number of shows that will be processed
50
        self.p_shows_count = self.plex.library.shows.count(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named plex.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
51
            self.p_sections
52
        )
53
54
        # Determine number of shows that will be processed
55
        self.p_episodes_count = self.plex.library.episodes.count_items(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named plex.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
56
            self.p_sections
57
        )
58
59
        # Increment progress steps total
60
        self.current.progress.group(Shows, 'matched:shows').add(self.p_shows_count)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
61
        self.current.progress.group(Shows, 'matched:episodes').add(self.p_episodes_count)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
62
        self.current.progress.group(Shows, 'missing:shows')
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
63
        self.current.progress.group(Shows, 'missing:episodes')
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
64
65 1
    @elapsed.clock
66
    def start(self):
67
        # Fetch movies with account settings
68
        self.p_shows, self.p_seasons, self.p_episodes = self.plex.library.episodes.mapped(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named plex.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
69
            self.p_sections, ([
70
                MetadataItem.title,
71
                MetadataItem.year
72
            ], [], [
73
                MediaItem.audio_channels,
74
                MediaItem.audio_codec,
75
                MediaItem.height,
76
                MediaItem.interlaced,
77
78
                Episode.added_at
79
            ]),
80
            account=self.current.account.plex.key,
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
81
            parse_guid=True
82
        )
83
84
        # Reset state
85
        self.p_shows_pending = self.trakt.table.show_keys.copy()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
86
        self.p_shows_unsupported = {}
87
88
        self.p_episodes_pending = copy.deepcopy(self.trakt.table.episode_keys)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
89
90 1
    @elapsed.clock
91
    def run(self):
92
        # Process matched items
93
        self.process_matched_shows()
94
        self.process_matched_episodes()
95
96
        # Report unsupported shows
97
        log_unsupported(log, 'Found %d unsupported show(s)', self.p_shows_unsupported)
98
99
        # Process missing items
100
        self.process_missing_shows()
101
        self.process_missing_episodes()
102
103
    #
104
    # Shows
105
    #
106
107 1 View Code Duplication
    @elapsed.clock
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
108
    def process_matched_shows(self):
109
        # Iterate over plex shows
110
        for sh_id, p_guid, p_show in self.p_shows:
111
            # Increment one step
112
            self.current.progress.group(Shows, 'matched:shows').step()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
113
114
            # Process `p_guid` (map + validate)
115
            supported, matched, p_guid = self.process_guid(p_guid)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named process_guid.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
116
117
            if not supported:
118
                mark_unsupported(self.p_shows_unsupported, sh_id, p_guid)
119
                continue
120
121
            if not matched:
122
                log.info('Unable to find identifier for: %s/%s (rating_key: %r)', p_guid.service, p_guid.id, sh_id)
123
                continue
124
125
            key = (p_guid.service, p_guid.id)
126
127
            # Try retrieve `pk` for `key`
128
            pk = self.trakt.table('shows').get(key)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
129
130
            for data in self.get_data(SyncMedia.Shows):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named get_data.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
131
                t_show = self.trakt[(SyncMedia.Shows, data)].get(pk)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
132
133
                # Execute show handlers
134
                self.execute_handlers(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named execute_handlers.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
135
                    SyncMedia.Shows, data,
136
                    key=sh_id,
137
                    guid=p_guid,
138
139
                    p_item=p_show,
140
141
                    t_item=t_show
142
                )
143
144
            # Remove show from `pending_shows`
145
            if pk and pk in self.p_shows_pending:
146
                self.p_shows_pending.remove(pk)
147
148
            # Task checkpoint
149
            self.checkpoint()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named checkpoint.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
150 1
151
        # Stop progress group
152
        self.current.progress.group(Shows, 'matched:shows').stop()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
153
154
    @elapsed.clock
155
    def process_missing_shows(self):
156
        if self.current.kwargs.get('section'):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
157
            # Collection cleaning disabled for individual syncs
158
            return
159
160
        # Increment progress steps
161
        self.current.progress.group(Shows, 'missing:shows').add(len(self.p_shows_pending))
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
162
163
        # Iterate over trakt shows (that aren't in plex)
164
        for pk in list(self.p_shows_pending):
165
            # Increment one step
166
            self.current.progress.group(Shows, 'missing:shows').step()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
167
168
            # Iterate over data handlers
169
            triggered = False
170
171
            for data in self.get_data(SyncMedia.Shows):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named get_data.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
172
                if data not in [SyncData.Collection]:
173
                    continue
174
175
                # Retrieve show
176
                t_show = self.trakt[(SyncMedia.Shows, data)].get(pk)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
177
178
                if not t_show:
179
                    continue
180
181
                log.debug('Found show missing from plex: %r [data: %r]', pk, SyncData.title(data))
182
183
                # Trigger handler
184
                self.execute_handlers(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named execute_handlers.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
185
                    SyncMedia.Shows, data,
186
187
                    key=None,
188
189
                    guid=Guid.construct(*pk),
190
                    p_item=None,
191
192
                    t_item=t_show
193
                )
194
195
                # Mark triggered
196
                triggered = True
197
198
            # Check if action was triggered
199
            if not triggered:
200
                continue
201
202
            # Remove movie from `pending` set
203
            self.p_shows_pending.remove(pk)
204
205
        # Stop progress group
206
        self.current.progress.group(Shows, 'missing:shows').stop()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
207
208
        self.log_pending(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named log_pending.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
209
            log, 'Unable to find %d show(s) in Plex, list has been saved to: %s',
210
            self.current.account, 'shows', self.p_shows_pending
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
211
        )
212
213 1
    #
214
    # Episodes
215
    #
216
217
    @elapsed.clock
218
    def process_matched_episodes(self):
219
        # Iterate over plex episodes
220
        for ids, p_guid, (season_num, episode_num), p_show, p_season, p_episode in self.p_episodes:
0 ignored issues
show
Unused Code introduced by
The variable p_season seems to be unused.
Loading history...
221
            # Increment one step
222
            self.current.progress.group(Shows, 'matched:episodes').step()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
223
224
            # Process `p_guid` (map + validate)
225
            supported, matched, p_guid, episodes = self.process_guid_episode(p_guid, season_num, episode_num)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named process_guid_episode.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
226
227
            if not supported:
228
                mark_unsupported(self.p_shows_unsupported, ids['show'], p_guid)
229
                continue
230
231
            if not matched:
232
                log.info('Unable to find identifier for: %s/%s (rating_key: %r)', p_guid.service, p_guid.id, ids['show'])
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (121/120).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
233
                continue
234
235
            if not episodes:
236
                log.warn('No episodes returned for: %s/%s', p_guid.service, p_guid.id)
237
                continue
238
239
            key = (p_guid.service, p_guid.id)
240
            season_num, episode_num = episodes[0]
241
242
            identifier = (season_num, episode_num)
243
244
            # Try retrieve `pk` for `key`
245
            pk = self.trakt.table('shows').get(key)
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
246
247
            with elapsed.clock(Shows, 'run:plex_episodes:execute_handlers'):
248
                for data in self.get_data(SyncMedia.Episodes):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named get_data.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
249
                    with elapsed.clock(Shows, 'run:plex_episodes:t_objects'):
250
                        t_show, t_season, t_episode = self.t_objects(
0 ignored issues
show
Unused Code introduced by
The variable t_season seems to be unused.
Loading history...
251
                            self.trakt[(SyncMedia.Episodes, data)], pk,
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
252
                            season_num, episode_num
253
                        )
254
255
                    # Execute episode handlers
256
                    self.execute_handlers(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named execute_handlers.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
257
                        SyncMedia.Episodes, data,
258
259
                        key=ids['episode'],
260
                        identifier=identifier,
261
262
                        guid=p_guid,
263
                        p_show=p_show,
264
                        p_item=p_episode,
265
266 1
                        t_show=t_show,
267
                        t_item=t_episode
268
                    )
269
270
            # Remove episode from `pending_episodes`
271
            if pk in self.p_episodes_pending and identifier in self.p_episodes_pending[pk]:
272
                self.p_episodes_pending[pk].remove(identifier)
273
274
            # Task checkpoint
275
            self.checkpoint()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named checkpoint.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
276
277
        # Stop progress group
278
        self.current.progress.group(Shows, 'matched:episodes').stop()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
279
280
    @elapsed.clock
281
    def process_missing_episodes(self):
282
        if self.current.kwargs.get('section'):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
283
            # Collection cleaning disabled for individual syncs
284
            return
285
286
        # Increment progress steps
287
        self.current.progress.group(Shows, 'missing:episodes').add(len(self.p_episodes_pending))
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
288
289
        # Iterate over trakt episodes (that aren't in plex)
290
        for pk, episodes in [(p, list(e)) for (p, e) in self.p_episodes_pending.items()]:
291
            # Increment one step
292
            self.current.progress.group(Shows, 'missing:episodes').step()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
293
294
            # Iterate over trakt episodes (that aren't in plex)
295
            for identifier in episodes:
296
                # Iterate over data handlers
297
                season_num, episode_num = identifier
298
                triggered = False
299
300
                for data in self.get_data(SyncMedia.Episodes):
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named get_data.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
301
                    if data not in [SyncData.Collection]:
302
                        continue
303
304
                    # Retrieve episode
305
                    t_show, t_season, t_episode = self.t_objects(
0 ignored issues
show
Unused Code introduced by
The variable t_season seems to be unused.
Loading history...
306
                        self.trakt[(SyncMedia.Episodes, data)], pk,
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named trakt.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
307
                        season_num, episode_num
308
                    )
309
310
                    if not t_episode:
311
                        continue
312
313
                    log.debug('Found episode missing from plex: %r - %r [data: %r]', pk, identifier, SyncData.title(data))
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (122/120).

This check looks for lines that are too long. You can specify the maximum line length.

Loading history...
314
315
                    # Trigger handler
316
                    self.execute_handlers(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named execute_handlers.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
317
                        SyncMedia.Episodes, data,
318
                        key=None,
319
                        identifier=identifier,
320
                        guid=Guid.construct(*pk),
321
322
                        p_show=None,
323
                        p_item=None,
324
325
                        t_show=t_show,
326
                        t_item=t_episode
327
                    )
328
329
                    # Mark triggered
330
                    triggered = True
331
332
                # Check if action was triggered
333 1
                if not triggered:
334
                    continue
335
336
                # Remove movie from `pending` set
337
                self.p_episodes_pending[pk].remove(identifier)
338
339
        # Stop progress group
340
        self.current.progress.group(Shows, 'missing:episodes').stop()
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
341
342
        self.log_pending(
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named log_pending.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
343
            log, 'Unable to find %d episode(s) in Plex, list has been saved to: %s',
344
            self.current.account, 'episodes', self.p_episodes_pending
0 ignored issues
show
Bug introduced by
The Instance of Shows does not seem to have a member named current.

This check looks for calls to members that are non-existent. These calls will fail.

The member could have been renamed or removed.

Loading history...
345
        )
346
347
    @staticmethod
348
    def t_objects(collection, pk, season_num, episode_num):
349
        # Try find trakt `Show` from `collection`
350
        t_show = collection.get(pk)
351
352
        if t_show is None:
353
            return t_show, None, None
354
355
        # Try find trakt `Season`
356
        t_season = t_show.seasons.get(season_num)
357
358
        if t_season is None:
359
            return t_show, t_season, None
360
361
        # Try find trakt `Episode`
362
        t_episode = t_season.episodes.get(episode_num)
363
364
        return t_show, t_season, t_episode
365