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

Shows.process_matched_shows()   C

Complexity

Conditions 7

Size

Total Lines 46

Duplication

Lines 46
Ratio 100 %

Code Coverage

Tests 2
CRAP Score 41.4155

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 46
loc 46
ccs 2
cts 18
cp 0.1111
rs 5.5
cc 7
crap 41.4155
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