Passed
Push — master ( aeb165...d9ae97 )
by Dean
03:04
created

Shows.run()   A

Complexity

Conditions 1

Size

Total Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1.5786
Metric Value
cc 1
dl 0
loc 12
ccs 1
cts 6
cp 0.1666
crap 1.5786
rs 9.4285
1 1
from plugin.core.constants import GUID_SERVICES
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
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)\n%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, 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
            # Ensure `guid` is available
115
            if not guid or guid.service not in GUID_SERVICES:
116
                mark_unsupported(self.p_shows_unsupported, sh_id, guid)
117
                continue
118
119
            key = (guid.service, guid.id)
120
121
            # Try retrieve `pk` for `key`
122
            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...
123
124
            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...
125
                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...
126
127
                # Execute show handlers
128
                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...
129
                    SyncMedia.Shows, data,
130
                    key=sh_id,
131
                    guid=guid,
132
133
                    p_item=p_show,
134
135
                    t_item=t_show
136
                )
137
138
            # Remove show from `pending_shows`
139
            if pk and pk in self.p_shows_pending:
140
                self.p_shows_pending.remove(pk)
141
142
            # Task checkpoint
143
            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...
144
145
        # Stop progress group
146
        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...
147
148 1 View Code Duplication
    @elapsed.clock
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
149
    def process_missing_shows(self):
150
        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...
151
            # Collection cleaning disabled for individual syncs
152
            return
153
154
        # Increment progress steps
155
        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...
156
157
        # Iterate over trakt shows (that aren't in plex)
158
        for pk in list(self.p_shows_pending):
159
            # Increment one step
160
            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...
161
162
            # Iterate over data handlers
163
            triggered = False
164
165
            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...
166
                if data not in [SyncData.Collection]:
167
                    continue
168
169
                # Retrieve show
170
                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...
171
172
                if not t_show:
173
                    continue
174
175
                log.debug('Found show missing from plex: %r [data: %r]', pk, SyncData.title(data))
176
177
                # Trigger handler
178
                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...
179
                    SyncMedia.Shows, data,
180
181
                    key=None,
182
183
                    guid=Guid.construct(*pk),
184
                    p_item=None,
185
186
                    t_item=t_show
187
                )
188
189
                # Mark triggered
190
                triggered = True
191
192
            # Check if action was triggered
193
            if not triggered:
194
                continue
195
196
            # Remove movie from `pending` set
197
            self.p_shows_pending.remove(pk)
198
199
        # Stop progress group
200
        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...
201
202
        self.log_pending('Unable to find %d show(s) in Plex\n%s', self.p_shows_pending)
203
204
    #
205
    # Episodes
206
    #
207
208 1
    @elapsed.clock
209
    def process_matched_episodes(self):
210
        # Iterate over plex episodes
211
        for ids, 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...
212
            # Increment one step
213
            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...
214
215
            # Ensure `guid` is available
216
            if not guid or guid.service not in GUID_SERVICES:
217
                mark_unsupported(self.p_shows_unsupported, ids['show'], guid)
218
                continue
219
220
            key = (guid.service, guid.id)
221
            identifier = (season_num, episode_num)
222
223
            # Try retrieve `pk` for `key`
224
            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...
225
226
            with elapsed.clock(Shows, 'run:plex_episodes:execute_handlers'):
227
                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...
228
                    with elapsed.clock(Shows, 'run:plex_episodes:t_objects'):
229
                        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...
230
                            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...
231
                            season_num, episode_num
232
                        )
233
234
                    # Execute episode handlers
235
                    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...
236
                        SyncMedia.Episodes, data,
237
238
                        key=ids['episode'],
239
                        identifier=identifier,
240
241
                        guid=guid,
242
                        p_show=p_show,
243
                        p_item=p_episode,
244
245
                        t_show=t_show,
246
                        t_item=t_episode
247
                    )
248
249
            # Remove episode from `pending_episodes`
250
            if pk in self.p_episodes_pending and identifier in self.p_episodes_pending[pk]:
251
                self.p_episodes_pending[pk].remove(identifier)
252
253
            # Task checkpoint
254
            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...
255
256
        # Stop progress group
257
        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...
258
259 1
    @elapsed.clock
260
    def process_missing_episodes(self):
261
        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...
262
            # Collection cleaning disabled for individual syncs
263
            return
264
265
        # Increment progress steps
266
        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...
267
268
        # Iterate over trakt episodes (that aren't in plex)
269
        for pk, episodes in [(p, list(e)) for (p, e) in self.p_episodes_pending.items()]:
270
            # Increment one step
271
            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...
272
273
            # Iterate over trakt episodes (that aren't in plex)
274
            for identifier in episodes:
275
                # Iterate over data handlers
276
                season_num, episode_num = identifier
277
                triggered = False
278
279
                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...
280
                    if data not in [SyncData.Collection]:
281
                        continue
282
283
                    # Retrieve episode
284
                    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...
285
                        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...
286
                        season_num, episode_num
287
                    )
288
289
                    if not t_episode:
290
                        continue
291
292
                    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...
293
294
                    # Trigger handler
295
                    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...
296
                        SyncMedia.Episodes, data,
297
                        key=None,
298
                        identifier=identifier,
299
                        guid=Guid.construct(*pk),
300
301
                        p_show=None,
302
                        p_item=None,
303
304
                        t_show=t_show,
305
                        t_item=t_episode
306
                    )
307
308
                    # Mark triggered
309
                    triggered = True
310
311
                # Check if action was triggered
312
                if not triggered:
313
                    continue
314
315
                # Remove movie from `pending` set
316
                self.p_episodes_pending[pk].remove(identifier)
317
318
        # Stop progress group
319
        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...
320
321
        self.log_pending('Unable to find %d episode(s) in Plex\n%s', self.p_episodes_pending)
322
323 1
    @staticmethod
324
    def t_objects(collection, pk, season_num, episode_num):
325
        # Try find trakt `Show` from `collection`
326
        t_show = collection.get(pk)
327
328
        if t_show is None:
329
            return t_show, None, None
330
331
        # Try find trakt `Season`
332
        t_season = t_show.seasons.get(season_num)
333
334
        if t_season is None:
335
            return t_show, t_season, None
336
337
        # Try find trakt `Episode`
338
        t_episode = t_season.episodes.get(episode_num)
339
340
        return t_show, t_season, t_episode
341