Test Failed
Push — beta ( 918fe2...7d3e07 )
by Dean
03:03
created

UpdateSession.match_parts()   B

Complexity

Conditions 6

Size

Total Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 42

Importance

Changes 0
Metric Value
dl 0
loc 37
ccs 0
cts 1
cp 0
rs 7.5384
c 0
b 0
f 0
cc 6
crap 42
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
        # Queue flush for metadata cache
76
        Metadata.cache.flush_queue()
77
78
        # Validate metadata
79
        if metadata.type not in ['movie', 'episode']:
80
            log.info('Ignoring metadata with type %r for rating_key %r', metadata.type, rating_key)
81
            return metadata, None
82
83
        # Parse guid
84
        guid = Guid.parse(metadata.guid)
85
86
        return metadata, guid
87
88
    @classmethod
89
    def match_parts(cls, p_metadata, guid, view_offset):
90
        if p_metadata.type != 'episode':
91
            # TODO support multi-part movies
92
            return 1, 1, p_metadata.duration
93
94
        # Retrieve number of parts
95
        if guid.service in GUID_SERVICES:
96
            # Parse parts from filename
97
            _, episodes = ModuleManager['matcher'].process(p_metadata)
98
99
            part_count = len(episodes)
100
        else:
101
            # Retrieve episode mappings from OEM
102
            supported, match = ModuleManager['mapper'].map(
103
                guid.service, guid.id,
104
                EpisodeIdentifier(p_metadata.season.index, p_metadata.index),
105
                resolve_mappings=False
106
            )
107
108
            if not supported or not match:
109
                return 1, 1, p_metadata.duration
110
111
            if not isinstance(match, EpisodeMatch):
112
                log.info('Movie mappings are not supported')
113
                return 1, 1, p_metadata.duration
114
115
            part_count = len(match.mappings)
116
117
        # Determine the current part number
118
        part, part_duration = cls.get_part(
119
            p_metadata.duration,
120
            view_offset,
121
            part_count
122
        )
123
124
        return part, part_count, part_duration
125
126
    @staticmethod
127
    def get_part(duration, view_offset, part_count):
128
        if duration is None:
129
            return 1, duration
130
131
        part_duration = int(math.floor(
132
            float(duration) / part_count
133
        ))
134
135
        # Calculate current part number
136
        part = int(math.floor(
137
            float(view_offset) / part_duration
138
        )) + 1
139
140
        # Clamp `part` to: 0 - `total_parts`
141
        return max(0, min(part, part_count)), part_duration
142
143
    @staticmethod
144
    def get_progress(duration, view_offset, part=1, part_count=1, part_duration=None):
145
        if duration is None:
146
            return None
147
148
        if part_count > 1 and part_duration is not None:
149
            # Update attributes for part progress calculations
150
            duration = part_duration
151
            view_offset -= (part_duration * (part - 1))
152
153
        # Calculate progress (0 - 100)
154
        return round((float(view_offset) / duration) * 100, 2)
155