Passed
Push — develop ( 2798d2...d1b463 )
by Dean
02:48
created

Main   B

Complexity

Total Complexity 40

Size/Duplication

Total Lines 288
Duplicated Lines 0 %

Importance

Changes 6
Bugs 0 Features 0
Metric Value
wmc 40
c 6
b 0
f 0
dl 0
loc 288
rs 8.2608

12 Methods

Rating   Name   Duplication   Size   Complexity  
A __init__() 0 13 1
B run() 0 27 4
A start() 0 3 1
B init_plex() 0 34 3
A process_server_state() 0 17 4
A on_starting_plugins() 0 5 1
B on_trakt_refresh() 0 47 6
A init_trakt() 0 21 1
A init() 0 11 3
A on_trakt_refresh_rejected() 0 23 2
F update_proxies() 0 62 13
A on_configuration_changed() 0 7 1

How to fix   Complexity   

Complex Class

Complex classes like Main 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 core.header import Header
0 ignored issues
show
Bug introduced by
The name header does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.header could not be resolved.

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...
2
from core.helpers import get_class_name, spawn
0 ignored issues
show
Bug introduced by
The name helpers does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.helpers could not be resolved.

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...
3
from core.logger import Logger
0 ignored issues
show
Bug introduced by
The name logger does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.logger could not be resolved.

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 core.update_checker import UpdateChecker
0 ignored issues
show
Bug introduced by
The name update_checker does not seem to exist in module core.
Loading history...
Configuration introduced by
The import core.update_checker could not be resolved.

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
6
from plugin.core.constants import ACTIVITY_MODE, PLUGIN_VERSION
0 ignored issues
show
Configuration introduced by
The import plugin.core.constants could not be resolved.

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...
7
from plugin.core.helpers.thread import module_start
0 ignored issues
show
Configuration introduced by
The import plugin.core.helpers.thread could not be resolved.

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...
8
from plugin.core.logger import LOG_HANDLER, LoggerManager
0 ignored issues
show
Configuration introduced by
The import plugin.core.logger could not be resolved.

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...
9
from plugin.managers.account import TraktAccountManager
0 ignored issues
show
Configuration introduced by
The import plugin.managers.account could not be resolved.

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...
10
from plugin.managers.m_trakt.credential import TraktOAuthCredentialManager
0 ignored issues
show
Configuration introduced by
The import plugin.managers.m_trakt.credential could not be resolved.

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...
11
from plugin.models import TraktAccount
0 ignored issues
show
Configuration introduced by
The import plugin.models could not be resolved.

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...
12
from plugin.modules.core.manager import ModuleManager
0 ignored issues
show
Configuration introduced by
The import plugin.modules.core.manager could not be resolved.

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...
13
from plugin.preferences import Preferences
0 ignored issues
show
Configuration introduced by
The import plugin.preferences could not be resolved.

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...
14
from plugin.scrobbler.core.session_prefix import SessionPrefix
0 ignored issues
show
Configuration introduced by
The import plugin.scrobbler.core.session_prefix could not be resolved.

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...
15
16
from plex import Plex
0 ignored issues
show
Configuration introduced by
The import plex could not be resolved.

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...
17
from plex_activity import Activity
0 ignored issues
show
Configuration introduced by
The import plex_activity could not be resolved.

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...
18
from plex_metadata import Metadata
0 ignored issues
show
Configuration introduced by
The import plex_metadata could not be resolved.

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...
19
from six.moves.urllib.parse import quote_plus, urlsplit, urlunsplit
0 ignored issues
show
Configuration introduced by
The import six.moves.urllib.parse could not be resolved.

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...
20
from requests.packages.urllib3.util import Retry
0 ignored issues
show
Bug introduced by
The name packages does not seem to exist in module requests.
Loading history...
Configuration introduced by
The import requests.packages.urllib3.util could not be resolved.

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...
21
from trakt import Trakt
0 ignored issues
show
Configuration introduced by
The import trakt could not be resolved.

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...
22
import os
23
import uuid
24
25
log = Logger()
26
27
28
class Main(object):
29
    modules = [
30
        # core
31
        UpdateChecker()
32
    ]
33
34
    def __init__(self):
35
        Header.show(self)
36
37
        # Initial configuration update
38
        self.on_configuration_changed()
39
40
        # Initialize clients
