1
|
|
|
#!/usr/bin/python |
2
|
|
|
# -*- coding: UTF-8 -*- |
3
|
|
|
|
4
|
|
|
import xbmc |
5
|
|
|
import interface |
6
|
|
|
import json |
7
|
|
|
__addon__ = interface.__addon__ |
8
|
|
|
def getstr(strid): return interface.getstr(strid) |
9
|
|
|
|
10
|
|
|
class Engine: |
11
|
|
|
def __init__(self, api, player): |
12
|
|
|
self.api = api |
13
|
|
|
self.player = player |
14
|
|
|
player.engine = self |
15
|
|
|
player.api = api |
16
|
|
|
|
17
|
|
|
def synclibrary(self, mode="quick"): |
18
|
|
|
""" |
19
|
|
|
Fetches the library from Simkl to Kodi |
20
|
|
|
Mode can be "quick" or "full" |
21
|
|
|
""" |
22
|
|
|
xbmc.log("Simkl: Syncing library (Simkl to Kodi)") |
23
|
|
|
|
24
|
|
|
mode = "full" |
25
|
|
|
|
26
|
|
|
if mode == "full": |
27
|
|
|
todump = { |
28
|
|
|
"jsonrpc": "2.0", |
29
|
|
|
"method": "VideoLibrary.GetMovies", |
30
|
|
|
"params": { |
31
|
|
|
"limits": { |
32
|
|
|
"start": 0, |
33
|
|
|
"end": 1000 |
34
|
|
|
}, |
35
|
|
|
"properties": [ |
36
|
|
|
"playcount", |
37
|
|
|
"imdbnumber", |
38
|
|
|
"file", |
39
|
|
|
"lastplayed", |
40
|
|
|
"year" |
41
|
|
|
], |
42
|
|
|
"sort": { |
43
|
|
|
"order": "ascending", |
44
|
|
|
"method": "playcount", |
45
|
|
|
#"ignorearticle": True |
46
|
|
|
} |
47
|
|
|
}, |
48
|
|
|
"id": "libMovies" |
49
|
|
|
} |
50
|
|
|
kodilibrary = json.loads(xbmc.executeJSONRPC(json.dumps(todump))) |
51
|
|
|
if kodilibrary["result"]["limits"]["total"] > 0: |
52
|
|
|
xbmc.log(str(kodilibrary)) |
53
|
|
|
progress = interface.SyncProgress("movies", "full") |
54
|
|
|
each = float(100) / kodilibrary["result"]["limits"]["total"] |
55
|
|
|
for movie in kodilibrary["result"]["movies"]: |
56
|
|
|
progress.push(each, "{0} ({1})".format(movie["label"], movie["year"])) |
57
|
|
|
if movie["playcount"] == 0: |
58
|
|
|
### DOWNLOAD FROM KODI |
59
|
|
|
#Separate big list in chunks |
60
|
|
|
movie["media"] = "movie" |
61
|
|
|
if self.api.check_if_watched(movie): |
62
|
|
|
xbmc.log("Simkl: {0}".format(movie)) |
63
|
|
|
ret = xbmc.executeJSONRPC(json.dumps({ |
64
|
|
|
"jsonrpc": "2.0", |
65
|
|
|
"method": "VideoLibrary.SetMovieDetails", |
66
|
|
|
"params": { |
67
|
|
|
"playcount": 1, |
68
|
|
|
#"lastplayed":"", |
69
|
|
|
"movieid":movie["movieid"] |
70
|
|
|
} |
71
|
|
|
})) |
72
|
|
|
#xbmc.log(ret) |
73
|
|
|
del progress |
74
|
|
|
|
75
|
|
|
todump["method"] = "VideoLibrary.GetTVShows" |
76
|
|
|
todump["params"]["properties"] = ["imdbnumber", "title", "watchedepisodes"] |
77
|
|
|
#If watchedepisodes > 0 |
78
|
|
|
kodilibrary = xbmc.executeJSONRPC(json.dumps(todump)) |
79
|
|
|
kodilibrary = json.loads(kodilibrary) |
80
|
|
|
|
81
|
|
|
if kodilibrary["result"]["limits"]["total"] > 0: |
82
|
|
|
progress = interface.SyncProgress("TV Shows", "full") |
83
|
|
|
each = float(100) / kodilibrary["result"]["limits"]["total"] |
84
|
|
|
debug_cnt = 0 |
85
|
|
|
for tvshow in kodilibrary["result"]["tvshows"]: |
86
|
|
|
#if debug_cnt >= 10: break #I have a lot of TV Shows, only for testing |
87
|
|
|
progress.push(each, tvshow["label"]) |
88
|
|
|
debug_cnt += 1 |
89
|
|
|
|
90
|
|
|
|
91
|
|
|
todump["method"] = "VideoLibrary.GetSeasons" |
92
|
|
|
#todump["params"]["Library.Id"] = tvshow["tvshowid"] |
93
|
|
|
todump["id"] = tvshow["tvshowid"] |
94
|
|
|
todump["params"]["properties"] = ["season", "episode", "watchedepisodes", "showtitle"] |
95
|
|
|
seasons = xbmc.executeJSONRPC(json.dumps(todump)) |
96
|
|
|
xbmc.log(json.dumps(tvshow)) |
97
|
|
|
xbmc.log(seasons) |
98
|
|
|
seasons = json.loads(seasons) |
99
|
|
|
|
100
|
|
|
|
101
|
|
|
for season in seasons["result"]["seasons"]: |
102
|
|
|
values = [] |
103
|
|
|
|
104
|
|
|
todump["method"] = "VideoLibrary.GetEpisodes" |
105
|
|
|
todump["params"]["tvshowid"] = tvshow["tvshowid"] |
106
|
|
|
todump["params"]["season"] = season["season"] |
107
|
|
|
todump["params"]["properties"] = ["title", "rating", "playcount", |
108
|
|
|
"season", "episode", "showtitle", "lastplayed", "tvshowid"] |
109
|
|
|
|
110
|
|
|
episodes = xbmc.executeJSONRPC(json.dumps(todump)) |
111
|
|
|
xbmc.log(episodes) |
112
|
|
|
episodes = json.loads(episodes) |
113
|
|
|
|
114
|
|
|
if episodes["result"]["limits"]["total"] > 0: |
115
|
|
|
for episode in episodes["result"]["episodes"]: |
116
|
|
|
values.append({ |
117
|
|
|
"type": "tv", |
118
|
|
|
"season": episode["season"], |
119
|
|
|
"episode": episode["episode"], |
120
|
|
|
"title": episode["showtitle"], |
121
|
|
|
"tvdb": tvshow["imdbnumber"] |
122
|
|
|
}) |
123
|
|
|
|
124
|
|
|
watched = self.api.check_if_watched(values, False) |
125
|
|
|
xbmc.log(json.dumps(watched)) |
126
|
|
|
|
127
|
|
|
for i, episode in enumerate(episodes["result"]["episodes"]): |
128
|
|
|
toupdate = { |
129
|
|
|
"jsonrpc": "2.0", |
130
|
|
|
"method": "VideoLibrary.SetEpisodeDetails", |
131
|
|
|
"params": { |
132
|
|
|
"episodeid":episode["episodeid"], |
133
|
|
|
"playcount": int(watched[i]["result"]), |
134
|
|
|
}, |
135
|
|
|
"id": "libMovies" |
136
|
|
|
} |
137
|
|
|
try: |
138
|
|
|
toupdate["params"]["lastplayed"] = watched[i]["last_watched"] |
139
|
|
|
except KeyError: |
140
|
|
|
toupdate["params"]["lastplayed"] = "" |
141
|
|
|
|
142
|
|
|
info = xbmc.executeJSONRPC(json.dumps(toupdate)) |
143
|
|
|
xbmc.log("Simkl: Info: {0}".format(info)) |
144
|
|
|
|
145
|
|
|
del todump["params"]["tvshowid"] |
146
|
|
|
del todump["params"]["season"] |
147
|
|
|
del progress |
148
|
|
|
|
149
|
|
|
xbmc.log("Simkl: Finished syncing library") |
150
|
|
|
interface.notify("Finished syncing library") |
151
|
|
|
|
152
|
|
|
|
153
|
|
|
class Player(xbmc.Player): |
154
|
|
|
""" Replaces the Kodi player class """ |
155
|
|
|
def __init__(self): |
156
|
|
|
xbmc.Player.__init__(self) |
157
|
|
|
|
158
|
|
|
@staticmethod |
159
|
|
|
def getMediaType(): |
160
|
|
|
""" Returns the MediaType of the file currently playing """ |
161
|
|
|
if xbmc.getCondVisibility('Container.Content(tvshows)'): |
162
|
|
|
return "show" |
163
|
|
|
elif xbmc.getCondVisibility('Container.Content(seasons)'): |
164
|
|
|
return "season" |
165
|
|
|
elif xbmc.getCondVisibility('Container.Content(episodes)'): |
166
|
|
|
return "episode" |
167
|
|
|
elif xbmc.getCondVisibility('Container.Content(movies)'): |
168
|
|
|
return "movie" |
169
|
|
|
else: |
170
|
|
|
return None |
171
|
|
|
|
172
|
|
|
def onPlayBackStarted(self): |
173
|
|
|
""" Activated at start """ |
174
|
|
|
#self.onPlayBackStopped() |
175
|
|
|
pass |
176
|
|
|
def onPlayBackSeek(self, *args): |
177
|
|
|
""" Activated on seek """ |
178
|
|
|
self.onPlayBackStopped() |
179
|
|
|
def onPlayBackResumed(self): |
180
|
|
|
""" Activated on resume """ |
181
|
|
|
self.onPlayBackStopped() |
182
|
|
|
def onPlayBackEnded(self): |
183
|
|
|
""" Activated at end """ |
184
|
|
|
xbmc.log("Simkl: ONPLAYBACKENDED") |
185
|
|
|
self.onPlayBackStopped() |
186
|
|
|
|
187
|
|
|
def onPlayBackStopped(self): |
188
|
|
|
""" Gets the info needed to pass to the api """ |
189
|
|
|
try: |
190
|
|
|
movie = self.getVideoInfoTag() |
191
|
|
|
thing = xbmc.executeJSONRPC(json.dumps({ |
192
|
|
|
"jsonrpc": "2.0", |
193
|
|
|
"method": "Player.GetItem", |
194
|
|
|
"params": { |
195
|
|
|
"properties": [ "showtitle", "title", "season", "episode", "file", "imdbnumber", "genre" ], |
196
|
|
|
"playerid": 1 }, |
197
|
|
|
"id": "VideoGetItem" |
198
|
|
|
})) |
199
|
|
|
xbmc.log("Simkl: Full: {0}".format(thing)) |
200
|
|
|
item = json.loads(thing)["result"]["item"] |
201
|
|
|
#imdb = movie.getIMDBNumber().strip(" ") |
202
|
|
|
#fname = self.getPlayingFile() |
203
|
|
|
imdb = item["imdbnumber"] |
204
|
|
|
fname = item["file"] |
205
|
|
|
media = item["type"] |
206
|
|
|
xbmc.log("Simkl: IMDb: {0}".format(imdb)) |
207
|
|
|
xbmc.log("Simkl: Genre: {0}".format(item["genre"])) |
208
|
|
|
xbmc.log("Simkl: MediaType: " + str(media)) |
209
|
|
|
|
210
|
|
|
percentage = 100 * self.getTime() / self.getTotalTime() |
211
|
|
|
pctconfig = int(self.addon.getSetting("scr-pct")) |
212
|
|
|
|
213
|
|
|
if 99 > percentage > pctconfig: |
214
|
|
|
bubble = __addon__.getSetting("bubble") |
215
|
|
|
xbmc.log("Simkl: Bubble == {0}".format(bubble)) |
216
|
|
|
xbmc.log("Percentage: {0}, pctconfig {1}".format(percentage, pctconfig)) |
217
|
|
|
|
218
|
|
|
xbmc.log("Simkl: Ready to scrobble {0}".format(movie.getTitle())) |
219
|
|
|
if imdb == "": |
220
|
|
|
#if True: |
221
|
|
|
xbmc.log("Simkl: No imdb - Fname: {0}".format(fname)) |
222
|
|
|
r = self.api.watched(fname, media, self.getTotalTime()) |
223
|
|
|
else: |
224
|
|
|
xbmc.log("Simkl: IMDB: " + str(imdb)) |
225
|
|
|
r = self.api.watched(imdb, media, self.getTotalTime()) |
226
|
|
|
|
227
|
|
|
if bubble=="true" and r: |
228
|
|
|
if item["label"] in item["file"]: |
229
|
|
|
#if True: #For testing purposes |
230
|
|
|
xbmc.log("Simkl: Label and file are the same") |
231
|
|
|
lstw = self.api.lastwatched |
232
|
|
|
if lstw["type"] == "episode": |
233
|
|
|
item["showtitle"] = lstw["show"]["title"] |
234
|
|
|
item["season"] = lstw["episode"]["season"] |
235
|
|
|
item["episode"] = lstw["episode"]["episode"] |
236
|
|
|
elif lstw["type"] == "movie": |
237
|
|
|
item["title"] = "".join([lstw["movie"]["title"], " (", str(lstw["movie"]["year"]), ")"]) |
238
|
|
|
media = lstw["type"] |
239
|
|
|
|
240
|
|
|
txt = item["label"] |
241
|
|
|
title = "" |
242
|
|
|
if media == "movie": |
243
|
|
|
txt = item["title"] |
244
|
|
|
elif media == "episode": |
245
|
|
|
txt = item["showtitle"] |
246
|
|
|
title = "- S{:02}E{:02}".format(item["season"], item["episode"]) |
247
|
|
|
xbmc.log("Simkl: " + "; ".join([media, txt, title])) |
248
|
|
|
interface.notify(getstr(32028).format(title), title=txt) |
249
|
|
|
r = 0 |
250
|
|
|
|
251
|
|
|
except RuntimeError: |
252
|
|
|
pass |
253
|
|
|
except ZeroDivisionError: |
254
|
|
|
self.onPlayBackStopped() |
255
|
|
|
|