GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.
Passed
Push — master ( d62c21...90a13c )
by David
01:18
created

API.watched()   D

Complexity

Conditions 10

Size

Total Lines 59

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 0 Features 0
Metric Value
cc 10
c 4
b 0
f 0
dl 0
loc 59
rs 4.8648

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 API.watched() 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
#!/usr/bin/python
2
# -*- coding: UTF-8 -*-
3
4
import sys, os, time
5
#import urllib
6
#import request
7
import json
8
9
import xbmc
10
import interface
11
import httplib
12
13
__addon__ = interface.__addon__
14
def getstr(strid): return interface.getstr(strid)
15
16
REDIRECT_URI = "http://simkl.com"
17
USERFILE     = os.path.join(xbmc.translatePath(__addon__.getAddonInfo("profile")).decode("utf-8"), "simkl_key")
18
xbmc.translatePath("special://profile/simkl_key")
19
20
if not os.path.exists(USERFILE):
21
    os.mkdir(os.path.dirname(USERFILE))
22
    with open(USERFILE, "w+") as f:
23
        f.write("")
24
else:
25
    with open(USERFILE, "r") as f:
26
        xbmc.log("Simkl: Userfile " + str(f.read()))
27
28
APIFILE = os.path.join(os.path.dirname(os.path.realpath(__file__)).strip("lib"), "data", "apikey")
29
xbmc.log("Simkl: APIFILE: {0}".format(APIFILE))
30
with open(APIFILE, "r") as f:
31
    rd = f.read()
32
    d = json.loads(rd)
33
    APIKEY = d["apikey"]
34
    SECRET = d["secret"]
35
    xbmc.log("Simkl: {0}".format(rd))
36
    xbmc.log("Simkl: APIKEY: {0}".format(APIKEY))
37
ATOKEN = 0 #Get atoken from file
38
headers = {"Content-Type": "application-json",
39
    "simkl-api-key": APIKEY}
40
41
class API:
42
    def __init__(self):
43
        self.scrobbled_dict = {} #So it doesn't scrobble 5 times the same chapter
44
        #{"Label":expiration_time}
45
        with open(USERFILE, "r") as f:
46
            self.token = f.readline().strip("\n")
47
            headers["authorization"] = "Bearer " + self.token
48
        try:
49
            self.get_usersettings()
50
            self.internet = True
51
            #if not os.path.exists(USERFILE):
52
            #    api.login()
53
        except Exception:
54
            xbmc.log("Simkl: {0}".format("No INTERNET"))
55
            #interface.notify(getstr(32027))
56
            self.internet = False
57
58
    def get_usersettings(self):
59
        self.con = httplib.HTTPSConnection("api.simkl.com")
60
        self.con.request("GET", "/users/settings", headers=headers)
61
        self.USERSETTINGS = json.loads(self.con.getresponse().read().decode("utf-8"))
62
        xbmc.log("Simkl: Usersettings: " + str(self.USERSETTINGS))
63
64
    def login(self):
65
        url = "/oauth/pin?client_id="
66
        url += APIKEY + "&redirect=" + REDIRECT_URI
67
68
        log = httplib.HTTPSConnection("api.simkl.com")
69
        log.request("GET", url, headers=headers)
70
        r = log.getresponse().read().decode("utf-8")
71
        xbmc.log(r)
72
        rdic = json.loads(r)
73
        #interface.loginDialog(rdic["verification_url"],
74
        #  rdic["user_code"], self.check_login, log, rdic["expires_in"],
75
        #  rdic["interval"], self)
76
77
        pin = rdic["user_code"]
78
        url = rdic["verification_url"]
79
        exp = int(rdic["expires_in"])
80
        ntv = int(rdic["interval"])
81
82
        self.logindialog = interface.loginDialog("simkl-LoginDialog.xml",
83
            __addon__.getAddonInfo("path"), pin=pin, url=url,
84
            check_login=self.check_login, log=log, exp=exp, inter=ntv, api=self)
85
        self.logindialog.doModal()
86
        del self.logindialog
87
88
    def set_atoken(self, token):
89
        global ATOKEN
90
        with open(USERFILE, "w") as f:
91
            f.write(token)
92
        ATOKEN = token
93
        headers["authorization"] = "Bearer "+token
94
        self.token = token
95
96
    def check_login(self, ucode, log): #Log is the connection
97
        url = "/oauth/pin/" + ucode + "?client_id=" + APIKEY
98
        log.request("GET", url, headers=headers)
99
        r = json.loads(log.getresponse().read().decode("utf-8"))
100
        xbmc.log("Simkl:" + str(r))
101
        if r["result"] == "OK":
102
            self.set_atoken(r["access_token"])
103
            log.request("GET", "/users/settings", headers=headers)
104
            r = json.loads(log.getresponse().read().decode("utf-8"))
105
            self.USERSETTINGS = r
106
            return True
107
        elif r["result"] == "KO":
108
            return False
109
110
    def is_user_logged(self):
111
        """ Checks if user is logged in """