41
        self.init_trakt()
42
        self.init_plex()
43
        self.init()
44
45
        # Initialize modules
46
        ModuleManager.initialize()
47
48
    def init(self):
49
        names = []
50
51
        # Initialize modules
52
        for module in self.modules:
53
            names.append(get_class_name(module))
54
55
            if hasattr(module, 'initialize'):
56
                module.initialize()
57
58
        log.info('Initialized %s modules: %s', len(names), ', '.join(names))
59
60
    @staticmethod
61
    def init_plex():
62
        # Ensure client identifier has been generated
63
        if not Dict['plex.client.identifier']:
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Dict'
Loading history...
64
            # Generate identifier
65
            Dict['plex.client.identifier'] = uuid.uuid4()
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Dict'
Loading history...
66
67
        # Retrieve current client identifier
68
        client_id = Dict['plex.client.identifier']
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Dict'
Loading history...
69
70
        if isinstance(client_id, uuid.UUID):
71
            client_id = str(client_id)
72
73
        # plex.py
74
        Plex.configuration.defaults.authentication(
75
            os.environ.get('PLEXTOKEN')
76
        )
77
78
        Plex.configuration.defaults.client(
79
            identifier=client_id,
80
81
            product='trakt (for Plex)',
82
            version=PLUGIN_VERSION
83
        )
84
85
        # plex.activity.py
86
        path = os.path.join(LOG_HANDLER.baseFilename, '..', '..', 'Plex Media Server.log')
87
        path = os.path.abspath(path)
88
89
        Activity['logging'].add_hint(path)
90
91
        # plex.metadata.py
92
        Metadata.configure(
93
            client=Plex.client
94
        )
95
96
    @classmethod
97
    def init_trakt(cls):
98
        # Client
99
        Trakt.configuration.defaults.client(
100
            id='c9ccd3684988a7862a8542ae0000535e0fbd2d1c0ca35583af7ea4e784650a61',
101
            secret='bf00575b1ad252b514f14b2c6171fe650d474091daad5eb6fa890ef24d581f65'
102
        )
103
104
        # Application
105
        Trakt.configuration.defaults.app(
106
            name='trakt (for Plex)',
107
            version=PLUGIN_VERSION
108
        )
109
110
        # Setup request retrying
111
        Trakt.http.adapter_kwargs = {'max_retries': Retry(total=3, read=0)}
112
        Trakt.http.rebuild()
113
114
        # Bind to events
115
        Trakt.on('oauth.refresh', cls.on_trakt_refresh)
116
        Trakt.on('oauth.refresh.rejected', cls.on_trakt_refresh_rejected)
117
118
    @classmethod
119
    def on_trakt_refresh(cls, username, authorization):
120
        log.debug('[Trakt.tv] Token has been refreshed for %r', username)
121
122
        # Retrieve trakt account matching this `authorization`
123
        with Trakt.configuration.http(retry=True).oauth(token=authorization.get('access_token')):
124
            settings = Trakt['users/settings'].get(validate_token=False)
125
126
        if not settings:
127
            log.warn('[Trakt.tv] Unable to retrieve account details for token')
128
            return False
129
130
        # Retrieve trakt account username from `settings`
131
        s_username = settings.get('user', {}).get('username')
132
133
        if not s_username:
134
            log.warn('[Trakt.tv] Unable to retrieve username for token')
135
            return False
136
137
        if s_username != username:
138
            log.warn('[Trakt.tv] Token mismatch (%r != %r)', s_username, username)
139
            return False
140
141
        # Find matching trakt account
142
        trakt_account = (TraktAccount
143
            .select()
144
            .where(
145
                TraktAccount.username == username
146
            )
147
        ).first()
148
149
        if not trakt_account:
150
            log.warn('[Trakt.tv] Unable to find account with the username: %r', username)
151
            return False
152
153
        # Update OAuth credential
154
        TraktAccountManager.update.from_dict(
155
            trakt_account, {
156
                'authorization': {
157
                    'oauth': authorization
158
                }
159
            },
160
            settings=settings
161
        )
162
163
        log.info('[Trakt.tv] Token updated for %r', trakt_account)
164
        return True
165
166
    @classmethod
167
    def on_trakt_refresh_rejected(cls, username):
168
        log.debug('[Trakt.tv] Token refresh for %r has been rejected', username)
