Test Failed
Push — develop ( a80574...5ed66c )
by Dean
02:36
created

WebSocket.on_playing()   D

Complexity

Conditions 10

Size

Total Lines 51

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 110

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 51
ccs 0
cts 21
cp 0
rs 4.2352
cc 10
crap 110

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 WebSocket.on_playing() 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.helpers.variable import to_integer
2
from plugin.core.message import InterfaceMessages
3
from plugin.managers.action import ActionManager
0 ignored issues
show
Bug introduced by
The name action does not seem to exist in module plugin.managers.
Loading history...
Configuration introduced by
Unable to import 'plugin.managers.action' (invalid syntax (<string>, line 113))

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
4
from plugin.managers.session.base import UpdateSession
0 ignored issues
show
Bug introduced by
The name base does not seem to exist in module plugin.managers.session.
Loading history...
Configuration introduced by
Unable to import 'plugin.managers.session.base' (invalid syntax (<string>, line 67))

This can be caused by one of the following:

1. Missing Dependencies

This error could indicate a configuration issue of Pylint. Make sure that your libraries are available by adding the necessary commands.

# .scrutinizer.yml
before_commands:
    - sudo pip install abc # Python2
    - sudo pip3 install abc # Python3
Tip: We are currently not using virtualenv to run pylint, when installing your modules make sure to use the command for the correct version.

2. Missing __init__.py files

This error could also result from missing __init__.py files in your module folders. Make sure that you place one file in each sub-folder.

Loading history...
5
from plugin.managers.session.s_websocket import WSessionManager
6
from plugin.scrobbler.core.constants import IGNORED_EVENTS
7
from plugin.scrobbler.core.engine import SessionEngine
8
from plugin.scrobbler.methods.core.base import Base
9
10
from datetime import datetime, timedelta
11
from plex import Plex
12
from plex_activity import Activity
13
import logging
14
15
log = logging.getLogger(__name__)
16
17
18
class WebSocket(Base):
19
    name = 'websocket'
20
21
    def __init__(self):
22
        Activity.on('websocket.playing', self.on_playing)
23
24
        self.engine = SessionEngine()
25
26
    def on_playing(self, info):
27
        if InterfaceMessages.critical:
0 ignored issues
show
Bug introduced by
The Class InterfaceMessages does not seem to have a member named critical.

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...
28
            return
29
30
        # Create or retrieve existing session
31
        session = WSessionManager.get.or_create(info, fetch=True)
32
33
        # Validate session
34
        if session.updated_at is None or (datetime.utcnow() - session.updated_at) > timedelta(minutes=5):
35
            log.info('Updating session, last update was over 5 minutes ago')
36
            WSessionManager.update(session, info, fetch=True)
37
            return
38
39
        if session.duration is None or session.view_offset is None:
40
            # Update session
41
            WSessionManager.update(session, info, fetch=lambda s, i: (
42
                s.rating_key != to_integer(i.get('ratingKey')) or
43
                s.duration is None
44
            ))
45
            return
46
47
        # Parse `info` to events
48
        events = self.to_events(session, info)
49
50
        if not events:
51
            return
52
53
        # Check for changed media
54
        media_changed = session.rating_key != to_integer(info.get('ratingKey'))
55
56
        # Parse `events`
57
        actions = self.engine.process(session, events)
58
59
        for action, payload in actions:
60
            # Build request for the event
61
            request = self.build_request(
62
                session,
63
                part=payload.get('part', 1),
64
                rating_key=payload.get('rating_key'),
65
                view_offset=payload.get('view_offset')
66
            )
67
68
            if not request:
69
                log.info('No request returned for action %r (payload: %r)', action, payload)
70
                continue
71
72
            # Queue request to be sent
73
            ActionManager.queue('/'.join(['scrobble', action]), request, session)
74
75
        # Update session
76
        WSessionManager.update(session, info, fetch=media_changed)
77
78
    @classmethod
79
    def to_events(cls, session, info):
80
        # Validate `state`
81
        state = info.get('state')
82
83
        if not state:
84
            log.warn('Event has an invalid state %r', state)
85
            return []
86
87
        if state in IGNORED_EVENTS:
88
            log.debug('Ignored "%s" event: %r', state, info)
89
            return []
90
91
        # Check for session `view_offset` jump
92
        if cls.session_jumped(session, info.get('viewOffset')):
93
            return []
94
95
        # Retrieve event parameters
96
        view_offset = to_integer(info.get('viewOffset'))
97
98
        # Calculate current part number
99
        # TODO handle null values from session?
0 ignored issues
show
Coding Style introduced by
TODO and FIXME comments should generally be avoided.
Loading history...
100
        part, _ = UpdateSession.get_part(session.duration, view_offset, session.part_count)
101
102
        # Build event
103
        return [
104
            (state, {
105
                'part': part,
106
                'rating_key': to_integer(info.get('ratingKey')),
107
                'view_offset': view_offset
108
            })
109
        ]
110
111
    @classmethod
112
    def test(cls):
113
        if Plex['status'].sessions() is None:
114
            log.info("Error while retrieving sessions, assuming WebSocket method isn't available")
115
            return False
116
117
        detail = Plex.detail()
0 ignored issues
show
Bug introduced by
The Class Plex does not seem to have a member named detail.

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...
118
        if detail is None:
119
            log.info('Error while retrieving server info for testing')
120
            return False
121
122
        if not detail.multiuser:
123
            log.info("Server info indicates multi-user support isn't available, WebSocket method not available")
124
            return False
125
126
        return True
127