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

Mode.trakt()   A

Complexity

Conditions 3

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 6.7968
Metric Value
cc 3
dl 0
loc 6
ccs 1
cts 4
cp 0.25
crap 6.7968
rs 9.4285
1 1
from plugin.core.filters import Filters
2 1
from plugin.sync import SyncMedia, SyncData, SyncMode
3
4 1
from plex import Plex
5 1
import elapsed
6 1
import itertools
7 1
import logging
8
9 1
log = logging.getLogger(__name__)
10
11 1
TRAKT_DATA_MAP = {
12
    SyncMedia.Movies: [
13
        SyncData.Collection,
14
        SyncData.Playback,
15
        SyncData.Ratings,
16
        SyncData.Watched,
17
        # SyncData.Watchlist
18
    ],
19
    SyncMedia.Shows: [
20
        SyncData.Ratings
21
    ],
22
    SyncMedia.Seasons: [
23
        SyncData.Ratings
24
    ],
25
    SyncMedia.Episodes: [
26
        SyncData.Collection,
27
        SyncData.Playback,
28
        SyncData.Ratings,
29
        SyncData.Watched,
30
        # SyncData.Watchlist
31
    ]
32
}
33
34 1
DATA_PREFERENCE_MAP = {
35
    SyncData.Collection:    'sync.collection.mode',
36
    SyncData.Playback:      'sync.playback.mode',
37
    SyncData.Ratings:       'sync.ratings.mode',
38
    SyncData.Watched:       'sync.watched.mode',
39
40
    # Lists
41
    SyncData.Liked:         'sync.lists.liked.mode',
42
    SyncData.Personal:      'sync.lists.personal.mode',
43
    SyncData.Watchlist:     'sync.lists.watchlist.mode',
44
}
45
46
47 1
class Mode(object):
48 1
    data = None
49 1
    mode = None
50
51 1
    children = []
52
53 1
    def __init__(self, task):
54
        self.__task = task
55
56
        self.children = [c(task) for c in self.children]
57
58
        # Retrieve enabled data
59
        self.enabled_data = self.get_enabled_data()
60
61
        # Determine if mode should be enabled
62
        self.enabled = len(self.enabled_data) > 0
63
64
        if not self.enabled:
65
            log.debug('Mode %r disabled on: %r', self.mode, self)
66
67 1
    @property
68
    def current(self):
69
        return self.__task
70
71 1
    @property
72
    def configuration(self):
73
        return self.__task.configuration
74
75 1
    @property
76
    def handlers(self):
77
        return self.__task.handlers
78
79 1
    @property
80
    def modes(self):
81
        return self.__task.modes
82
83 1
    @property
84
    def plex(self):
85
        if not self.current or not self.current.state:
86
            return None
87
88
        return self.current.state.plex
89
90 1
    @property
91
    def trakt(self):
92
        if not self.current or not self.current.state:
93
            return None
94
95
        return self.current.state.trakt
96
97 1
    def construct(self):
98
        pass
99
100 1
    def start(self):
101
        pass
102
103 1
    def run(self):
104
        raise NotImplementedError
105
106 1
    def stop(self):
107
        pass
108
109 1
    def checkpoint(self):
110
        if self.current is None:
111
            return
112
113
        self.current.checkpoint()
114
115 1
    def execute_children(self, name, force=None):
116
        # Run method on children
117
        for c in self.children:
118
            if not force and not c.enabled:
119
                log.debug('Ignoring %s() call on child: %r', name, c)
120
                continue
121
122
            # Find method `name` in child
123
            log.info('Executing %s() on child: %r', name, c)
124
125
            func = getattr(c, name, None)
126
127
            if not func:
128
                log.warn('Unknown method: %r', name)
129
                continue
130
131
            # Run method on child
132
            func()
133
134 1
    @elapsed.clock
135
    def execute_handlers(self, media, data, *args, **kwargs):
136
        if type(media) is not list:
137
            media = [media]
138
139
        if type(data) is not list:
140
            data = [data]
141
142
        for m, d in itertools.product(media, data):
143
            if d not in self.handlers:
144
                log.debug('Unable to find handler for data: %r', d)
145
                continue
146
147
            try:
148
                self.handlers[d].run(m, self.mode, *args, **kwargs)
149
            except Exception, ex:
150
                log.warn('Exception raised in handlers[%r].run(%r, ...): %s', d, m, ex, exc_info=True)
151
152 1
    def get_enabled_data(self):
153
        config = self.configuration
154
155
        # Determine accepted modes
156
        modes = [SyncMode.Full]
157
158
        if self.mode == SyncMode.Full:
159
            modes.extend([
160
                SyncMode.FastPull,
161
                SyncMode.Pull,
162
                SyncMode.Push
163
            ])
164
        elif self.mode == SyncMode.FastPull:
165
            modes.extend([
166
                self.mode,
167
                SyncMode.Pull
168
            ])
169
        else:
170
            modes.append(self.mode)
171
172
        # Retrieve enabled data
173
        result = []
174
175
        if config['sync.watched.mode'] in modes:
176
            result.append(SyncData.Watched)
177
178
        if config['sync.ratings.mode'] in modes:
179
            result.append(SyncData.Ratings)
180
181
        if config['sync.playback.mode'] in modes:
182
            result.append(SyncData.Playback)
183
184
        if config['sync.collection.mode'] in modes:
185
            result.append(SyncData.Collection)
186
187
        # Lists
188
        if config['sync.lists.watchlist.mode'] in modes:
189
            result.append(SyncData.Watchlist)
190
191
        if config['sync.lists.liked.mode'] in modes:
192
            result.append(SyncData.Liked)
193
194
        if config['sync.lists.personal.mode'] in modes:
195
            result.append(SyncData.Personal)
196
197
        # Filter `result` to data provided by this mode
198
        if self.data is None:
199
            log.warn('No "data" property defined on %r', self)
200
            return result
201
202
        if self.data == SyncData.All:
203
            return result
204
205
        return [
206
            data for data in result
207
            if data in self.data
208
        ]
209
210 1
    def get_data(self, media):
211
        for data in TRAKT_DATA_MAP[media]:
212
            if not self.is_data_enabled(data):
213
                continue
214
215
            yield data
216
217 1
    @elapsed.clock
218
    def is_data_enabled(self, data):
219
        return data in self.enabled_data
220
221 1
    def sections(self, section_type=None):
222
        # Retrieve "section" for current task
223
        section_key = self.current.kwargs.get('section', None)
224
225
        # Fetch sections from server
226
        p_sections = Plex['library'].sections()
227
228
        if p_sections is None:
229
            return None
230
231
        # Filter sections, map to dictionary
232
        result = {}
233
234
        for section in p_sections.filter(section_type, section_key):
235
            # Apply section name filter
236
            if not Filters.is_valid_section_name(section.title):
237
                continue
238
239
            try:
240
                key = int(section.key)
241
            except Exception, ex:
242
                log.warn('Unable to cast section key %r to integer: %s', section.key, ex, exc_info=True)
243
                continue
244
245
            result[key] = section.uuid
246
247
        return [(key, ) for key in result.keys()], result
248