112
        failed = False
113
        if self.internet == False: return False
114
        if "error" in self.USERSETTINGS.keys(): failed = self.USERSETTINGS["error"]
115
        if self.token == "" or failed == "user_token_failed":
116
            xbmc.log("Simkl: User not logged in")
117
            interface.login(0)
118
            return False
119
        else:
120
            #interface.login(self.USERSETTINGS["user"]["name"])
121
            interface.login(1)
122
            return True
123
124
    ### SCROBBLING OR CHECKIN
125
    def lock(self, fname, duration):
126
        xbmc.log("Duration: %s" %duration)
127
        exp = self.scrobbled_dict
128
        exp[fname] = int(time.time() + (105 - float(__addon__.getSetting("scr-pct"))) / 100 * duration)
129
        xbmc.log("Simkl: Locking {0}".format(exp))
130
        self.scrobbled_dict = {fname:exp[fname]} #So there is always only one entry on the dict
131
132
    def is_locked(self, fname):
133
        exp = self.scrobbled_dict
134
        if not (fname in exp.keys()): return 0
135
        xbmc.log("Time: {0}, exp: {1}, Dif: {2}".format(int(time.time()), exp[fname], int(exp[fname]-time.time())))
136
        #When Dif reaches 0, scrobble.
137
        if time.time() < exp[fname]:
138
            xbmc.log("Simkl: Can't scrobble, file locked (alredy scrobbled)")
139
            xbmc.log(str(exp))
140
            return 1
141
        else:
142
            del exp[fname]
143
            return 0
144
145
    def watched(self, item, duration, date=time.strftime('%Y-%m-%d %H:%M:%S'), cnt=0): #OR IDMB, member: only works with movies
146
        filename = item["file"].replace("\\", "/")
147
        if self.is_user_logged() and not self.is_locked(filename):
148
            try:
149
                con = httplib.HTTPSConnection("api.simkl.com")
150
                mediadict = {"movie": "movies", "episode":"shows", "show":"shows"}
151
152
                if item["imdbnumber"] != "":
153
                    if item["type"] == "movie": toappend = {"ids":{"imdb": item["imdbnumber"]}, "watched_at":date}
154
                    elif item["type"] == "episode":
155
                        toappend = {"ids":{"tvdb":item["imdbnumber"]}, "watched_at":date,
156
                        "seasons":[{
157
                            "number":item["season"],
158
                            "episodes":[{"number":item["episode"]}]}]}
159
                    media = mediadict[item["type"]]
160
                else:
161
                    xbmc.log("Simkl: Filename - {0}".format(filename))
162
                    values = json.dumps({"file":filename})
163
                    xbmc.log("Simkl: Query: {0}".format(values))
164
                    con.request("GET", "/search/file/", body=values, headers=headers)
165
                    r1 = con.getresponse().read()#.decode("utf-8")
166
                    xbmc.log("Simkl: Response: {0}".format(r1))
167
                    r = json.loads(str(r1))
168
                    self.lastwatched = r
169
                    if r == []:
170
                        xbmc.log("Simkl: Couldn't scrobble: Null Response")
171
                        return 0
172
                    media = mediadict[r["type"]]
173
                    toappend = {"ids": r[r["type"]]["ids"], "watched_at":date}
174
175
                tosend = {}
176
                tosend[media] = []
177
                tosend[media].append(toappend)
178
                tosend = json.dumps(tosend)
179
180
                xbmc.log("Simkl: values {0}".format(tosend))
181
                con.request("GET", "/sync/history/", body=tosend, headers=headers)
182
                r = con.getresponse().read().decode("utf-8")
183
                xbmc.log("Simkl: {0}".format(r))
184
185
                success = max(json.loads(r)["added"].values())
186
                if success:
187
                    self.scrobbled_dict
188
                    self.lock(filename, duration)
189
                return success
190
191
            #except httplib.BadStatusLine:
192
            #    xbmc.log("Simkl: {0}".format("ERROR: httplib.BadStatusLine"))
193
            except:
194
                xbmc.log("Simkl: ERROR: SSLError, retrying?")
195
                interface.notify(getstr(32029).format(cnt+1))
196
                time.sleep(5)
197
                if cnt <= 3:
198
                    self.watched(item, duration, date, cnt=cnt+1)
199
                else: interface.notify(getstr(32027))
200
201
        else:
202
            xbmc.log("Simkl: Can't scrobble. User not logged in or file locked")
203
            return 0
204
205
    def check_connection(self, cnt=0):
206
        if cnt < 3:
207
            try:
208
                self.get_usersettings()
209
                self.internet = True
210
            except Exception:
211
                time.sleep(5)
212
                self.check_connection(cnt=cnt+1)
213
        else:
214
            self.internet = False
215
            interface.notify(getstr(32027))
216
217
api = API()
218
if __name__ == "__main__":
219
    if sys.argv[1] == "login":
220
        xbmc.log("Logging in", level=xbmc.LOGDEBUG)
221
        api.login()