Base.build_request()   F
last analyzed

Complexity

Conditions 12

Size

Total Lines 60

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 156

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 60
ccs 0
cts 33
cp 0
rs 3.0169
cc 12
crap 156

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 Base.build_request() 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
from plugin.core.filters import Filters
2
from plugin.core.helpers.variable import merge
3
from plugin.core.identifier import Identifier
4
from plugin.core.logger.helpers import log_unsupported_guid
5
from plugin.managers.session.base import UpdateSession
6
from plugin.modules.core.manager import ModuleManager
7
8
from plex.objects.library.metadata.episode import Episode
9
from plex.objects.library.metadata.movie import Movie
10
from plex_metadata import Metadata, Guid
11
import logging
12
13
log = logging.getLogger(__name__)
14
15
16
class Base(object):
17
    name = None
18
19
    @classmethod
20
    def build_request(cls, session, part=None, rating_key=None, view_offset=None):
21
        # Retrieve metadata for session
22
        if part is None:
23
            part = session.part
24
25
        if rating_key is None:
26
            rating_key = session.rating_key
27
28
        # Retrieve metadata
29
        metadata = Metadata.get(rating_key)
30
31
        # Validate metadata
32
        if not metadata:
33
            log.warn('Unable to retrieve metadata for rating_key %r', rating_key)
34
            return None
35
36
        if metadata.type not in ['movie', 'episode']:
37
            log.info('Ignoring session with type %r for rating_key %r', metadata.type, rating_key)
38
            return None
39
40
        # Apply library/section filter
41
        if not Filters.is_valid_metadata_section(metadata):
42
            log.info('Ignoring session in filtered section: %r', metadata.section.title)
43
            return None
44
45
        # Parse guid
46
        guid = Guid.parse(metadata.guid, strict=True)
47
48
        if not guid or not guid.valid:
49
            log_unsupported_guid(log, guid)
50
            return None
51
52
        # Build request from guid/metadata
53
        if type(metadata) is Movie:
54
            result = cls.build_movie(metadata, guid, part)
55
        elif type(metadata) is Episode:
56
            result = cls.build_episode(metadata, guid, part)
57
        else:
58
            log.warn('Unknown metadata type: %r', type(metadata))
59
            return None
60
61
        if not result:
62
            log.info('Unable to build request for session: %r', session)
63
            return None
64
65
        # Retrieve media progress
66
        if view_offset is not None:
67
            # Calculate progress from `view_offset` parameter
68
            progress = UpdateSession.get_progress(
69
                metadata.duration, view_offset,
70
                part, session.part_count, session.part_duration
71
            )
72
        else:
73
            # Use session progress
74
            progress = session.progress
75
76
        # Merge progress into request
77
        return merge(result, {
78
            'progress': progress
79
        })
80
81
    @classmethod
82
    def build_episode(cls, episode, guid, part):
83
        # Retrieve show identifier
84
        ids = Identifier.get_ids(guid, strict=False)
85
86
        if not ids:
87
            # Try map episode to a supported service (with OEM)
88
            supported, request = ModuleManager['mapper'].request_episode(
89
                guid, episode,
90
                part=part
91
            )
92
93
            if not supported:
94
                log.info('No mappings available for service: %r', guid.service)
95
96
            return request
97
98
        # Retrieve episode number
99
        season_num, episodes = ModuleManager['matcher'].process(episode)
100
101
        if len(episodes) > 0 and part - 1 < len(episodes):
102
            episode_num = episodes[part - 1]
103
        elif len(episodes) > 0:
104
            log.warn('Part %s doesn\'t exist in episodes: %r', part, episodes)
105
            episode_num = episodes[0]
106
        else:
107
            log.warn('Matcher didn\'t return a valid result - season_num: %r, episodes: %r', season_num, episodes)
108
            episode_num = episode.index
109
110
        # Process guid episode identifier overrides
111
        if guid.season is not None:
112
            season_num = guid.season
113
114
        # Build request
115
        return {
116
            'show': {
117
                'title': episode.show.title,
118
                'year': episode.year,
119
120
                'ids': ids
121
            },
122
            'episode': {
123
                'title': episode.title,
124
125
                'season': season_num,
126
                'number': episode_num
127
            }
128
        }
129
130
    @staticmethod
131
    def build_movie(movie, guid, part):
132
        ids = Identifier.get_ids(guid, strict=False)
133
134
        if not ids:
135
            # Try map episode to a supported service (with OEM)
136
            supported, request = ModuleManager['mapper'].request_movie(
137
                guid, movie,
138
                part=part
139
            )
140
141
            if not supported:
142
                log.info('No mappings available for service: %r', guid.service)
143
144
            return request
145
146
        return {
147
            'movie': {
148
                'title': movie.title,
149
                'year': movie.year,
150
151
                'ids': ids
152
            }
153
        }
154
155
    @staticmethod
156
    def session_jumped(session, view_offset):
157
        if session.view_offset is None or view_offset is None:
158
            return False
159
160
        view_delta = view_offset - session.view_offset
161
162
        jump_offset = session.duration - session.view_offset - view_delta
163
        jump_perc = float(view_delta) / session.duration
164
165
        if jump_perc >= 0.98 and jump_offset < 1000:
166
            log.info('Session jumped: %r -> %r (delta: %r, jump_offset: %r, jump_perc: %r)', session.view_offset, view_offset, view_delta, jump_offset, jump_perc)
0 ignored issues
show
Coding Style introduced by
This line is too long as per the coding-style (162/120).

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

Loading history...
167
            return True
168
169
        return False
170