Test Failed
Push — beta ( c9094c...317f5f )
by Dean
03:05
created

UpdateSession.match_parts()   C

Complexity

Conditions 7

Size

Total Lines 44

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 44
ccs 0
cts 3
cp 0
rs 5.5
cc 7
crap 56
1
from plugin.core.constants import GUID_SERVICES
2
from plugin.managers.core.base import Get, Update
3
from plugin.modules.core.manager import ModuleManager
4
from plugin.scrobbler.core.session_prefix import SessionPrefix
5
6
from oem.media.show import EpisodeIdentifier, EpisodeMatch
7
from plex_metadata import Metadata, Guid
8
import logging
9
import math
10
11
log = logging.getLogger(__name__)
12
13
14
class Base(object):
15
    @classmethod
16
    def build_session_key(cls, session_key):
17
        if type(session_key) is str:
18
            return session_key
19
20
        # Prepend session prefix
21
        session_prefix = SessionPrefix.get()
22
23
        return '%s:%s' % (
24
            session_prefix,
25
            session_key
26
        )
27
28
29
class GetSession(Get, Base):
30
    pass
31
32
33
class UpdateSession(Update, Base):
34
    @staticmethod
35
    def get_account(result):
36
        # Try retrieve account from client
37
        client = result.get('client')
38
39
        try:
40
            client_account_id = client.account_id if client else None
41
        except KeyError:
42
            client_account_id = None
43
44
        if client_account_id:
45
            # Valid account found
46
            return client_account_id
47
48
        # Try retrieve account from user
49
        user = result.get('user')
50
51
        try:
52
            user_account_id = user.account_id if user else None
53
        except KeyError:
54
            user_account_id = None
55
56
        if user_account_id:
57
            # Valid account found
58
            return user_account_id
59
60
        return None
61
62
    @staticmethod
63
    def get_metadata(rating_key):
64
        # Retrieve metadata for `rating_key`
65
        try:
66
            metadata = Metadata.get(rating_key)
67
        except NotImplementedError, e:
68
            log.debug('%r, ignoring session', e.message)
69
            return None, None
70
71
        # Ensure metadata was returned
72
        if not metadata:
73
            return None, None
74
75
        # Validate metadata
76
        if metadata.type not in ['movie', 'episode']:
77
            log.info('Ignoring metadata with type %r for rating_key %r', metadata.type, rating_key)
78
            return metadata, None
79
80
        # Parse guid
81
        guid = Guid.parse(metadata.guid, strict=True)
82
83
        return metadata, guid
84
85
    @classmethod
86
    def match_parts(cls, p_metadata, guid, view_offset):
87
        if p_metadata.type != 'episode':
88
            # TODO support multi-part movies
89
            return 1, 1, p_metadata.duration
90
91
        # Retrieve number of parts
92
        if guid.service in GUID_SERVICES:
93
            # Parse parts from filename
94
            _, episodes = ModuleManager['matcher'].process(p_metadata)
95
96
            part_count = len(episodes)
97
        else:
98
            season_num = p_metadata.season.index
99
            episode_num = p_metadata.index
100
101
            # Process guid episode identifier overrides
102
            if guid.season is not None:
103
                season_num = guid.season
104
105
            # Retrieve episode mappings from OEM
106
            supported, match = ModuleManager['mapper'].map(
107
                guid.service, guid.id,
108
                EpisodeIdentifier(season_num, episode_num),
109
                resolve_mappings=False
110
            )
111
112
            if not supported or not match:
113
                return 1, 1, p_metadata.duration
114
115
            if not isinstance(match, EpisodeMatch):
116
                log.info('Movie mappings are not supported')
117
                return 1, 1, p_metadata.duration
118
119
            part_count = len(match.mappings) or 1
120
121
        # Determine the current part number
122
        part, part_duration = cls.get_part(
123
            p_metadata.duration,
124
            view_offset,
125
            part_count
126
        )
127
128
        return part, part_count, part_duration
129
130
    @staticmethod
131
    def get_part(duration, view_offset, part_count):
132
        if duration is None or part_count is None or part_count < 1:
133
            return 1, duration
134
135
        part_duration = int(math.floor(
136
            float(duration) / part_count
137
        ))
138
139
        # Calculate current part number
140
        part = int(math.floor(
141
            float(view_offset) / part_duration
142
        )) + 1
143
144
        # Clamp `part` to: 0 - `total_parts`
145
        return max(0, min(part, part_count)), part_duration
146
147
    @staticmethod
148
    def get_progress(duration, view_offset, part=1, part_count=1, part_duration=None):
149
        if duration is None:
150
            return None
151
152
        if part_count > 1 and part_duration is not None:
153
            # Update attributes for part progress calculations
154
            duration = part_duration
155
            view_offset -= (part_duration * (part - 1))
156
157
        # Calculate progress (0 - 100)
158
        return round((float(view_offset) / duration) * 100, 2)
159