169
170
        # Find matching trakt account
171
        account = (TraktAccount
172
            .select()
173
            .where(
174
                TraktAccount.username == username
175
            )
176
        ).first()
177
178
        if not account:
179
            log.warn('[Trakt.tv] Unable to find account with the username: %r', username)
180
            return False
181
182
        # Delete OAuth credential
183
        TraktOAuthCredentialManager.delete(
184
            account=account.id
185
        )
186
187
        log.info('[Trakt.tv] Token cleared for %r', account)
188
        return True
189
190
    def start(self):
191
        # Construct main thread
192
        spawn(self.run, daemon=True, thread_name='main')
193
194
    def run(self):
195
        # Check for authentication token
196
        log.info('X-Plex-Token: %s', 'available' if os.environ.get('PLEXTOKEN') else 'unavailable')
197
198
        # Process server startup state
199
        self.process_server_state()
200
201
        # Start new-style modules
202
        module_start()
203
204
        # Start modules
205
        names = []
206
207
        for module in self.modules:
208
            if not hasattr(module, 'start'):
209
                continue
210
211
            names.append(get_class_name(module))
212
213
            module.start()
214
215
        log.info('Started %s modules: %s', len(names), ', '.join(names))
216
217
        ModuleManager.start()
218
219
        # Start plex.activity.py
220
        Activity.start(ACTIVITY_MODE.get(Preferences.get('activity.mode')))
221
222
    @classmethod
223
    def process_server_state(cls):
224
        # Check startup state
225
        server = Plex.detail()
226
227
        if server is None:
228
            log.info('Unable to check startup state, detail request failed')
229
            return
230
231
        # Check server startup state
232
        if server.start_state is None:
233
            return
234
235
        if server.start_state == 'startingPlugins':
236
            return cls.on_starting_plugins()
237
238
        log.error('Unhandled server start state %r', server.start_state)
239
240
    @staticmethod
241
    def on_starting_plugins():
242
        log.debug('on_starting_plugins')
243
244
        SessionPrefix.increment()
245
246
    @classmethod
247
    def on_configuration_changed(cls):
248
        # Update proxies (for requests)
249
        cls.update_proxies()
250
251
        # Refresh loggers
252
        LoggerManager.refresh()
253
254
    @staticmethod
255
    def update_proxies():
256
        # Retrieve proxy host
257
        host = Prefs['proxy_host']
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Prefs'
Loading history...
258
259
        if not host:
260
            if not Trakt.http.proxies and not os.environ.get('HTTP_PROXY') and not os.environ.get('HTTPS_PROXY'):
261
                return
262
263
            # Update trakt client
264
            Trakt.http.proxies = {}
265
266
            # Update environment variables
267
            if 'HTTP_PROXY' in os.environ:
268
                del os.environ['HTTP_PROXY']
269
270
            if 'HTTPS_PROXY' in os.environ:
271
                del os.environ['HTTPS_PROXY']
272
273
            log.info('HTTP Proxy has been disabled')
274
            return
275
276
        # Parse URL
277
        host_parsed = urlsplit(host)
278
279
        # Expand components
280
        scheme, netloc, path, query, fragment = host_parsed
281
282
        if not scheme:
283
            scheme = 'http'
284
285
        # Retrieve proxy credentials
286
        username = Prefs['proxy_username']
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Prefs'
Loading history...
287
        password = Prefs['proxy_password']
0 ignored issues
show
Comprehensibility Best Practice introduced by
Undefined variable 'Prefs'
Loading history...
288
289
        # Build URL
290
        if username and password and '@' not in netloc:
291
            netloc = '%s:%s@%s' % (
292
                quote_plus(username),
293
                quote_plus(password),
294
                netloc
295
            )
296
297
        url = urlunsplit((scheme, netloc, path, query, fragment))
298
299
        # Update trakt client
300
        Trakt.http.proxies = {
301
            'http': url,
302
            'https': url
303
        }
304
305
        # Update environment variables
306
        os.environ.update({
307
            'HTTP_PROXY': url,
308
            'HTTPS_PROXY': url
309
        })
310
311
        # Display message in log file
312
        if not host_parsed.username and not host_parsed.password:
313
            log.info('HTTP Proxy has been enabled (host: %r)', host)
314
        else:
315
            log.info('HTTP Proxy has been enabled (host: <sensitive>)')
316