commit
bec455e8f7
24 changed files with 12471 additions and 12835 deletions
|
@ -143,7 +143,7 @@ if __name__ == '__main__':
|
|||
doUtils = downloadutils.DownloadUtils()
|
||||
url = "{server}/emby/Items/%s?format=json" % embyid
|
||||
logMsg("Deleting request: %s" % embyid, 0)
|
||||
doUtils.downloadUrl(url, type="DELETE")
|
||||
doUtils.downloadUrl(url, action_type="DELETE")
|
||||
|
||||
'''if utils.settings('skipContextMenu') != "true":
|
||||
if xbmcgui.Dialog().yesno(
|
||||
|
@ -152,8 +152,7 @@ if __name__ == '__main__':
|
|||
"also delete the file(s) from disk!")):
|
||||
import downloadutils
|
||||
doUtils = downloadutils.DownloadUtils()
|
||||
url = "{server}/emby/Items/%s?format=json" % embyid
|
||||
doUtils.downloadUrl(url, type="DELETE")'''
|
||||
doUtils.downloadUrl("{server}/emby/Items/%s?format=json" % embyid, action_type="DELETE")'''
|
||||
|
||||
xbmc.sleep(500)
|
||||
xbmc.executebuiltin("Container.Update")
|
|
@ -323,7 +323,7 @@
|
|||
<string id="33020">Gathering tv shows from:</string>
|
||||
<string id="33021">Gathering:</string>
|
||||
<string id="33022">Detected the database needs to be recreated for this version of Emby for Kodi. Proceed?</string>
|
||||
<string id="33023">Emby for Kod may not work correctly until the database is reset.</string>
|
||||
<string id="33023">Emby for Kodi may not work correctly until the database is reset.</string>
|
||||
<string id="33024">Cancelling the database syncing process. The current Kodi version is unsupported.</string>
|
||||
<string id="33025">completed in:</string>
|
||||
<string id="33026">Comparing movies from:</string>
|
||||
|
|
|
@ -116,17 +116,16 @@ class API():
|
|||
}
|
||||
|
||||
def getMediaStreams(self):
|
||||
item = self.item
|
||||
videotracks = []
|
||||
audiotracks = []
|
||||
subtitlelanguages = []
|
||||
|
||||
try:
|
||||
media_streams = item['MediaSources'][0]['MediaStreams']
|
||||
media_streams = self.item['MediaSources'][0]['MediaStreams']
|
||||
|
||||
except KeyError:
|
||||
if not item.get("MediaStreams"): return None
|
||||
media_streams = item['MediaStreams']
|
||||
if not self.item.get("MediaStreams"): return None
|
||||
media_streams = self.item['MediaStreams']
|
||||
|
||||
for media_stream in media_streams:
|
||||
# Sort through Video, Audio, Subtitle
|
||||
|
@ -141,12 +140,12 @@ class API():
|
|||
'codec': codec,
|
||||
'height': media_stream.get('Height'),
|
||||
'width': media_stream.get('Width'),
|
||||
'video3DFormat': item.get('Video3DFormat'),
|
||||
'video3DFormat': self.item.get('Video3DFormat'),
|
||||
'aspect': 1.85
|
||||
}
|
||||
|
||||
try:
|
||||
container = item['MediaSources'][0]['Container'].lower()
|
||||
container = self.item['MediaSources'][0]['Container'].lower()
|
||||
except:
|
||||
container = ""
|
||||
|
||||
|
@ -161,9 +160,9 @@ class API():
|
|||
track['codec'] = "avc1"
|
||||
|
||||
# Aspect ratio
|
||||
if item.get('AspectRatio'):
|
||||
if self.item.get('AspectRatio'):
|
||||
# Metadata AR
|
||||
aspect = item['AspectRatio']
|
||||
aspect = self.item['AspectRatio']
|
||||
else: # File AR
|
||||
aspect = media_stream.get('AspectRatio', "0")
|
||||
|
||||
|
@ -180,8 +179,8 @@ class API():
|
|||
else:
|
||||
track['aspect'] = 1.85
|
||||
|
||||
if item.get("RunTimeTicks"):
|
||||
track['duration'] = item.get("RunTimeTicks") / 10000000.0
|
||||
if self.item.get("RunTimeTicks"):
|
||||
track['duration'] = self.item.get("RunTimeTicks") / 10000000.0
|
||||
|
||||
videotracks.append(track)
|
||||
|
||||
|
@ -211,12 +210,11 @@ class API():
|
|||
}
|
||||
|
||||
def getRuntime(self):
|
||||
item = self.item
|
||||
try:
|
||||
runtime = item['RunTimeTicks'] / 10000000.0
|
||||
runtime = self.item['RunTimeTicks'] / 10000000.0
|
||||
|
||||
except KeyError:
|
||||
runtime = item.get('CumulativeRunTimeTicks', 0) / 10000000.0
|
||||
runtime = self.item.get('CumulativeRunTimeTicks', 0) / 10000000.0
|
||||
|
||||
return runtime
|
||||
|
||||
|
@ -234,15 +232,14 @@ class API():
|
|||
|
||||
def getStudios(self):
|
||||
# Process Studios
|
||||
item = self.item
|
||||
studios = []
|
||||
|
||||
try:
|
||||
studio = item['SeriesStudio']
|
||||
studio = self.item['SeriesStudio']
|
||||
studios.append(self.verifyStudio(studio))
|
||||
|
||||
except KeyError:
|
||||
studioList = item['Studios']
|
||||
studioList = self.item['Studios']
|
||||
for studio in studioList:
|
||||
|
||||
name = studio['Name']
|
||||
|
@ -265,12 +262,11 @@ class API():
|
|||
|
||||
def getChecksum(self):
|
||||
# Use the etags checksum and userdata
|
||||
item = self.item
|
||||
userdata = item['UserData']
|
||||
userdata = self.item['UserData']
|
||||
|
||||
checksum = "%s%s%s%s%s%s%s" % (
|
||||
|
||||
item['Etag'],
|
||||
self.item['Etag'],
|
||||
userdata['Played'],
|
||||
userdata['IsFavorite'],
|
||||
userdata.get('Likes',''),
|
||||
|
@ -282,9 +278,8 @@ class API():
|
|||
return checksum
|
||||
|
||||
def getGenres(self):
|
||||
item = self.item
|
||||
all_genres = ""
|
||||
genres = item.get('Genres', item.get('SeriesGenres'))
|
||||
genres = self.item.get('Genres', self.item.get('SeriesGenres'))
|
||||
|
||||
if genres:
|
||||
all_genres = " / ".join(genres)
|
||||
|
@ -362,9 +357,8 @@ class API():
|
|||
|
||||
def getFilePath(self):
|
||||
|
||||
item = self.item
|
||||
try:
|
||||
filepath = item['Path']
|
||||
filepath = self.item['Path']
|
||||
|
||||
except KeyError:
|
||||
filepath = ""
|
||||
|
@ -375,8 +369,8 @@ class API():
|
|||
filepath = filepath.replace("\\\\", "smb://")
|
||||
filepath = filepath.replace("\\", "/")
|
||||
|
||||
if item.get('VideoType'):
|
||||
videotype = item['VideoType']
|
||||
if self.item.get('VideoType'):
|
||||
videotype = self.item['VideoType']
|
||||
# Specific format modification
|
||||
if 'Dvd'in videotype:
|
||||
filepath = "%s/VIDEO_TS/VIDEO_TS.IFO" % filepath
|
||||
|
@ -388,4 +382,3 @@ class API():
|
|||
filepath = filepath.replace("/", "\\")
|
||||
|
||||
return filepath
|
||||
|
|
@ -35,7 +35,7 @@ class Artwork():
|
|||
|
||||
self.enableTextureCache = utils.settings('enableTextureCache') == "true"
|
||||
self.imageCacheLimitThreads = int(utils.settings("imageCacheLimit"))
|
||||
self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5);
|
||||
self.imageCacheLimitThreads = int(self.imageCacheLimitThreads * 5)
|
||||
utils.logMsg("Using Image Cache Thread Count: " + str(self.imageCacheLimitThreads), 1)
|
||||
|
||||
if not self.xbmc_port and self.enableTextureCache:
|
||||
|
@ -509,8 +509,6 @@ class Artwork():
|
|||
|
||||
def getAllArtwork(self, item, parentInfo=False):
|
||||
|
||||
server = self.server
|
||||
|
||||
itemid = item['Id']
|
||||
artworks = item['ImageTags']
|
||||
backdrops = item.get('BackdropImageTags',[])
|
||||
|
@ -541,7 +539,7 @@ class Artwork():
|
|||
artwork = (
|
||||
"%s/emby/Items/%s/Images/Backdrop/%s?"
|
||||
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
|
||||
% (server, itemid, index, maxWidth, maxHeight, tag, customquery))
|
||||
% (self.server, itemid, index, maxWidth, maxHeight, tag, customquery))
|
||||
allartworks['Backdrop'].append(artwork)
|
||||
|
||||
# Process the rest of the artwork
|
||||
|
@ -552,7 +550,7 @@ class Artwork():
|
|||
artwork = (
|
||||
"%s/emby/Items/%s/Images/%s/0?"
|
||||
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
|
||||
% (server, itemid, art, maxWidth, maxHeight, tag, customquery))
|
||||
% (self.server, itemid, art, maxWidth, maxHeight, tag, customquery))
|
||||
allartworks[art] = artwork
|
||||
|
||||
# Process parent items if the main item is missing artwork
|
||||
|
@ -570,7 +568,7 @@ class Artwork():
|
|||
artwork = (
|
||||
"%s/emby/Items/%s/Images/Backdrop/%s?"
|
||||
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
|
||||
% (server, parentId, index, maxWidth, maxHeight, tag, customquery))
|
||||
% (self.server, parentId, index, maxWidth, maxHeight, tag, customquery))
|
||||
allartworks['Backdrop'].append(artwork)
|
||||
|
||||
# Process the rest of the artwork
|
||||
|
@ -586,7 +584,7 @@ class Artwork():
|
|||
artwork = (
|
||||
"%s/emby/Items/%s/Images/%s/0?"
|
||||
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
|
||||
% (server, parentId, parentart,
|
||||
% (self.server, parentId, parentart,
|
||||
maxWidth, maxHeight, parentTag, customquery))
|
||||
allartworks[parentart] = artwork
|
||||
|
||||
|
@ -600,7 +598,7 @@ class Artwork():
|
|||
artwork = (
|
||||
"%s/emby/Items/%s/Images/Primary/0?"
|
||||
"MaxWidth=%s&MaxHeight=%s&Format=original&Tag=%s%s"
|
||||
% (server, parentId, maxWidth, maxHeight, parentTag, customquery))
|
||||
% (self.server, parentId, maxWidth, maxHeight, parentTag, customquery))
|
||||
allartworks['Primary'] = artwork
|
||||
|
||||
return allartworks
|
|
@ -60,8 +60,6 @@ class ConnectUtils():
|
|||
|
||||
def startSession(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
self.deviceId = self.clientInfo.getDeviceId()
|
||||
|
||||
# User is identified from this point
|
||||
|
@ -75,7 +73,7 @@ class ConnectUtils():
|
|||
if self.sslclient is not None:
|
||||
verify = self.sslclient
|
||||
except:
|
||||
log("Could not load SSL settings.", 1)
|
||||
self.logMsg("Could not load SSL settings.", 1)
|
||||
|
||||
# Start session
|
||||
self.c = requests.Session()
|
||||
|
@ -85,7 +83,7 @@ class ConnectUtils():
|
|||
self.c.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||
self.c.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||
|
||||
log("Requests session started on: %s" % self.server, 1)
|
||||
self.logMsg("Requests session started on: %s" % self.server, 1)
|
||||
|
||||
def stopSession(self):
|
||||
try:
|
||||
|
@ -95,8 +93,7 @@ class ConnectUtils():
|
|||
|
||||
def getHeader(self, authenticate=True):
|
||||
|
||||
clientInfo = self.clientInfo
|
||||
version = clientInfo.getVersion()
|
||||
version = self.clientInfo.getVersion()
|
||||
|
||||
if not authenticate:
|
||||
# If user is not authenticated
|
||||
|
@ -125,10 +122,9 @@ class ConnectUtils():
|
|||
def doUrl(self, url, data=None, postBody=None, rtype="GET",
|
||||
parameters=None, authenticate=True, timeout=None):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
|
||||
log("=== ENTER connectUrl ===", 2)
|
||||
self.logMsg("=== ENTER connectUrl ===", 2)
|
||||
default_link = ""
|
||||
if timeout is None:
|
||||
timeout = self.timeout
|
||||
|
@ -213,25 +209,25 @@ class ConnectUtils():
|
|||
verify=verifyssl)
|
||||
|
||||
##### THE RESPONSE #####
|
||||
log(r.url, 1)
|
||||
log(r, 1)
|
||||
self.logMsg(r.url, 1)
|
||||
self.logMsg(r, 1)
|
||||
|
||||
if r.status_code == 204:
|
||||
# No body in the response
|
||||
log("====== 204 Success ======", 1)
|
||||
self.logMsg("====== 204 Success ======", 1)
|
||||
|
||||
elif r.status_code == requests.codes.ok:
|
||||
|
||||
try:
|
||||
# UNICODE - JSON object
|
||||
r = r.json()
|
||||
log("====== 200 Success ======", 1)
|
||||
log("Response: %s" % r, 1)
|
||||
self.logMsg("====== 200 Success ======", 1)
|
||||
self.logMsg("Response: %s" % r, 1)
|
||||
return r
|
||||
|
||||
except:
|
||||
if r.headers.get('content-type') != "text/html":
|
||||
log("Unable to convert the response for: %s" % url, 1)
|
||||
self.logMsg("Unable to convert the response for: %s" % url, 1)
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
|
@ -242,8 +238,8 @@ class ConnectUtils():
|
|||
pass
|
||||
|
||||
except requests.exceptions.ConnectTimeout as e:
|
||||
log("Server timeout at: %s" % url, 0)
|
||||
log(e, 1)
|
||||
self.logMsg("Server timeout at: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
|
||||
except requests.exceptions.HTTPError as e:
|
||||
|
||||
|
@ -259,11 +255,11 @@ class ConnectUtils():
|
|||
pass
|
||||
|
||||
except requests.exceptions.SSLError as e:
|
||||
log("Invalid SSL certificate for: %s" % url, 0)
|
||||
log(e, 1)
|
||||
self.logMsg("Invalid SSL certificate for: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
|
||||
except requests.exceptions.RequestException as e:
|
||||
log("Unknown error connecting to: %s" % url, 0)
|
||||
log(e, 1)
|
||||
self.logMsg("Unknown error connecting to: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
|
||||
return default_link
|
||||
|
|
|
@ -97,7 +97,7 @@ class DownloadUtils():
|
|||
self.logMsg("Capabilities URL: %s" % url, 2)
|
||||
self.logMsg("Postdata: %s" % data, 2)
|
||||
|
||||
self.downloadUrl(url, postBody=data, type="POST")
|
||||
self.downloadUrl(url, postBody=data, action_type="POST")
|
||||
self.logMsg("Posted capabilities to %s" % self.server, 2)
|
||||
|
||||
# Attempt at getting sessionId
|
||||
|
@ -140,13 +140,11 @@ class DownloadUtils():
|
|||
"{server}/emby/Sessions/%s/Users/%s?format=json"
|
||||
% (sessionId, userId)
|
||||
)
|
||||
self.downloadUrl(url, postBody={}, type="POST")
|
||||
self.downloadUrl(url, postBody={}, action_type="POST")
|
||||
|
||||
|
||||
def startSession(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
self.deviceId = self.clientInfo.getDeviceId()
|
||||
|
||||
# User is identified from this point
|
||||
|
@ -160,7 +158,7 @@ class DownloadUtils():
|
|||
if self.sslclient is not None:
|
||||
verify = self.sslclient
|
||||
except:
|
||||
log("Could not load SSL settings.", 1)
|
||||
self.logMsg("Could not load SSL settings.", 1)
|
||||
|
||||
# Start session
|
||||
self.s = requests.Session()
|
||||
|
@ -170,7 +168,7 @@ class DownloadUtils():
|
|||
self.s.mount("http://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||
self.s.mount("https://", requests.adapters.HTTPAdapter(max_retries=1))
|
||||
|
||||
log("Requests session started on: %s" % self.server, 1)
|
||||
self.logMsg("Requests session started on: %s" % self.server, 1)
|
||||
|
||||
def stopSession(self):
|
||||
try:
|
||||
|
@ -180,12 +178,10 @@ class DownloadUtils():
|
|||
|
||||
def getHeader(self, authenticate=True):
|
||||
|
||||
clientInfo = self.clientInfo
|
||||
|
||||
deviceName = clientInfo.getDeviceName()
|
||||
deviceName = self.clientInfo.getDeviceName()
|
||||
deviceName = utils.normalize_string(deviceName.encode('utf-8'))
|
||||
deviceId = clientInfo.getDeviceId()
|
||||
version = clientInfo.getVersion()
|
||||
deviceId = self.clientInfo.getDeviceId()
|
||||
version = self.clientInfo.getVersion()
|
||||
|
||||
if not authenticate:
|
||||
# If user is not authenticated
|
||||
|
@ -220,11 +216,10 @@ class DownloadUtils():
|
|||
|
||||
return header
|
||||
|
||||
def downloadUrl(self, url, postBody=None, type="GET", parameters=None, authenticate=True):
|
||||
def downloadUrl(self, url, postBody=None, action_type="GET", parameters=None, authenticate=True):
|
||||
|
||||
self.logMsg("=== ENTER downloadUrl ===", 2)
|
||||
|
||||
timeout = self.timeout
|
||||
default_link = ""
|
||||
|
||||
try:
|
||||
|
@ -238,12 +233,12 @@ class DownloadUtils():
|
|||
url = url.replace("{UserId}", self.userId)
|
||||
|
||||
# Prepare request
|
||||
if type == "GET":
|
||||
r = s.get(url, json=postBody, params=parameters, timeout=timeout)
|
||||
elif type == "POST":
|
||||
r = s.post(url, json=postBody, timeout=timeout)
|
||||
elif type == "DELETE":
|
||||
r = s.delete(url, json=postBody, timeout=timeout)
|
||||
if action_type == "GET":
|
||||
r = s.get(url, json=postBody, params=parameters, timeout=self.timeout)
|
||||
elif action_type == "POST":
|
||||
r = s.post(url, json=postBody, timeout=self.timeout)
|
||||
elif action_type == "DELETE":
|
||||
r = s.delete(url, json=postBody, timeout=self.timeout)
|
||||
|
||||
except AttributeError:
|
||||
# request session does not exists
|
||||
|
@ -266,26 +261,26 @@ class DownloadUtils():
|
|||
url = url.replace("{UserId}", self.userId)
|
||||
|
||||
# Prepare request
|
||||
if type == "GET":
|
||||
if action_type == "GET":
|
||||
r = requests.get(url,
|
||||
json=postBody,
|
||||
params=parameters,
|
||||
headers=header,
|
||||
timeout=timeout,
|
||||
timeout=self.timeout,
|
||||
verify=verifyssl)
|
||||
|
||||
elif type == "POST":
|
||||
elif action_type == "POST":
|
||||
r = requests.post(url,
|
||||
json=postBody,
|
||||
headers=header,
|
||||
timeout=timeout,
|
||||
timeout=self.timeout,
|
||||
verify=verifyssl)
|
||||
|
||||
elif type == "DELETE":
|
||||
elif action_type == "DELETE":
|
||||
r = requests.delete(url,
|
||||
json=postBody,
|
||||
headers=header,
|
||||
timeout=timeout,
|
||||
timeout=self.timeout,
|
||||
verify=verifyssl)
|
||||
|
||||
# If user is not authenticated
|
||||
|
@ -303,19 +298,19 @@ class DownloadUtils():
|
|||
pass
|
||||
|
||||
# Prepare request
|
||||
if type == "GET":
|
||||
if action_type == "GET":
|
||||
r = requests.get(url,
|
||||
json=postBody,
|
||||
params=parameters,
|
||||
headers=header,
|
||||
timeout=timeout,
|
||||
timeout=self.timeout,
|
||||
verify=verifyssl)
|
||||
|
||||
elif type == "POST":
|
||||
elif action_type == "POST":
|
||||
r = requests.post(url,
|
||||
json=postBody,
|
||||
headers=header,
|
||||
timeout=timeout,
|
||||
timeout=self.timeout,
|
||||
verify=verifyssl)
|
||||
|
||||
##### THE RESPONSE #####
|
||||
|
|
|
@ -25,7 +25,6 @@ class Embydb_Functions():
|
|||
|
||||
def getViews(self):
|
||||
|
||||
embycursor = self.embycursor
|
||||
views = []
|
||||
|
||||
query = ' '.join((
|
||||
|
@ -33,8 +32,8 @@ class Embydb_Functions():
|
|||
"SELECT view_id",
|
||||
"FROM view"
|
||||
))
|
||||
embycursor.execute(query)
|
||||
rows = embycursor.fetchall()
|
||||
self.embycursor.execute(query)
|
||||
rows = self.embycursor.fetchall()
|
||||
for row in rows:
|
||||
views.append(row[0])
|
||||
|
||||
|
@ -42,7 +41,6 @@ class Embydb_Functions():
|
|||
|
||||
def getView_byId(self, viewid):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -50,14 +48,13 @@ class Embydb_Functions():
|
|||
"FROM view",
|
||||
"WHERE view_id = ?"
|
||||
))
|
||||
embycursor.execute(query, (viewid,))
|
||||
view = embycursor.fetchone()
|
||||
self.embycursor.execute(query, (viewid,))
|
||||
view = self.embycursor.fetchone()
|
||||
|
||||
return view
|
||||
|
||||
def getView_byType(self, mediatype):
|
||||
|
||||
embycursor = self.embycursor
|
||||
views = []
|
||||
|
||||
query = ' '.join((
|
||||
|
@ -66,8 +63,8 @@ class Embydb_Functions():
|
|||
"FROM view",
|
||||
"WHERE media_type = ?"
|
||||
))
|
||||
embycursor.execute(query, (mediatype,))
|
||||
rows = embycursor.fetchall()
|
||||
self.embycursor.execute(query, (mediatype,))
|
||||
rows = self.embycursor.fetchall()
|
||||
for row in rows:
|
||||
views.append({
|
||||
|
||||
|
@ -79,17 +76,15 @@ class Embydb_Functions():
|
|||
|
||||
def getView_byName(self, tagname):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT view_id",
|
||||
"FROM view",
|
||||
"WHERE view_name = ?"
|
||||
))
|
||||
embycursor.execute(query, (tagname,))
|
||||
self.embycursor.execute(query, (tagname,))
|
||||
try:
|
||||
view = embycursor.fetchone()[0]
|
||||
view = self.embycursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
view = None
|
||||
|
@ -129,8 +124,6 @@ class Embydb_Functions():
|
|||
|
||||
def getItem_byId(self, embyid):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT kodi_id, kodi_fileid, kodi_pathid, parent_id, media_type, emby_type",
|
||||
|
@ -138,45 +131,35 @@ class Embydb_Functions():
|
|||
"WHERE emby_id = ?"
|
||||
))
|
||||
try:
|
||||
embycursor.execute(query, (embyid,))
|
||||
item = embycursor.fetchone()
|
||||
self.embycursor.execute(query, (embyid,))
|
||||
item = self.embycursor.fetchone()
|
||||
return item
|
||||
except: return None
|
||||
|
||||
def getItem_byWildId(self, embyid):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT kodi_id, media_type",
|
||||
"FROM emby",
|
||||
"WHERE emby_id LIKE ?"
|
||||
))
|
||||
embycursor.execute(query, (embyid+"%",))
|
||||
items = embycursor.fetchall()
|
||||
|
||||
return items
|
||||
self.embycursor.execute(query, (embyid+"%",))
|
||||
return self.embycursor.fetchall()
|
||||
|
||||
def getItem_byView(self, mediafolderid):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT kodi_id",
|
||||
"FROM emby",
|
||||
"WHERE media_folder = ?"
|
||||
))
|
||||
embycursor.execute(query, (mediafolderid,))
|
||||
items = embycursor.fetchall()
|
||||
|
||||
return items
|
||||
self.embycursor.execute(query, (mediafolderid,))
|
||||
return self.embycursor.fetchall()
|
||||
|
||||
def getItem_byKodiId(self, kodiid, mediatype):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT emby_id, parent_id",
|
||||
|
@ -184,15 +167,11 @@ class Embydb_Functions():
|
|||
"WHERE kodi_id = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
embycursor.execute(query, (kodiid, mediatype,))
|
||||
item = embycursor.fetchone()
|
||||
|
||||
return item
|
||||
self.embycursor.execute(query, (kodiid, mediatype,))
|
||||
return self.embycursor.fetchone()
|
||||
|
||||
def getItem_byParentId(self, parentid, mediatype):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT emby_id, kodi_id, kodi_fileid",
|
||||
|
@ -200,15 +179,11 @@ class Embydb_Functions():
|
|||
"WHERE parent_id = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
embycursor.execute(query, (parentid, mediatype,))
|
||||
items = embycursor.fetchall()
|
||||
|
||||
return items
|
||||
self.embycursor.execute(query, (parentid, mediatype,))
|
||||
return self.embycursor.fetchall()
|
||||
|
||||
def getItemId_byParentId(self, parentid, mediatype):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT emby_id, kodi_id",
|
||||
|
@ -216,39 +191,31 @@ class Embydb_Functions():
|
|||
"WHERE parent_id = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
embycursor.execute(query, (parentid, mediatype,))
|
||||
items = embycursor.fetchall()
|
||||
|
||||
return items
|
||||
self.embycursor.execute(query, (parentid, mediatype,))
|
||||
return self.embycursor.fetchall()
|
||||
|
||||
def getChecksum(self, mediatype):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT emby_id, checksum",
|
||||
"FROM emby",
|
||||
"WHERE emby_type = ?"
|
||||
))
|
||||
embycursor.execute(query, (mediatype,))
|
||||
items = embycursor.fetchall()
|
||||
|
||||
return items
|
||||
self.embycursor.execute(query, (mediatype,))
|
||||
return self.embycursor.fetchall()
|
||||
|
||||
def getMediaType_byId(self, embyid):
|
||||
|
||||
embycursor = self.embycursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT emby_type",
|
||||
"FROM emby",
|
||||
"WHERE emby_id = ?"
|
||||
))
|
||||
embycursor.execute(query, (embyid,))
|
||||
self.embycursor.execute(query, (embyid,))
|
||||
try:
|
||||
itemtype = embycursor.fetchone()[0]
|
||||
itemtype = self.embycursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
itemtype = None
|
||||
|
|
|
@ -67,12 +67,12 @@ def doMainListing():
|
|||
if not path:
|
||||
path = utils.window('Emby.nodes.%s.content' % i)
|
||||
label = utils.window('Emby.nodes.%s.title' % i)
|
||||
type = utils.window('Emby.nodes.%s.type' % i)
|
||||
node_type = utils.window('Emby.nodes.%s.type' % i)
|
||||
#because we do not use seperate entrypoints for each content type, we need to figure out which items to show in each listing.
|
||||
#for now we just only show picture nodes in the picture library video nodes in the video library and all nodes in any other window
|
||||
if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and type == "photos":
|
||||
if path and xbmc.getCondVisibility("Window.IsActive(Pictures)") and node_type == "photos":
|
||||
addDirectoryItem(label, path)
|
||||
elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and type != "photos":
|
||||
elif path and xbmc.getCondVisibility("Window.IsActive(VideoLibrary)") and node_type != "photos":
|
||||
addDirectoryItem(label, path)
|
||||
elif path and not xbmc.getCondVisibility("Window.IsActive(VideoLibrary) | Window.IsActive(Pictures) | Window.IsActive(MusicLibrary)"):
|
||||
addDirectoryItem(label, path)
|
||||
|
@ -166,7 +166,7 @@ def deleteItem():
|
|||
doUtils = downloadutils.DownloadUtils()
|
||||
url = "{server}/emby/Items/%s?format=json" % embyid
|
||||
utils.logMsg("EMBY delete", "Deleting request: %s" % embyid, 0)
|
||||
doUtils.downloadUrl(url, type="DELETE")
|
||||
doUtils.downloadUrl(url, action_type="DELETE")
|
||||
|
||||
##### ADD ADDITIONAL USERS #####
|
||||
def addUser():
|
||||
|
@ -221,7 +221,7 @@ def addUser():
|
|||
selected = additionalUsername[resp]
|
||||
selected_userId = additionalUserlist[selected]
|
||||
url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
|
||||
doUtils.downloadUrl(url, postBody={}, type="DELETE")
|
||||
doUtils.downloadUrl(url, postBody={}, action_type="DELETE")
|
||||
dialog.notification(
|
||||
heading="Success!",
|
||||
message="%s removed from viewing session" % selected,
|
||||
|
@ -254,7 +254,7 @@ def addUser():
|
|||
selected = users[resp]
|
||||
selected_userId = userlist[selected]
|
||||
url = "{server}/emby/Sessions/%s/Users/%s" % (sessionId, selected_userId)
|
||||
doUtils.downloadUrl(url, postBody={}, type="POST")
|
||||
doUtils.downloadUrl(url, postBody={}, action_type="POST")
|
||||
dialog.notification(
|
||||
heading="Success!",
|
||||
message="%s added to viewing session" % selected,
|
||||
|
@ -483,12 +483,11 @@ def GetSubFolders(nodeindex):
|
|||
title = utils.window('Emby.nodes.%s%s.title' %(nodeindex,node))
|
||||
if title:
|
||||
path = utils.window('Emby.nodes.%s%s.content' %(nodeindex,node))
|
||||
type = utils.window('Emby.nodes.%s%s.type' %(nodeindex,node))
|
||||
addDirectoryItem(title, path)
|
||||
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||
|
||||
##### BROWSE EMBY NODES DIRECTLY #####
|
||||
def BrowseContent(viewname, type="", folderid=""):
|
||||
def BrowseContent(viewname, browse_type="", folderid=""):
|
||||
|
||||
emby = embyserver.Read_EmbyServer()
|
||||
art = artwork.Artwork()
|
||||
|
@ -496,46 +495,47 @@ def BrowseContent(viewname, type="", folderid=""):
|
|||
|
||||
#folderid used as filter ?
|
||||
if folderid in ["recent","recentepisodes","inprogress","inprogressepisodes","unwatched","nextepisodes","sets","genres","random","recommended"]:
|
||||
filter = folderid
|
||||
filter_type = folderid
|
||||
folderid = ""
|
||||
else:
|
||||
filter = ""
|
||||
filter_type = ""
|
||||
|
||||
xbmcplugin.setPluginCategory(int(sys.argv[1]), viewname)
|
||||
#get views for root level
|
||||
if not folderid:
|
||||
views = emby.getViews(type)
|
||||
views = emby.getViews(browse_type)
|
||||
for view in views:
|
||||
if view.get("name") == viewname.decode('utf-8'):
|
||||
folderid = view.get("id")
|
||||
break
|
||||
|
||||
if viewname is not None:
|
||||
utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), type.decode('utf-8'), folderid.decode('utf-8'), filter.decode('utf-8')))
|
||||
utils.logMsg("BrowseContent","viewname: %s - type: %s - folderid: %s - filter: %s" %(viewname.decode('utf-8'), browse_type.decode('utf-8'), folderid.decode('utf-8'), filter_type.decode('utf-8')))
|
||||
#set the correct params for the content type
|
||||
#only proceed if we have a folderid
|
||||
if folderid:
|
||||
if type.lower() == "homevideos":
|
||||
if browse_type.lower() == "homevideos":
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'episodes')
|
||||
itemtype = "Video,Folder,PhotoAlbum"
|
||||
elif type.lower() == "photos":
|
||||
elif browse_type.lower() == "photos":
|
||||
xbmcplugin.setContent(int(sys.argv[1]), 'files')
|
||||
itemtype = "Photo,PhotoAlbum,Folder"
|
||||
else:
|
||||
itemtype = ""
|
||||
|
||||
#get the actual listing
|
||||
if type == "recordings":
|
||||
if browse_type == "recordings":
|
||||
listing = emby.getTvRecordings(folderid)
|
||||
elif type == "tvchannels":
|
||||
elif browse_type == "tvchannels":
|
||||
listing = emby.getTvChannels()
|
||||
elif filter == "recent":
|
||||
elif filter_type == "recent":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="DateCreated", recursive=True, limit=25, sortorder="Descending")
|
||||
elif filter == "random":
|
||||
elif filter_type == "random":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="Random", recursive=True, limit=150, sortorder="Descending")
|
||||
elif filter == "recommended":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite")
|
||||
elif filter == "sets":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter="IsFavorite")
|
||||
elif filter_type == "recommended":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[0], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
|
||||
elif filter_type == "sets":
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype.split(",")[1], sortby="SortName", recursive=True, limit=25, sortorder="Ascending", filter_type="IsFavorite")
|
||||
else:
|
||||
listing = emby.getFilteredSection(folderid, itemtype=itemtype, recursive=False)
|
||||
|
||||
|
@ -545,14 +545,14 @@ def BrowseContent(viewname, type="", folderid=""):
|
|||
li = createListItemFromEmbyItem(item,art,doUtils)
|
||||
if item.get("IsFolder") == True:
|
||||
#for folders we add an additional browse request, passing the folderId
|
||||
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), type.decode('utf-8'), item.get("Id").decode('utf-8'))
|
||||
path = "%s?id=%s&mode=browsecontent&type=%s&folderid=%s" % (sys.argv[0].decode('utf-8'), viewname.decode('utf-8'), browse_type.decode('utf-8'), item.get("Id").decode('utf-8'))
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=path, listitem=li, isFolder=True)
|
||||
else:
|
||||
#playable item, set plugin path and mediastreams
|
||||
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=li.getProperty("path"), listitem=li)
|
||||
|
||||
|
||||
if filter == "recent":
|
||||
if filter_type == "recent":
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_DATE)
|
||||
else:
|
||||
xbmcplugin.addSortMethod(int(sys.argv[1]), xbmcplugin.SORT_METHOD_VIDEO_TITLE)
|
||||
|
|
|
@ -176,8 +176,8 @@ class InitialSetup():
|
|||
sock.setsockopt(socket.SOL_IP, socket.IP_MULTICAST_LOOP, 1)
|
||||
sock.setsockopt(socket.IPPROTO_IP, socket.SO_REUSEADDR, 1)
|
||||
|
||||
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2);
|
||||
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2);
|
||||
self.logMsg("MultiGroup : %s" % str(MULTI_GROUP), 2)
|
||||
self.logMsg("Sending UDP Data: %s" % MESSAGE, 2)
|
||||
sock.sendto(MESSAGE, MULTI_GROUP)
|
||||
|
||||
try:
|
||||
|
|
|
@ -249,10 +249,9 @@ class Movies(Items):
|
|||
count = 0
|
||||
for boxset in items:
|
||||
|
||||
title = boxset['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=boxset['Name'])
|
||||
count += 1
|
||||
self.add_updateBoxset(boxset)
|
||||
|
||||
|
@ -261,7 +260,6 @@ class Movies(Items):
|
|||
# Process single movie
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -423,9 +421,9 @@ class Movies(Items):
|
|||
self.logMsg("ADD movie itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Add path
|
||||
pathid = kodi_db.addPath(path)
|
||||
pathid = self.kodi_db.addPath(path)
|
||||
# Add the file
|
||||
fileid = kodi_db.addFile(filename, pathid)
|
||||
fileid = self.kodi_db.addFile(filename, pathid)
|
||||
|
||||
# Create the movie entry
|
||||
query = (
|
||||
|
@ -463,35 +461,34 @@ class Movies(Items):
|
|||
kodicursor.execute(query, (pathid, filename, dateadded, fileid))
|
||||
|
||||
# Process countries
|
||||
kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
|
||||
self.kodi_db.addCountries(movieid, item['ProductionLocations'], "movie")
|
||||
# Process cast
|
||||
people = artwork.getPeopleArtwork(item['People'])
|
||||
kodi_db.addPeople(movieid, people, "movie")
|
||||
self.kodi_db.addPeople(movieid, people, "movie")
|
||||
# Process genres
|
||||
kodi_db.addGenres(movieid, genres, "movie")
|
||||
self.kodi_db.addGenres(movieid, genres, "movie")
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(item), movieid, "movie", kodicursor)
|
||||
# Process stream details
|
||||
streams = API.getMediaStreams()
|
||||
kodi_db.addStreams(fileid, streams, runtime)
|
||||
self.kodi_db.addStreams(fileid, streams, runtime)
|
||||
# Process studios
|
||||
kodi_db.addStudios(movieid, studios, "movie")
|
||||
self.kodi_db.addStudios(movieid, studios, "movie")
|
||||
# Process tags: view, emby tags
|
||||
tags = [viewtag]
|
||||
tags.extend(item['Tags'])
|
||||
if userdata['Favorite']:
|
||||
tags.append("Favorite movies")
|
||||
kodi_db.addTags(movieid, tags, "movie")
|
||||
self.kodi_db.addTags(movieid, tags, "movie")
|
||||
# Process playstates
|
||||
resume = API.adjustResume(userdata['Resume'])
|
||||
total = round(float(runtime), 6)
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
|
||||
def add_updateBoxset(self, boxset):
|
||||
|
||||
emby = self.emby
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
|
||||
boxsetid = boxset['Id']
|
||||
|
@ -502,7 +499,7 @@ class Movies(Items):
|
|||
setid = emby_dbitem[0]
|
||||
|
||||
except TypeError:
|
||||
setid = kodi_db.createBoxset(title)
|
||||
setid = self.kodi_db.createBoxset(title)
|
||||
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(boxset), setid, "set", self.kodicursor)
|
||||
|
@ -521,8 +518,7 @@ class Movies(Items):
|
|||
process.append(current_movie)
|
||||
|
||||
# New list to compare
|
||||
boxsetMovies = emby.getMovies_byBoxset(boxsetid)
|
||||
for movie in boxsetMovies['Items']:
|
||||
for movie in emby.getMovies_byBoxset(boxsetid)['Items']:
|
||||
|
||||
itemid = movie['Id']
|
||||
|
||||
|
@ -536,7 +532,7 @@ class Movies(Items):
|
|||
continue
|
||||
|
||||
self.logMsg("New addition to boxset %s: %s" % (title, movie['Name']), 1)
|
||||
kodi_db.assignBoxset(setid, movieid)
|
||||
self.kodi_db.assignBoxset(setid, movieid)
|
||||
# Update emby reference
|
||||
emby_db.updateParentId(itemid, setid)
|
||||
else:
|
||||
|
@ -547,7 +543,7 @@ class Movies(Items):
|
|||
for movie in process:
|
||||
movieid = current[movie]
|
||||
self.logMsg("Remove from boxset %s: %s" % (title, movieid))
|
||||
kodi_db.removefromBoxset(movieid)
|
||||
self.kodi_db.removefromBoxset(movieid)
|
||||
# Update emby reference
|
||||
emby_db.updateParentId(movie, None)
|
||||
|
||||
|
@ -558,7 +554,6 @@ class Movies(Items):
|
|||
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
||||
# Poster with progress bar
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
API = api.API(item)
|
||||
|
||||
# Get emby information
|
||||
|
@ -580,9 +575,9 @@ class Movies(Items):
|
|||
|
||||
# Process favorite tags
|
||||
if userdata['Favorite']:
|
||||
kodi_db.addTag(movieid, "Favorite movies", "movie")
|
||||
self.kodi_db.addTag(movieid, "Favorite movies", "movie")
|
||||
else:
|
||||
kodi_db.removeTag(movieid, "Favorite movies", "movie")
|
||||
self.kodi_db.removeTag(movieid, "Favorite movies", "movie")
|
||||
|
||||
# Process playstates
|
||||
playcount = userdata['PlayCount']
|
||||
|
@ -592,7 +587,7 @@ class Movies(Items):
|
|||
|
||||
self.logMsg("%s New resume point: %s" % (itemid, resume))
|
||||
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
emby_db.updateReference(itemid, checksum)
|
||||
|
||||
def remove(self, itemid):
|
||||
|
@ -660,7 +655,6 @@ class MusicVideos(Items):
|
|||
# Process single music video
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -851,32 +845,31 @@ class MusicVideos(Items):
|
|||
artist['Type'] = "Artist"
|
||||
people.extend(artists)
|
||||
people = artwork.getPeopleArtwork(people)
|
||||
kodi_db.addPeople(mvideoid, people, "musicvideo")
|
||||
self.kodi_db.addPeople(mvideoid, people, "musicvideo")
|
||||
# Process genres
|
||||
kodi_db.addGenres(mvideoid, genres, "musicvideo")
|
||||
self.kodi_db.addGenres(mvideoid, genres, "musicvideo")
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(item), mvideoid, "musicvideo", kodicursor)
|
||||
# Process stream details
|
||||
streams = API.getMediaStreams()
|
||||
kodi_db.addStreams(fileid, streams, runtime)
|
||||
self.kodi_db.addStreams(fileid, streams, runtime)
|
||||
# Process studios
|
||||
kodi_db.addStudios(mvideoid, studios, "musicvideo")
|
||||
self.kodi_db.addStudios(mvideoid, studios, "musicvideo")
|
||||
# Process tags: view, emby tags
|
||||
tags = [viewtag]
|
||||
tags.extend(item['Tags'])
|
||||
if userdata['Favorite']:
|
||||
tags.append("Favorite musicvideos")
|
||||
kodi_db.addTags(mvideoid, tags, "musicvideo")
|
||||
self.kodi_db.addTags(mvideoid, tags, "musicvideo")
|
||||
# Process playstates
|
||||
resume = API.adjustResume(userdata['Resume'])
|
||||
total = round(float(runtime), 6)
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
|
||||
def updateUserdata(self, item):
|
||||
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
||||
# Poster with progress bar
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
API = api.API(item)
|
||||
|
||||
# Get emby information
|
||||
|
@ -898,9 +891,9 @@ class MusicVideos(Items):
|
|||
|
||||
# Process favorite tags
|
||||
if userdata['Favorite']:
|
||||
kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
||||
self.kodi_db.addTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
||||
else:
|
||||
kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
||||
self.kodi_db.removeTag(mvideoid, "Favorite musicvideos", "musicvideo")
|
||||
|
||||
# Process playstates
|
||||
playcount = userdata['PlayCount']
|
||||
|
@ -908,7 +901,7 @@ class MusicVideos(Items):
|
|||
resume = API.adjustResume(userdata['Resume'])
|
||||
total = round(float(runtime), 6)
|
||||
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
emby_db.updateReference(itemid, checksum)
|
||||
|
||||
def remove(self, itemid):
|
||||
|
@ -935,8 +928,7 @@ class MusicVideos(Items):
|
|||
"AND media_type = 'musicvideo'"
|
||||
))
|
||||
kodicursor.execute(query, (mvideoid,))
|
||||
rows = kodicursor.fetchall()
|
||||
for row in rows:
|
||||
for row in kodicursor.fetchall():
|
||||
|
||||
url = row[0]
|
||||
imagetype = row[1]
|
||||
|
@ -1009,7 +1001,6 @@ class TVShows(Items):
|
|||
kodicursor = self.kodicursor
|
||||
emby = self.emby
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -1131,7 +1122,7 @@ class TVShows(Items):
|
|||
self.logMsg("ADD tvshow itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Add top path
|
||||
toppathid = kodi_db.addPath(toplevelpath)
|
||||
toppathid = self.kodi_db.addPath(toplevelpath)
|
||||
query = ' '.join((
|
||||
|
||||
"UPDATE path",
|
||||
|
@ -1141,7 +1132,7 @@ class TVShows(Items):
|
|||
kodicursor.execute(query, (toplevelpath, "tvshows", "metadata.local", 1, toppathid))
|
||||
|
||||
# Add path
|
||||
pathid = kodi_db.addPath(path)
|
||||
pathid = self.kodi_db.addPath(path)
|
||||
|
||||
# Create the tvshow entry
|
||||
query = (
|
||||
|
@ -1174,26 +1165,26 @@ class TVShows(Items):
|
|||
|
||||
# Process cast
|
||||
people = artwork.getPeopleArtwork(item['People'])
|
||||
kodi_db.addPeople(showid, people, "tvshow")
|
||||
self.kodi_db.addPeople(showid, people, "tvshow")
|
||||
# Process genres
|
||||
kodi_db.addGenres(showid, genres, "tvshow")
|
||||
self.kodi_db.addGenres(showid, genres, "tvshow")
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(item), showid, "tvshow", kodicursor)
|
||||
# Process studios
|
||||
kodi_db.addStudios(showid, studios, "tvshow")
|
||||
self.kodi_db.addStudios(showid, studios, "tvshow")
|
||||
# Process tags: view, emby tags
|
||||
tags = [viewtag]
|
||||
tags.extend(item['Tags'])
|
||||
if userdata['Favorite']:
|
||||
tags.append("Favorite tvshows")
|
||||
kodi_db.addTags(showid, tags, "tvshow")
|
||||
self.kodi_db.addTags(showid, tags, "tvshow")
|
||||
# Process seasons
|
||||
all_seasons = emby.getSeasons(itemid)
|
||||
for season in all_seasons['Items']:
|
||||
self.add_updateSeason(season, showid=showid)
|
||||
else:
|
||||
# Finally, refresh the all season entry
|
||||
seasonid = kodi_db.addSeason(showid, -1)
|
||||
seasonid = self.kodi_db.addSeason(showid, -1)
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor)
|
||||
|
||||
|
@ -1207,11 +1198,9 @@ class TVShows(Items):
|
|||
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
|
||||
seasonnum = item.get('IndexNumber', 1)
|
||||
itemid = item['Id']
|
||||
|
||||
if showid is None:
|
||||
try:
|
||||
|
@ -1225,21 +1214,19 @@ class TVShows(Items):
|
|||
self.add_update(show)
|
||||
return
|
||||
|
||||
seasonid = kodi_db.addSeason(showid, seasonnum)
|
||||
seasonid = self.kodi_db.addSeason(showid, seasonnum)
|
||||
|
||||
if item['LocationType'] != "Virtual":
|
||||
# Create the reference in emby table
|
||||
emby_db.addReference(itemid, seasonid, "Season", "season", parentid=showid)
|
||||
emby_db.addReference(item['Id'], seasonid, "Season", "season", parentid=showid)
|
||||
|
||||
# Process artwork
|
||||
artwork.addArtwork(artwork.getAllArtwork(item), seasonid, "season", kodicursor)
|
||||
|
||||
def add_updateEpisode(self, item):
|
||||
# Process single episode
|
||||
kodiversion = self.kodiversion
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -1336,7 +1323,7 @@ class TVShows(Items):
|
|||
self.logMsg("Skipping: %s. Unable to add series: %s." % (itemid, seriesId))
|
||||
return False
|
||||
|
||||
seasonid = kodi_db.addSeason(showid, season)
|
||||
seasonid = self.kodi_db.addSeason(showid, season)
|
||||
|
||||
|
||||
##### GET THE FILE AND PATH #####
|
||||
|
@ -1384,7 +1371,7 @@ class TVShows(Items):
|
|||
self.logMsg("UPDATE episode itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Update the movie entry
|
||||
if kodiversion in (16, 17):
|
||||
if self.kodiversion in (16, 17):
|
||||
# Kodi Jarvis, Krypton
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -1418,12 +1405,12 @@ class TVShows(Items):
|
|||
self.logMsg("ADD episode itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Add path
|
||||
pathid = kodi_db.addPath(path)
|
||||
pathid = self.kodi_db.addPath(path)
|
||||
# Add the file
|
||||
fileid = kodi_db.addFile(filename, pathid)
|
||||
fileid = self.kodi_db.addFile(filename, pathid)
|
||||
|
||||
# Create the episode entry
|
||||
if kodiversion in (16, 17):
|
||||
if self.kodiversion in (16, 17):
|
||||
# Kodi Jarvis, Krypton
|
||||
query = (
|
||||
'''
|
||||
|
@ -1475,21 +1462,21 @@ class TVShows(Items):
|
|||
|
||||
# Process cast
|
||||
people = artwork.getPeopleArtwork(item['People'])
|
||||
kodi_db.addPeople(episodeid, people, "episode")
|
||||
self.kodi_db.addPeople(episodeid, people, "episode")
|
||||
# Process artwork
|
||||
artworks = artwork.getAllArtwork(item)
|
||||
artwork.addOrUpdateArt(artworks['Primary'], episodeid, "episode", "thumb", kodicursor)
|
||||
# Process stream details
|
||||
streams = API.getMediaStreams()
|
||||
kodi_db.addStreams(fileid, streams, runtime)
|
||||
self.kodi_db.addStreams(fileid, streams, runtime)
|
||||
# Process playstates
|
||||
resume = API.adjustResume(userdata['Resume'])
|
||||
total = round(float(runtime), 6)
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
if not self.directpath and resume:
|
||||
# Create additional entry for widgets. This is only required for plugin/episode.
|
||||
temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
|
||||
tempfileid = kodi_db.addFile(filename, temppathid)
|
||||
temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
|
||||
tempfileid = self.kodi_db.addFile(filename, temppathid)
|
||||
query = ' '.join((
|
||||
|
||||
"UPDATE files",
|
||||
|
@ -1497,13 +1484,12 @@ class TVShows(Items):
|
|||
"WHERE idFile = ?"
|
||||
))
|
||||
kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
|
||||
kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
|
||||
|
||||
def updateUserdata(self, item):
|
||||
# This updates: Favorite, LastPlayedDate, Playcount, PlaybackPositionTicks
|
||||
# Poster with progress bar
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
API = api.API(item)
|
||||
|
||||
# Get emby information
|
||||
|
@ -1528,12 +1514,11 @@ class TVShows(Items):
|
|||
# Process favorite tags
|
||||
if mediatype == "tvshow":
|
||||
if userdata['Favorite']:
|
||||
kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
|
||||
self.kodi_db.addTag(kodiid, "Favorite tvshows", "tvshow")
|
||||
else:
|
||||
kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
|
||||
|
||||
self.kodi_db.removeTag(kodiid, "Favorite tvshows", "tvshow")
|
||||
elif mediatype == "episode":
|
||||
# Process playstates
|
||||
if mediatype == "episode":
|
||||
playcount = userdata['PlayCount']
|
||||
dateplayed = userdata['LastPlayedDate']
|
||||
resume = API.adjustResume(userdata['Resume'])
|
||||
|
@ -1541,17 +1526,17 @@ class TVShows(Items):
|
|||
|
||||
self.logMsg("%s New resume point: %s" % (itemid, resume))
|
||||
|
||||
kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(fileid, resume, total, playcount, dateplayed)
|
||||
if not self.directpath and not resume:
|
||||
# Make sure there's no other bookmarks created by widget.
|
||||
filename = kodi_db.getFile(fileid)
|
||||
kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
|
||||
filename = self.kodi_db.getFile(fileid)
|
||||
self.kodi_db.removeFile("plugin://plugin.video.emby.tvshows/", filename)
|
||||
|
||||
if not self.directpath and resume:
|
||||
# Create additional entry for widgets. This is only required for plugin/episode.
|
||||
filename = kodi_db.getFile(fileid)
|
||||
temppathid = kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
|
||||
tempfileid = kodi_db.addFile(filename, temppathid)
|
||||
filename = self.kodi_db.getFile(fileid)
|
||||
temppathid = self.kodi_db.getPath("plugin://plugin.video.emby.tvshows/")
|
||||
tempfileid = self.kodi_db.addFile(filename, temppathid)
|
||||
query = ' '.join((
|
||||
|
||||
"UPDATE files",
|
||||
|
@ -1559,7 +1544,7 @@ class TVShows(Items):
|
|||
"WHERE idFile = ?"
|
||||
))
|
||||
self.kodicursor.execute(query, (temppathid, filename, dateadded, tempfileid))
|
||||
kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
|
||||
self.kodi_db.addPlaystate(tempfileid, resume, total, playcount, dateplayed)
|
||||
|
||||
emby_db.updateReference(itemid, checksum)
|
||||
|
||||
|
@ -1672,27 +1657,23 @@ class TVShows(Items):
|
|||
def removeShow(self, kodiid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "tvshow", kodicursor)
|
||||
self.artwork.deleteArtwork(kodiid, "tvshow", kodicursor)
|
||||
kodicursor.execute("DELETE FROM tvshow WHERE idShow = ?", (kodiid,))
|
||||
self.logMsg("Removed tvshow: %s." % kodiid, 2)
|
||||
|
||||
def removeSeason(self, kodiid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "season", kodicursor)
|
||||
self.artwork.deleteArtwork(kodiid, "season", kodicursor)
|
||||
kodicursor.execute("DELETE FROM seasons WHERE idSeason = ?", (kodiid,))
|
||||
self.logMsg("Removed season: %s." % kodiid, 2)
|
||||
|
||||
def removeEpisode(self, kodiid, fileid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "episode", kodicursor)
|
||||
self.artwork.deleteArtwork(kodiid, "episode", kodicursor)
|
||||
kodicursor.execute("DELETE FROM episode WHERE idEpisode = ?", (kodiid,))
|
||||
kodicursor.execute("DELETE FROM files WHERE idFile = ?", (fileid,))
|
||||
self.logMsg("Removed episode: %s." % kodiid, 2)
|
||||
|
@ -1717,10 +1698,9 @@ class Music(Items):
|
|||
count = 0
|
||||
for artist in items:
|
||||
|
||||
title = artist['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=artist['Name'])
|
||||
count += 1
|
||||
self.add_updateArtist(artist)
|
||||
# Add albums
|
||||
|
@ -1733,10 +1713,9 @@ class Music(Items):
|
|||
count = 0
|
||||
for album in items:
|
||||
|
||||
title = album['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=album['Name'])
|
||||
count += 1
|
||||
self.add_updateAlbum(album)
|
||||
# Add songs
|
||||
|
@ -1749,21 +1728,18 @@ class Music(Items):
|
|||
count = 0
|
||||
for song in items:
|
||||
|
||||
title = song['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=song['Name'])
|
||||
count += 1
|
||||
self.add_updateSong(song)
|
||||
if not pdialog and self.contentmsg:
|
||||
self.contentPop(title, self.newmusic_time)
|
||||
self.contentPop(song['Name'], self.newmusic_time)
|
||||
|
||||
def add_updateArtist(self, item, artisttype="MusicArtist"):
|
||||
# Process a single artist
|
||||
kodiversion = self.kodiversion
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -1810,7 +1786,7 @@ class Music(Items):
|
|||
self.logMsg("ADD artist itemid: %s - Name: %s" % (itemid, name), 1)
|
||||
# safety checks: It looks like Emby supports the same artist multiple times.
|
||||
# Kodi doesn't allow that. In case that happens we just merge the artist entries.
|
||||
artistid = kodi_db.addArtist(name, musicBrainzId)
|
||||
artistid = self.kodi_db.addArtist(name, musicBrainzId)
|
||||
# Create the reference in emby table
|
||||
emby_db.addReference(itemid, artistid, artisttype, "artist", checksum=checksum)
|
||||
|
||||
|
@ -1843,10 +1819,8 @@ class Music(Items):
|
|||
def add_updateAlbum(self, item):
|
||||
# Process a single artist
|
||||
emby = self.emby
|
||||
kodiversion = self.kodiversion
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -1897,13 +1871,13 @@ class Music(Items):
|
|||
self.logMsg("ADD album itemid: %s - Name: %s" % (itemid, name), 1)
|
||||
# safety checks: It looks like Emby supports the same artist multiple times.
|
||||
# Kodi doesn't allow that. In case that happens we just merge the artist entries.
|
||||
albumid = kodi_db.addAlbum(name, musicBrainzId)
|
||||
albumid = self.kodi_db.addAlbum(name, musicBrainzId)
|
||||
# Create the reference in emby table
|
||||
emby_db.addReference(itemid, albumid, "MusicAlbum", "album", checksum=checksum)
|
||||
|
||||
|
||||
# Process the album info
|
||||
if kodiversion == 17:
|
||||
if self.kodiversion == 17:
|
||||
# Kodi Krypton
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -1914,7 +1888,7 @@ class Music(Items):
|
|||
))
|
||||
kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
|
||||
"album", albumid))
|
||||
elif kodiversion == 16:
|
||||
elif self.kodiversion == 16:
|
||||
# Kodi Jarvis
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -1925,7 +1899,7 @@ class Music(Items):
|
|||
))
|
||||
kodicursor.execute(query, (artistname, year, genre, bio, thumb, rating, lastScraped,
|
||||
"album", albumid))
|
||||
elif kodiversion == 15:
|
||||
elif self.kodiversion == 15:
|
||||
# Kodi Isengard
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -2006,17 +1980,15 @@ class Music(Items):
|
|||
emby_db.updateParentId(artistId, albumid)
|
||||
|
||||
# Add genres
|
||||
kodi_db.addMusicGenres(albumid, genres, "album")
|
||||
self.kodi_db.addMusicGenres(albumid, genres, "album")
|
||||
# Update artwork
|
||||
artwork.addArtwork(artworks, albumid, "album", kodicursor)
|
||||
|
||||
def add_updateSong(self, item):
|
||||
# Process single song
|
||||
kodiversion = self.kodiversion
|
||||
kodicursor = self.kodicursor
|
||||
emby = self.emby
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
artwork = self.artwork
|
||||
API = api.API(item)
|
||||
|
||||
|
@ -2122,7 +2094,7 @@ class Music(Items):
|
|||
self.logMsg("ADD song itemid: %s - Title: %s" % (itemid, title), 1)
|
||||
|
||||
# Add path
|
||||
pathid = kodi_db.addPath(path)
|
||||
pathid = self.kodi_db.addPath(path)
|
||||
|
||||
try:
|
||||
# Get the album
|
||||
|
@ -2133,7 +2105,7 @@ class Music(Items):
|
|||
album_name = item.get('Album')
|
||||
if album_name:
|
||||
self.logMsg("Creating virtual music album for song: %s." % itemid, 1)
|
||||
albumid = kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
|
||||
albumid = self.kodi_db.addAlbum(album_name, API.getProvider('MusicBrainzAlbum'))
|
||||
emby_db.addReference("%salbum%s" % (itemid, albumid), albumid, "MusicAlbum_", "album")
|
||||
else:
|
||||
# No album Id associated to the song.
|
||||
|
@ -2155,7 +2127,7 @@ class Music(Items):
|
|||
self.logMsg("Failed to add album. Creating singles.", 1)
|
||||
kodicursor.execute("select coalesce(max(idAlbum),0) from album")
|
||||
albumid = kodicursor.fetchone()[0] + 1
|
||||
if kodiversion == 16:
|
||||
if self.kodiversion == 16:
|
||||
# Kodi Jarvis
|
||||
query = (
|
||||
'''
|
||||
|
@ -2165,7 +2137,7 @@ class Music(Items):
|
|||
'''
|
||||
)
|
||||
kodicursor.execute(query, (albumid, genre, year, "single"))
|
||||
elif kodiversion == 15:
|
||||
elif self.kodiversion == 15:
|
||||
# Kodi Isengard
|
||||
query = (
|
||||
'''
|
||||
|
@ -2289,11 +2261,11 @@ class Music(Items):
|
|||
result = kodicursor.fetchone()
|
||||
if result and result[0] != album_artists:
|
||||
# Field is empty
|
||||
if kodiversion in (16, 17):
|
||||
if self.kodiversion in (16, 17):
|
||||
# Kodi Jarvis, Krypton
|
||||
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
|
||||
kodicursor.execute(query, (album_artists, albumid))
|
||||
elif kodiversion == 15:
|
||||
elif self.kodiversion == 15:
|
||||
# Kodi Isengard
|
||||
query = "UPDATE album SET strArtists = ? WHERE idAlbum = ?"
|
||||
kodicursor.execute(query, (album_artists, albumid))
|
||||
|
@ -2303,7 +2275,7 @@ class Music(Items):
|
|||
kodicursor.execute(query, (album_artists, albumid))
|
||||
|
||||
# Add genres
|
||||
kodi_db.addMusicGenres(songid, genres, "song")
|
||||
self.kodi_db.addMusicGenres(songid, genres, "song")
|
||||
|
||||
# Update artwork
|
||||
allart = artwork.getAllArtwork(item, parentInfo=True)
|
||||
|
@ -2320,7 +2292,6 @@ class Music(Items):
|
|||
# Poster with progress bar
|
||||
kodicursor = self.kodicursor
|
||||
emby_db = self.emby_db
|
||||
kodi_db = self.kodi_db
|
||||
API = api.API(item)
|
||||
|
||||
# Get emby information
|
||||
|
@ -2391,10 +2362,9 @@ class Music(Items):
|
|||
self.removeSong(kodiid)
|
||||
# This should only address single song scenario, where server doesn't actually
|
||||
# create an album for the song.
|
||||
customitems = emby_db.getItem_byWildId(itemid)
|
||||
emby_db.removeWildItem(itemid)
|
||||
|
||||
for item in customitems:
|
||||
for item in emby_db.getItem_byWildId(itemid):
|
||||
|
||||
item_kid = item[0]
|
||||
item_mediatype = item[1]
|
||||
|
@ -2448,23 +2418,16 @@ class Music(Items):
|
|||
def removeSong(self, kodiid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "song", kodicursor)
|
||||
kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiid,))
|
||||
self.artwork.deleteArtwork(kodiid, "song", self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM song WHERE idSong = ?", (kodiid,))
|
||||
|
||||
def removeAlbum(self, kodiid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "album", kodicursor)
|
||||
kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiid,))
|
||||
self.artwork.deleteArtwork(kodiid, "album", self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM album WHERE idAlbum = ?", (kodiid,))
|
||||
|
||||
def removeArtist(self, kodiid):
|
||||
|
||||
kodicursor = self.kodicursor
|
||||
artwork = self.artwork
|
||||
|
||||
artwork.deleteArtwork(kodiid, "artist", kodicursor)
|
||||
kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))
|
||||
self.artwork.deleteArtwork(kodiid, "artist", self.kodicursor)
|
||||
self.kodicursor.execute("DELETE FROM artist WHERE idArtist = ?", (kodiid,))
|
||||
|
|
|
@ -33,20 +33,18 @@ class Kodidb_Functions():
|
|||
|
||||
def addPath(self, path):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idPath",
|
||||
"FROM path",
|
||||
"WHERE strPath = ?"
|
||||
))
|
||||
cursor.execute(query, (path,))
|
||||
self.cursor.execute(query, (path,))
|
||||
try:
|
||||
pathid = cursor.fetchone()[0]
|
||||
pathid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idPath),0) from path")
|
||||
pathid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idPath),0) from path")
|
||||
pathid = self.cursor.fetchone()[0] + 1
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO path(
|
||||
|
@ -55,23 +53,21 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (pathid, path))
|
||||
self.cursor.execute(query, (pathid, path))
|
||||
|
||||
return pathid
|
||||
|
||||
def getPath(self, path):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idPath",
|
||||
"FROM path",
|
||||
"WHERE strPath = ?"
|
||||
))
|
||||
cursor.execute(query, (path,))
|
||||
self.cursor.execute(query, (path,))
|
||||
try:
|
||||
pathid = cursor.fetchone()[0]
|
||||
pathid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
pathid = None
|
||||
|
||||
|
@ -79,8 +75,6 @@ class Kodidb_Functions():
|
|||
|
||||
def addFile(self, filename, pathid):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idFile",
|
||||
|
@ -88,12 +82,12 @@ class Kodidb_Functions():
|
|||
"WHERE strFilename = ?",
|
||||
"AND idPath = ?"
|
||||
))
|
||||
cursor.execute(query, (filename, pathid,))
|
||||
self.cursor.execute(query, (filename, pathid,))
|
||||
try:
|
||||
fileid = cursor.fetchone()[0]
|
||||
fileid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idFile),0) from files")
|
||||
fileid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idFile),0) from files")
|
||||
fileid = self.cursor.fetchone()[0] + 1
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO files(
|
||||
|
@ -102,23 +96,21 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (fileid, filename))
|
||||
self.cursor.execute(query, (fileid, filename))
|
||||
|
||||
return fileid
|
||||
|
||||
def getFile(self, fileid):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT strFilename",
|
||||
"FROM files",
|
||||
"WHERE idFile = ?"
|
||||
))
|
||||
cursor.execute(query, (fileid,))
|
||||
self.cursor.execute(query, (fileid,))
|
||||
try:
|
||||
filename = cursor.fetchone()[0]
|
||||
filename = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
filename = ""
|
||||
|
||||
|
@ -139,8 +131,6 @@ class Kodidb_Functions():
|
|||
|
||||
def addCountries(self, kodiid, countries, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
for country in countries:
|
||||
|
@ -151,18 +141,18 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (country,))
|
||||
self.cursor.execute(query, (country,))
|
||||
|
||||
try:
|
||||
country_id = cursor.fetchone()[0]
|
||||
country_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Country entry does not exists
|
||||
cursor.execute("select coalesce(max(country_id),0) from country")
|
||||
country_id = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(country_id),0) from country")
|
||||
country_id = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO country(country_id, name) values(?, ?)"
|
||||
cursor.execute(query, (country_id, country))
|
||||
self.cursor.execute(query, (country_id, country))
|
||||
self.logMsg("Add country to media, processing: %s" % country, 2)
|
||||
|
||||
finally: # Assign country to content
|
||||
|
@ -174,7 +164,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (country_id, kodiid, mediatype))
|
||||
self.cursor.execute(query, (country_id, kodiid, mediatype))
|
||||
else:
|
||||
# Kodi Helix
|
||||
for country in countries:
|
||||
|
@ -185,18 +175,18 @@ class Kodidb_Functions():
|
|||
"WHERE strCountry = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (country,))
|
||||
self.cursor.execute(query, (country,))
|
||||
|
||||
try:
|
||||
idCountry = cursor.fetchone()[0]
|
||||
idCountry = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Country entry does not exists
|
||||
cursor.execute("select coalesce(max(idCountry),0) from country")
|
||||
idCountry = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idCountry),0) from country")
|
||||
idCountry = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO country(idCountry, strCountry) values(?, ?)"
|
||||
cursor.execute(query, (idCountry, country))
|
||||
self.cursor.execute(query, (idCountry, country))
|
||||
self.logMsg("Add country to media, processing: %s" % country, 2)
|
||||
|
||||
finally:
|
||||
|
@ -210,23 +200,19 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (idCountry, kodiid))
|
||||
self.cursor.execute(query, (idCountry, kodiid))
|
||||
|
||||
def addPeople(self, kodiid, people, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
artwork = self.artwork
|
||||
kodiversion = self.kodiversion
|
||||
|
||||
castorder = 1
|
||||
for person in people:
|
||||
|
||||
name = person['Name']
|
||||
type = person['Type']
|
||||
person_type = person['Type']
|
||||
thumb = person['imageurl']
|
||||
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
if kodiversion in (15, 16, 17):
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT actor_id",
|
||||
|
@ -234,23 +220,23 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (name,))
|
||||
self.cursor.execute(query, (name,))
|
||||
|
||||
try:
|
||||
actorid = cursor.fetchone()[0]
|
||||
actorid = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Cast entry does not exists
|
||||
cursor.execute("select coalesce(max(actor_id),0) from actor")
|
||||
actorid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(actor_id),0) from actor")
|
||||
actorid = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO actor(actor_id, name) values(?, ?)"
|
||||
cursor.execute(query, (actorid, name))
|
||||
self.cursor.execute(query, (actorid, name))
|
||||
self.logMsg("Add people to media, processing: %s" % name, 2)
|
||||
|
||||
finally:
|
||||
# Link person to content
|
||||
if "Actor" in type:
|
||||
if "Actor" in person_type:
|
||||
role = person.get('Role')
|
||||
query = (
|
||||
'''
|
||||
|
@ -260,10 +246,10 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (actorid, kodiid, mediatype, role, castorder))
|
||||
self.cursor.execute(query, (actorid, kodiid, mediatype, role, castorder))
|
||||
castorder += 1
|
||||
|
||||
elif "Director" in type:
|
||||
elif "Director" in person_type:
|
||||
query = (
|
||||
'''
|
||||
INSERT OR REPLACE INTO director_link(
|
||||
|
@ -272,9 +258,9 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
self.cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
|
||||
elif type in ("Writing", "Writer"):
|
||||
elif person_type in ("Writing", "Writer"):
|
||||
query = (
|
||||
'''
|
||||
INSERT OR REPLACE INTO writer_link(
|
||||
|
@ -283,9 +269,9 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
self.cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
|
||||
elif "Artist" in type:
|
||||
elif "Artist" in person_type:
|
||||
query = (
|
||||
'''
|
||||
INSERT OR REPLACE INTO actor_link(
|
||||
|
@ -294,7 +280,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
self.cursor.execute(query, (actorid, kodiid, mediatype))
|
||||
# Kodi Helix
|
||||
else:
|
||||
query = ' '.join((
|
||||
|
@ -304,23 +290,23 @@ class Kodidb_Functions():
|
|||
"WHERE strActor = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (name,))
|
||||
self.cursor.execute(query, (name,))
|
||||
|
||||
try:
|
||||
actorid = cursor.fetchone()[0]
|
||||
actorid = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Cast entry does not exists
|
||||
cursor.execute("select coalesce(max(idActor),0) from actors")
|
||||
actorid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idActor),0) from actors")
|
||||
actorid = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO actors(idActor, strActor) values(?, ?)"
|
||||
cursor.execute(query, (actorid, name))
|
||||
self.cursor.execute(query, (actorid, name))
|
||||
self.logMsg("Add people to media, processing: %s" % name, 2)
|
||||
|
||||
finally:
|
||||
# Link person to content
|
||||
if "Actor" in type:
|
||||
if "Actor" in person_type:
|
||||
role = person.get('Role')
|
||||
|
||||
if "movie" in mediatype:
|
||||
|
@ -352,10 +338,10 @@ class Kodidb_Functions():
|
|||
)
|
||||
else: return # Item is invalid
|
||||
|
||||
cursor.execute(query, (actorid, kodiid, role, castorder))
|
||||
self.cursor.execute(query, (actorid, kodiid, role, castorder))
|
||||
castorder += 1
|
||||
|
||||
elif "Director" in type:
|
||||
elif "Director" in person_type:
|
||||
if "movie" in mediatype:
|
||||
query = (
|
||||
'''
|
||||
|
@ -395,9 +381,9 @@ class Kodidb_Functions():
|
|||
)
|
||||
else: return # Item is invalid
|
||||
|
||||
cursor.execute(query, (actorid, kodiid))
|
||||
self.cursor.execute(query, (actorid, kodiid))
|
||||
|
||||
elif type in ("Writing", "Writer"):
|
||||
elif person_type in ("Writing", "Writer"):
|
||||
if "movie" in mediatype:
|
||||
query = (
|
||||
'''
|
||||
|
@ -418,9 +404,9 @@ class Kodidb_Functions():
|
|||
)
|
||||
else: return # Item is invalid
|
||||
|
||||
cursor.execute(query, (actorid, kodiid))
|
||||
self.cursor.execute(query, (actorid, kodiid))
|
||||
|
||||
elif "Artist" in type:
|
||||
elif "Artist" in person_type:
|
||||
query = (
|
||||
'''
|
||||
INSERT OR REPLACE INTO artistlinkmusicvideo(
|
||||
|
@ -429,20 +415,19 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (actorid, kodiid))
|
||||
self.cursor.execute(query, (actorid, kodiid))
|
||||
|
||||
# Add person image to art table
|
||||
if thumb:
|
||||
arttype = type.lower()
|
||||
arttype = person_type.lower()
|
||||
|
||||
if "writing" in arttype:
|
||||
arttype = "writer"
|
||||
|
||||
artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", cursor)
|
||||
self.artwork.addOrUpdateArt(thumb, actorid, arttype, "thumb", self.cursor)
|
||||
|
||||
def addGenres(self, kodiid, genres, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
|
@ -453,7 +438,7 @@ class Kodidb_Functions():
|
|||
"WHERE media_id = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype,))
|
||||
self.cursor.execute(query, (kodiid, mediatype,))
|
||||
|
||||
# Add genres
|
||||
for genre in genres:
|
||||
|
@ -465,18 +450,18 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (genre,))
|
||||
self.cursor.execute(query, (genre,))
|
||||
|
||||
try:
|
||||
genre_id = cursor.fetchone()[0]
|
||||
genre_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Create genre in database
|
||||
cursor.execute("select coalesce(max(genre_id),0) from genre")
|
||||
genre_id = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(genre_id),0) from genre")
|
||||
genre_id = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO genre(genre_id, name) values(?, ?)"
|
||||
cursor.execute(query, (genre_id, genre))
|
||||
self.cursor.execute(query, (genre_id, genre))
|
||||
self.logMsg("Add Genres to media, processing: %s" % genre, 2)
|
||||
|
||||
finally:
|
||||
|
@ -489,16 +474,16 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (genre_id, kodiid, mediatype))
|
||||
self.cursor.execute(query, (genre_id, kodiid, mediatype))
|
||||
else:
|
||||
# Kodi Helix
|
||||
# Delete current genres for clean slate
|
||||
if "movie" in mediatype:
|
||||
cursor.execute("DELETE FROM genrelinkmovie WHERE idMovie = ?", (kodiid,))
|
||||
self.cursor.execute("DELETE FROM genrelinkmovie WHERE idMovie = ?", (kodiid,))
|
||||
elif "tvshow" in mediatype:
|
||||
cursor.execute("DELETE FROM genrelinktvshow WHERE idShow = ?", (kodiid,))
|
||||
self.cursor.execute("DELETE FROM genrelinktvshow WHERE idShow = ?", (kodiid,))
|
||||
elif "musicvideo" in mediatype:
|
||||
cursor.execute("DELETE FROM genrelinkmusicvideo WHERE idMVideo = ?", (kodiid,))
|
||||
self.cursor.execute("DELETE FROM genrelinkmusicvideo WHERE idMVideo = ?", (kodiid,))
|
||||
|
||||
# Add genres
|
||||
for genre in genres:
|
||||
|
@ -510,18 +495,18 @@ class Kodidb_Functions():
|
|||
"WHERE strGenre = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (genre,))
|
||||
self.cursor.execute(query, (genre,))
|
||||
|
||||
try:
|
||||
idGenre = cursor.fetchone()[0]
|
||||
idGenre = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Create genre in database
|
||||
cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
idGenre = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
idGenre = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
|
||||
cursor.execute(query, (idGenre, genre))
|
||||
self.cursor.execute(query, (idGenre, genre))
|
||||
self.logMsg("Add Genres to media, processing: %s" % genre, 2)
|
||||
|
||||
finally:
|
||||
|
@ -555,16 +540,13 @@ class Kodidb_Functions():
|
|||
)
|
||||
else: return # Item is invalid
|
||||
|
||||
cursor.execute(query, (idGenre, kodiid))
|
||||
self.cursor.execute(query, (idGenre, kodiid))
|
||||
|
||||
def addStudios(self, kodiid, studios, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
kodiversion = self.kodiversion
|
||||
|
||||
for studio in studios:
|
||||
|
||||
if kodiversion in (15, 16, 17):
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -573,17 +555,17 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (studio,))
|
||||
self.cursor.execute(query, (studio,))
|
||||
try:
|
||||
studioid = cursor.fetchone()[0]
|
||||
studioid = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Studio does not exists.
|
||||
cursor.execute("select coalesce(max(studio_id),0) from studio")
|
||||
studioid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(studio_id),0) from studio")
|
||||
studioid = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO studio(studio_id, name) values(?, ?)"
|
||||
cursor.execute(query, (studioid, studio))
|
||||
self.cursor.execute(query, (studioid, studio))
|
||||
self.logMsg("Add Studios to media, processing: %s" % studio, 2)
|
||||
|
||||
finally: # Assign studio to item
|
||||
|
@ -594,7 +576,7 @@ class Kodidb_Functions():
|
|||
|
||||
VALUES (?, ?, ?)
|
||||
''')
|
||||
cursor.execute(query, (studioid, kodiid, mediatype))
|
||||
self.cursor.execute(query, (studioid, kodiid, mediatype))
|
||||
else:
|
||||
# Kodi Helix
|
||||
query = ' '.join((
|
||||
|
@ -604,17 +586,17 @@ class Kodidb_Functions():
|
|||
"WHERE strstudio = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (studio,))
|
||||
self.cursor.execute(query, (studio,))
|
||||
try:
|
||||
studioid = cursor.fetchone()[0]
|
||||
studioid = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Studio does not exists.
|
||||
cursor.execute("select coalesce(max(idstudio),0) from studio")
|
||||
studioid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idstudio),0) from studio")
|
||||
studioid = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO studio(idstudio, strstudio) values(?, ?)"
|
||||
cursor.execute(query, (studioid, studio))
|
||||
self.cursor.execute(query, (studioid, studio))
|
||||
self.logMsg("Add Studios to media, processing: %s" % studio, 2)
|
||||
|
||||
finally: # Assign studio to item
|
||||
|
@ -642,14 +624,12 @@ class Kodidb_Functions():
|
|||
INSERT OR REPLACE INTO studiolinkepisode(idstudio, idEpisode)
|
||||
VALUES (?, ?)
|
||||
''')
|
||||
cursor.execute(query, (studioid, kodiid))
|
||||
self.cursor.execute(query, (studioid, kodiid))
|
||||
|
||||
def addStreams(self, fileid, streamdetails, runtime):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
# First remove any existing entries
|
||||
cursor.execute("DELETE FROM streamdetails WHERE idFile = ?", (fileid,))
|
||||
self.cursor.execute("DELETE FROM streamdetails WHERE idFile = ?", (fileid,))
|
||||
if streamdetails:
|
||||
# Video details
|
||||
for videotrack in streamdetails['video']:
|
||||
|
@ -662,7 +642,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (fileid, 0, videotrack['codec'],
|
||||
self.cursor.execute(query, (fileid, 0, videotrack['codec'],
|
||||
videotrack['aspect'], videotrack['width'], videotrack['height'],
|
||||
runtime ,videotrack['video3DFormat']))
|
||||
|
||||
|
@ -676,7 +656,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (fileid, 1, audiotrack['codec'],
|
||||
self.cursor.execute(query, (fileid, 1, audiotrack['codec'],
|
||||
audiotrack['channels'], audiotrack['language']))
|
||||
|
||||
# Subtitles details
|
||||
|
@ -689,19 +669,17 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (fileid, 2, subtitletrack))
|
||||
self.cursor.execute(query, (fileid, 2, subtitletrack))
|
||||
|
||||
def addPlaystate(self, fileid, resume_seconds, total_seconds, playcount, dateplayed):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
# Delete existing resume point
|
||||
query = ' '.join((
|
||||
|
||||
"DELETE FROM bookmark",
|
||||
"WHERE idFile = ?"
|
||||
))
|
||||
cursor.execute(query, (fileid,))
|
||||
self.cursor.execute(query, (fileid,))
|
||||
|
||||
# Set watched count
|
||||
query = ' '.join((
|
||||
|
@ -710,12 +688,12 @@ class Kodidb_Functions():
|
|||
"SET playCount = ?, lastPlayed = ?",
|
||||
"WHERE idFile = ?"
|
||||
))
|
||||
cursor.execute(query, (playcount, dateplayed, fileid))
|
||||
self.cursor.execute(query, (playcount, dateplayed, fileid))
|
||||
|
||||
# Set the resume bookmark
|
||||
if resume_seconds:
|
||||
cursor.execute("select coalesce(max(idBookmark),0) from bookmark")
|
||||
bookmarkId = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idBookmark),0) from bookmark")
|
||||
bookmarkId = self.cursor.fetchone()[0] + 1
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO bookmark(
|
||||
|
@ -724,13 +702,11 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?, ?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (bookmarkId, fileid, resume_seconds, total_seconds,
|
||||
self.cursor.execute(query, (bookmarkId, fileid, resume_seconds, total_seconds,
|
||||
"DVDPlayer", 1))
|
||||
|
||||
def addTags(self, kodiid, tags, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
# First, delete any existing tags associated to the id
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
|
@ -740,7 +716,7 @@ class Kodidb_Functions():
|
|||
"WHERE media_id = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype))
|
||||
self.cursor.execute(query, (kodiid, mediatype))
|
||||
else:
|
||||
# Kodi Helix
|
||||
query = ' '.join((
|
||||
|
@ -749,7 +725,7 @@ class Kodidb_Functions():
|
|||
"WHERE idMedia = ?",
|
||||
"AND media_type = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype))
|
||||
self.cursor.execute(query, (kodiid, mediatype))
|
||||
|
||||
# Add tags
|
||||
self.logMsg("Adding Tags: %s" % tags, 2)
|
||||
|
@ -758,8 +734,6 @@ class Kodidb_Functions():
|
|||
|
||||
def addTag(self, kodiid, tag, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
query = ' '.join((
|
||||
|
@ -769,9 +743,9 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (tag,))
|
||||
self.cursor.execute(query, (tag,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Create the tag, because it does not exist
|
||||
|
@ -788,7 +762,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (tag_id, kodiid, mediatype))
|
||||
self.cursor.execute(query, (tag_id, kodiid, mediatype))
|
||||
else:
|
||||
# Kodi Helix
|
||||
query = ' '.join((
|
||||
|
@ -798,9 +772,9 @@ class Kodidb_Functions():
|
|||
"WHERE strTag = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (tag,))
|
||||
self.cursor.execute(query, (tag,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
# Create the tag
|
||||
|
@ -817,12 +791,10 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (tag_id, kodiid, mediatype))
|
||||
self.cursor.execute(query, (tag_id, kodiid, mediatype))
|
||||
|
||||
def createTag(self, name):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
# This will create and return the tag_id
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
|
@ -833,16 +805,16 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (name,))
|
||||
self.cursor.execute(query, (name,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(tag_id),0) from tag")
|
||||
tag_id = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(tag_id),0) from tag")
|
||||
tag_id = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO tag(tag_id, name) values(?, ?)"
|
||||
cursor.execute(query, (tag_id, name))
|
||||
self.cursor.execute(query, (tag_id, name))
|
||||
self.logMsg("Create tag_id: %s name: %s" % (tag_id, name), 2)
|
||||
else:
|
||||
# Kodi Helix
|
||||
|
@ -853,23 +825,22 @@ class Kodidb_Functions():
|
|||
"WHERE strTag = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (name,))
|
||||
self.cursor.execute(query, (name,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idTag),0) from tag")
|
||||
tag_id = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idTag),0) from tag")
|
||||
tag_id = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO tag(idTag, strTag) values(?, ?)"
|
||||
cursor.execute(query, (tag_id, name))
|
||||
self.cursor.execute(query, (tag_id, name))
|
||||
self.logMsg("Create idTag: %s name: %s" % (tag_id, name), 2)
|
||||
|
||||
return tag_id
|
||||
|
||||
def updateTag(self, oldtag, newtag, kodiid, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
self.logMsg("Updating: %s with %s for %s: %s" % (oldtag, newtag, mediatype, kodiid), 2)
|
||||
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
|
@ -883,7 +854,7 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND tag_id = ?"
|
||||
))
|
||||
cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
|
||||
self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
|
||||
except Exception as e:
|
||||
# The new tag we are going to apply already exists for this item
|
||||
# delete current tag instead
|
||||
|
@ -895,7 +866,7 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND tag_id = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype, oldtag,))
|
||||
self.cursor.execute(query, (kodiid, mediatype, oldtag,))
|
||||
else:
|
||||
# Kodi Helix
|
||||
try:
|
||||
|
@ -907,7 +878,7 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND idTag = ?"
|
||||
))
|
||||
cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
|
||||
self.cursor.execute(query, (newtag, kodiid, mediatype, oldtag,))
|
||||
except Exception as e:
|
||||
# The new tag we are going to apply already exists for this item
|
||||
# delete current tag instead
|
||||
|
@ -919,12 +890,10 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND idTag = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype, oldtag,))
|
||||
self.cursor.execute(query, (kodiid, mediatype, oldtag,))
|
||||
|
||||
def removeTag(self, kodiid, tagname, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
# Kodi Isengard, Jarvis, Krypton
|
||||
query = ' '.join((
|
||||
|
@ -934,9 +903,9 @@ class Kodidb_Functions():
|
|||
"WHERE name = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (tagname,))
|
||||
self.cursor.execute(query, (tagname,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
return
|
||||
else:
|
||||
|
@ -947,7 +916,7 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND tag_id = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype, tag_id,))
|
||||
self.cursor.execute(query, (kodiid, mediatype, tag_id,))
|
||||
else:
|
||||
# Kodi Helix
|
||||
query = ' '.join((
|
||||
|
@ -957,9 +926,9 @@ class Kodidb_Functions():
|
|||
"WHERE strTag = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (tagname,))
|
||||
self.cursor.execute(query, (tagname,))
|
||||
try:
|
||||
tag_id = cursor.fetchone()[0]
|
||||
tag_id = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
return
|
||||
else:
|
||||
|
@ -970,11 +939,10 @@ class Kodidb_Functions():
|
|||
"AND media_type = ?",
|
||||
"AND idTag = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid, mediatype, tag_id,))
|
||||
self.cursor.execute(query, (kodiid, mediatype, tag_id,))
|
||||
|
||||
def createBoxset(self, boxsetname):
|
||||
|
||||
cursor = self.cursor
|
||||
self.logMsg("Adding boxset: %s" % boxsetname, 2)
|
||||
query = ' '.join((
|
||||
|
||||
|
@ -983,16 +951,16 @@ class Kodidb_Functions():
|
|||
"WHERE strSet = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (boxsetname,))
|
||||
self.cursor.execute(query, (boxsetname,))
|
||||
try:
|
||||
setid = cursor.fetchone()[0]
|
||||
setid = self.cursor.fetchone()[0]
|
||||
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idSet),0) from sets")
|
||||
setid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idSet),0) from sets")
|
||||
setid = self.cursor.fetchone()[0] + 1
|
||||
|
||||
query = "INSERT INTO sets(idSet, strSet) values(?, ?)"
|
||||
cursor.execute(query, (setid, boxsetname))
|
||||
self.cursor.execute(query, (setid, boxsetname))
|
||||
|
||||
return setid
|
||||
|
||||
|
@ -1018,8 +986,6 @@ class Kodidb_Functions():
|
|||
|
||||
def addSeason(self, showid, seasonnumber):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idSeason",
|
||||
|
@ -1027,30 +993,28 @@ class Kodidb_Functions():
|
|||
"WHERE idShow = ?",
|
||||
"AND season = ?"
|
||||
))
|
||||
cursor.execute(query, (showid, seasonnumber,))
|
||||
self.cursor.execute(query, (showid, seasonnumber,))
|
||||
try:
|
||||
seasonid = cursor.fetchone()[0]
|
||||
seasonid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idSeason),0) from seasons")
|
||||
seasonid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idSeason),0) from seasons")
|
||||
seasonid = self.cursor.fetchone()[0] + 1
|
||||
query = "INSERT INTO seasons(idSeason, idShow, season) values(?, ?, ?)"
|
||||
cursor.execute(query, (seasonid, showid, seasonnumber))
|
||||
self.cursor.execute(query, (seasonid, showid, seasonnumber))
|
||||
|
||||
return seasonid
|
||||
|
||||
def addArtist(self, name, musicbrainz):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idArtist, strArtist",
|
||||
"FROM artist",
|
||||
"WHERE strMusicBrainzArtistID = ?"
|
||||
))
|
||||
cursor.execute(query, (musicbrainz,))
|
||||
self.cursor.execute(query, (musicbrainz,))
|
||||
try:
|
||||
result = cursor.fetchone()
|
||||
result = self.cursor.fetchone()
|
||||
artistid = result[0]
|
||||
artistname = result[1]
|
||||
|
||||
|
@ -1063,12 +1027,12 @@ class Kodidb_Functions():
|
|||
"WHERE strArtist = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (name,))
|
||||
self.cursor.execute(query, (name,))
|
||||
try:
|
||||
artistid = cursor.fetchone()[0]
|
||||
artistid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
cursor.execute("select coalesce(max(idArtist),0) from artist")
|
||||
artistid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idArtist),0) from artist")
|
||||
artistid = self.cursor.fetchone()[0] + 1
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO artist(idArtist, strArtist, strMusicBrainzArtistID)
|
||||
|
@ -1076,33 +1040,30 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (artistid, name, musicbrainz))
|
||||
self.cursor.execute(query, (artistid, name, musicbrainz))
|
||||
else:
|
||||
if artistname != name:
|
||||
query = "UPDATE artist SET strArtist = ? WHERE idArtist = ?"
|
||||
cursor.execute(query, (name, artistid,))
|
||||
self.cursor.execute(query, (name, artistid,))
|
||||
|
||||
return artistid
|
||||
|
||||
def addAlbum(self, name, musicbrainz):
|
||||
|
||||
kodiversion = self.kodiversion
|
||||
cursor = self.cursor
|
||||
|
||||
query = ' '.join((
|
||||
|
||||
"SELECT idAlbum",
|
||||
"FROM album",
|
||||
"WHERE strMusicBrainzAlbumID = ?"
|
||||
))
|
||||
cursor.execute(query, (musicbrainz,))
|
||||
self.cursor.execute(query, (musicbrainz,))
|
||||
try:
|
||||
albumid = cursor.fetchone()[0]
|
||||
albumid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the album
|
||||
cursor.execute("select coalesce(max(idAlbum),0) from album")
|
||||
albumid = cursor.fetchone()[0] + 1
|
||||
if kodiversion in (15, 16, 17):
|
||||
self.cursor.execute("select coalesce(max(idAlbum),0) from album")
|
||||
albumid = self.cursor.fetchone()[0] + 1
|
||||
if self.kodiversion in (15, 16, 17):
|
||||
query = (
|
||||
'''
|
||||
INSERT INTO album(idAlbum, strAlbum, strMusicBrainzAlbumID, strReleaseType)
|
||||
|
@ -1110,7 +1071,7 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (albumid, name, musicbrainz, "album"))
|
||||
self.cursor.execute(query, (albumid, name, musicbrainz, "album"))
|
||||
else: # Helix
|
||||
query = (
|
||||
'''
|
||||
|
@ -1119,14 +1080,12 @@ class Kodidb_Functions():
|
|||
VALUES (?, ?, ?)
|
||||
'''
|
||||
)
|
||||
cursor.execute(query, (albumid, name, musicbrainz))
|
||||
self.cursor.execute(query, (albumid, name, musicbrainz))
|
||||
|
||||
return albumid
|
||||
|
||||
def addMusicGenres(self, kodiid, genres, mediatype):
|
||||
|
||||
cursor = self.cursor
|
||||
|
||||
if mediatype == "album":
|
||||
|
||||
# Delete current genres for clean slate
|
||||
|
@ -1135,7 +1094,7 @@ class Kodidb_Functions():
|
|||
"DELETE FROM album_genre",
|
||||
"WHERE idAlbum = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid,))
|
||||
self.cursor.execute(query, (kodiid,))
|
||||
|
||||
for genre in genres:
|
||||
query = ' '.join((
|
||||
|
@ -1145,18 +1104,18 @@ class Kodidb_Functions():
|
|||
"WHERE strGenre = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (genre,))
|
||||
self.cursor.execute(query, (genre,))
|
||||
try:
|
||||
genreid = cursor.fetchone()[0]
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
genreid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
|
||||
cursor.execute(query, (genreid, genre))
|
||||
self.cursor.execute(query, (genreid, genre))
|
||||
|
||||
query = "INSERT OR REPLACE INTO album_genre(idGenre, idAlbum) values(?, ?)"
|
||||
cursor.execute(query, (genreid, kodiid))
|
||||
self.cursor.execute(query, (genreid, kodiid))
|
||||
|
||||
elif mediatype == "song":
|
||||
|
||||
|
@ -1166,7 +1125,7 @@ class Kodidb_Functions():
|
|||
"DELETE FROM song_genre",
|
||||
"WHERE idSong = ?"
|
||||
))
|
||||
cursor.execute(query, (kodiid,))
|
||||
self.cursor.execute(query, (kodiid,))
|
||||
|
||||
for genre in genres:
|
||||
query = ' '.join((
|
||||
|
@ -1176,15 +1135,15 @@ class Kodidb_Functions():
|
|||
"WHERE strGenre = ?",
|
||||
"COLLATE NOCASE"
|
||||
))
|
||||
cursor.execute(query, (genre,))
|
||||
self.cursor.execute(query, (genre,))
|
||||
try:
|
||||
genreid = cursor.fetchone()[0]
|
||||
genreid = self.cursor.fetchone()[0]
|
||||
except TypeError:
|
||||
# Create the genre
|
||||
cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
genreid = cursor.fetchone()[0] + 1
|
||||
self.cursor.execute("select coalesce(max(idGenre),0) from genre")
|
||||
genreid = self.cursor.fetchone()[0] + 1
|
||||
query = "INSERT INTO genre(idGenre, strGenre) values(?, ?)"
|
||||
cursor.execute(query, (genreid, genre))
|
||||
self.cursor.execute(query, (genreid, genre))
|
||||
|
||||
query = "INSERT OR REPLACE INTO song_genre(idGenre, idSong) values(?, ?)"
|
||||
cursor.execute(query, (genreid, kodiid))
|
||||
self.cursor.execute(query, (genreid, kodiid))
|
|
@ -82,17 +82,17 @@ class KodiMonitor(xbmc.Monitor):
|
|||
item = data.get('item')
|
||||
try:
|
||||
kodiid = item['id']
|
||||
type = item['type']
|
||||
item_type = item['type']
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Item is invalid for playstate update.", 1)
|
||||
else:
|
||||
if ((utils.settings('useDirectPaths') == "1" and not type == "song") or
|
||||
(type == "song" and utils.settings('enableMusic') == "true")):
|
||||
if ((utils.settings('useDirectPaths') == "1" and not item_type == "song") or
|
||||
(item_type == "song" and utils.settings('enableMusic') == "true")):
|
||||
# Set up properties for player
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
|
||||
try:
|
||||
itemid = emby_dbitem[0]
|
||||
except TypeError:
|
||||
|
@ -114,7 +114,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
listItem = xbmcgui.ListItem()
|
||||
playback = pbutils.PlaybackUtils(result)
|
||||
|
||||
if type == "song" and utils.settings('streamMusic') == "true":
|
||||
if item_type == "song" and utils.settings('streamMusic') == "true":
|
||||
utils.window('emby_%s.playmethod' % playurl,
|
||||
value="DirectStream")
|
||||
else:
|
||||
|
@ -132,7 +132,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
item = data.get('item')
|
||||
try:
|
||||
kodiid = item['id']
|
||||
type = item['type']
|
||||
item_type = item['type']
|
||||
except (KeyError, TypeError):
|
||||
self.logMsg("Item is invalid for playstate update.", 1)
|
||||
else:
|
||||
|
@ -140,7 +140,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
embyconn = utils.kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, type)
|
||||
emby_dbitem = emby_db.getItem_byKodiId(kodiid, item_type)
|
||||
try:
|
||||
itemid = emby_dbitem[0]
|
||||
except TypeError:
|
||||
|
@ -154,10 +154,10 @@ class KodiMonitor(xbmc.Monitor):
|
|||
# notify the server
|
||||
url = "{server}/emby/Users/{UserId}/PlayedItems/%s?format=json" % itemid
|
||||
if playcount != 0:
|
||||
doUtils.downloadUrl(url, type="POST")
|
||||
doUtils.downloadUrl(url, action_type="POST")
|
||||
self.logMsg("Mark as watched for itemid: %s" % itemid, 1)
|
||||
else:
|
||||
doUtils.downloadUrl(url, type="DELETE")
|
||||
doUtils.downloadUrl(url, action_type="DELETE")
|
||||
self.logMsg("Mark as unwatched for itemid: %s" % itemid, 1)
|
||||
finally:
|
||||
embycursor.close()
|
||||
|
@ -195,7 +195,7 @@ class KodiMonitor(xbmc.Monitor):
|
|||
|
||||
url = "{server}/emby/Items/%s?format=json" % itemid
|
||||
self.logMsg("Deleting request: %s" % itemid)
|
||||
doUtils.downloadUrl(url, type="DELETE")
|
||||
doUtils.downloadUrl(url, action_type="DELETE")
|
||||
finally:
|
||||
embycursor.close()'''
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ class LibrarySync(threading.Thread):
|
|||
if plugin['Name'] == "Emby.Kodi Sync Queue":
|
||||
self.logMsg("Found server plugin.", 2)
|
||||
completed = self.fastSync()
|
||||
break
|
||||
|
||||
if not completed:
|
||||
# Fast sync failed or server plugin is not found
|
||||
|
@ -102,20 +103,15 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def fastSync(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
doUtils = self.doUtils
|
||||
|
||||
lastSync = utils.settings('LastIncrementalSync')
|
||||
if not lastSync:
|
||||
lastSync = "2010-01-01T00:00:00Z"
|
||||
|
||||
lastSyncTime = utils.convertdate(lastSync)
|
||||
log("Last sync run: %s" % lastSyncTime, 1)
|
||||
self.logMsg("Last sync run: %s" % lastSyncTime, 1)
|
||||
|
||||
# get server RetentionDateTime
|
||||
url = "{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json"
|
||||
result = doUtils(url)
|
||||
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
|
||||
retention_time = "2010-01-01T00:00:00Z"
|
||||
if result and result.get('RetentionDateTime'):
|
||||
retention_time = result['RetentionDateTime']
|
||||
|
@ -129,16 +125,15 @@ class LibrarySync(threading.Thread):
|
|||
'''
|
||||
|
||||
retention_time = utils.convertdate(retention_time)
|
||||
log("RetentionDateTime: %s" % retention_time, 1)
|
||||
self.logMsg("RetentionDateTime: %s" % retention_time, 1)
|
||||
|
||||
# if last sync before retention time do a full sync
|
||||
if retention_time > lastSyncTime:
|
||||
log("Fast sync server retention insufficient, fall back to full sync", 1)
|
||||
self.logMsg("Fast sync server retention insufficient, fall back to full sync", 1)
|
||||
return False
|
||||
|
||||
url = "{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json"
|
||||
params = {'LastUpdateDT': lastSync}
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/{UserId}/GetItems?format=json", parameters=params)
|
||||
|
||||
try:
|
||||
processlist = {
|
||||
|
@ -150,11 +145,11 @@ class LibrarySync(threading.Thread):
|
|||
}
|
||||
|
||||
except (KeyError, TypeError):
|
||||
log("Failed to retrieve latest updates using fast sync.", 1)
|
||||
self.logMsg("Failed to retrieve latest updates using fast sync.", 1)
|
||||
return False
|
||||
|
||||
else:
|
||||
log("Fast sync changes: %s" % result, 1)
|
||||
self.logMsg("Fast sync changes: %s" % result, 1)
|
||||
for action in processlist:
|
||||
self.triage_items(action, processlist[action])
|
||||
|
||||
|
@ -162,26 +157,24 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def saveLastSync(self):
|
||||
|
||||
log = self.logMsg
|
||||
# Save last sync time
|
||||
overlap = 2
|
||||
|
||||
url = "{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json"
|
||||
result = self.doUtils(url)
|
||||
result = self.doUtils("{server}/emby/Emby.Kodi.SyncQueue/GetServerDateTime?format=json")
|
||||
try: # datetime fails when used more than once, TypeError
|
||||
server_time = result['ServerDateTime']
|
||||
server_time = utils.convertdate(server_time)
|
||||
|
||||
except Exception as e:
|
||||
# If the server plugin is not installed or an error happened.
|
||||
log("An exception occurred: %s" % e, 1)
|
||||
self.logMsg("An exception occurred: %s" % e, 1)
|
||||
time_now = datetime.utcnow()-timedelta(minutes=overlap)
|
||||
lastSync = time_now.strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
log("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
|
||||
self.logMsg("New sync time: client time -%s min: %s" % (overlap, lastSync), 1)
|
||||
|
||||
else:
|
||||
lastSync = (server_time - timedelta(minutes=overlap)).strftime('%Y-%m-%dT%H:%M:%SZ')
|
||||
log("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
|
||||
self.logMsg("New sync time: server time -%s min: %s" % (overlap, lastSync), 1)
|
||||
|
||||
finally:
|
||||
utils.settings('LastIncrementalSync', value=lastSync)
|
||||
|
@ -197,35 +190,32 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def dbCommit(self, connection):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
# Central commit, verifies if Kodi database update is running
|
||||
kodidb_scan = window('emby_kodiScan') == "true"
|
||||
|
||||
while kodidb_scan:
|
||||
|
||||
log("Kodi scan is running. Waiting...", 1)
|
||||
self.logMsg("Kodi scan is running. Waiting...", 1)
|
||||
kodidb_scan = window('emby_kodiScan') == "true"
|
||||
|
||||
if self.shouldStop():
|
||||
log("Commit unsuccessful. Sync terminated.", 1)
|
||||
self.logMsg("Commit unsuccessful. Sync terminated.", 1)
|
||||
break
|
||||
|
||||
if self.monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
log("Commit unsuccessful.", 1)
|
||||
self.logMsg("Commit unsuccessful.", 1)
|
||||
break
|
||||
else:
|
||||
connection.commit()
|
||||
log("Commit successful.", 1)
|
||||
self.logMsg("Commit successful.", 1)
|
||||
|
||||
def fullSync(self, manualrun=False, repair=False, forceddialog=False):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
# Only run once when first setting up. Can be run manually.
|
||||
emby = self.emby
|
||||
music_enabled = utils.settings('enableMusic') == "true"
|
||||
|
||||
xbmc.executebuiltin('InhibitIdleShutdown(true)')
|
||||
|
@ -294,7 +284,7 @@ class LibrarySync(threading.Thread):
|
|||
self.dbCommit(kodiconn)
|
||||
embyconn.commit()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
log("SyncDatabase (finished %s in: %s)"
|
||||
self.logMsg("SyncDatabase (finished %s in: %s)"
|
||||
% (itemtype, str(elapsedTime).split('.')[0]), 1)
|
||||
else:
|
||||
# Close the Kodi cursor
|
||||
|
@ -322,7 +312,7 @@ class LibrarySync(threading.Thread):
|
|||
musicconn.commit()
|
||||
embyconn.commit()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
log("SyncDatabase (finished music in: %s)"
|
||||
self.logMsg("SyncDatabase (finished music in: %s)"
|
||||
% (str(elapsedTime).split('.')[0]), 1)
|
||||
musiccursor.close()
|
||||
|
||||
|
@ -369,19 +359,15 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def maintainViews(self, embycursor, kodicursor):
|
||||
|
||||
log = self.logMsg
|
||||
# Compare the views to emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
kodi_db = kodidb.Kodidb_Functions(kodicursor)
|
||||
doUtils = self.doUtils
|
||||
vnodes = self.vnodes
|
||||
|
||||
# Get views
|
||||
url = "{server}/emby/Users/{UserId}/Views?format=json"
|
||||
result = doUtils(url)
|
||||
result = self.doUtils("{server}/emby/Users/{UserId}/Views?format=json")
|
||||
grouped_views = result['Items']
|
||||
ordered_views = emby.getViews(sortedlist=True)
|
||||
ordered_views = self.emby.getViews(sortedlist=True)
|
||||
all_views = []
|
||||
sorted_views = []
|
||||
for view in ordered_views:
|
||||
|
@ -392,10 +378,10 @@ class LibrarySync(threading.Thread):
|
|||
if view['type'] == "mixed":
|
||||
sorted_views.append(view['name'])
|
||||
sorted_views.append(view['name'])
|
||||
log("Sorted views: %s" % sorted_views, 1)
|
||||
self.logMsg("Sorted views: %s" % sorted_views, 1)
|
||||
|
||||
# total nodes for window properties
|
||||
vnodes.clearProperties()
|
||||
self.vnodes.clearProperties()
|
||||
totalnodes = len(sorted_views) + 0
|
||||
|
||||
current_views = emby_db.getViews()
|
||||
|
@ -409,13 +395,12 @@ class LibrarySync(threading.Thread):
|
|||
'music': "Audio",
|
||||
'photos': "Photo"
|
||||
}
|
||||
mediatypes = ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']
|
||||
for mediatype in mediatypes:
|
||||
for mediatype in ['movies', 'tvshows', 'musicvideos', 'homevideos', 'music', 'photos']:
|
||||
|
||||
nodes = [] # Prevent duplicate for nodes of the same type
|
||||
playlists = [] # Prevent duplicate for playlists of the same type
|
||||
# Get media folders from server
|
||||
folders = emby.getViews(mediatype, root=True)
|
||||
folders = self.emby.getViews(mediatype, root=True)
|
||||
for folder in folders:
|
||||
|
||||
folderid = folder['id']
|
||||
|
@ -424,14 +409,13 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
if foldername not in all_views:
|
||||
# Media folders are grouped into userview
|
||||
url = "{server}/emby/Users/{UserId}/Items?format=json"
|
||||
params = {
|
||||
'ParentId': folderid,
|
||||
'Recursive': True,
|
||||
'Limit': 1,
|
||||
'IncludeItemTypes': emby_mediatypes[mediatype]
|
||||
} # Get one item from server using the folderid
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
|
||||
try:
|
||||
verifyitem = result['Items'][0]['Id']
|
||||
except (TypeError, IndexError):
|
||||
|
@ -444,16 +428,16 @@ class LibrarySync(threading.Thread):
|
|||
if (grouped_view['Type'] == "UserView" and
|
||||
grouped_view.get('CollectionType') == mediatype):
|
||||
# Take the userview, and validate the item belong to the view
|
||||
if emby.verifyView(grouped_view['Id'], verifyitem):
|
||||
if self.emby.verifyView(grouped_view['Id'], verifyitem):
|
||||
# Take the name of the userview
|
||||
log("Found corresponding view: %s %s"
|
||||
self.logMsg("Found corresponding view: %s %s"
|
||||
% (grouped_view['Name'], grouped_view['Id']), 1)
|
||||
foldername = grouped_view['Name']
|
||||
break
|
||||
else:
|
||||
# Unable to find a match, add the name to our sorted_view list
|
||||
sorted_views.append(foldername)
|
||||
log("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
|
||||
self.logMsg("Couldn't find corresponding grouped view: %s" % sorted_views, 1)
|
||||
|
||||
# Failsafe
|
||||
try:
|
||||
|
@ -469,7 +453,7 @@ class LibrarySync(threading.Thread):
|
|||
current_tagid = view[2]
|
||||
|
||||
except TypeError:
|
||||
log("Creating viewid: %s in Emby database." % folderid, 1)
|
||||
self.logMsg("Creating viewid: %s in Emby database." % folderid, 1)
|
||||
tagid = kodi_db.createTag(foldername)
|
||||
# Create playlist for the video library
|
||||
if (foldername not in playlists and
|
||||
|
@ -478,7 +462,7 @@ class LibrarySync(threading.Thread):
|
|||
playlists.append(foldername)
|
||||
# Create the video node
|
||||
if foldername not in nodes and mediatype not in ("musicvideos", "music"):
|
||||
vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype,
|
||||
self.vnodes.viewNode(sorted_views.index(foldername), foldername, mediatype,
|
||||
viewtype, folderid)
|
||||
if viewtype == "mixed": # Change the value
|
||||
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
|
||||
|
@ -488,7 +472,7 @@ class LibrarySync(threading.Thread):
|
|||
emby_db.addView(folderid, foldername, viewtype, tagid)
|
||||
|
||||
else:
|
||||
log(' '.join((
|
||||
self.logMsg(' '.join((
|
||||
|
||||
"Found viewid: %s" % folderid,
|
||||
"viewname: %s" % current_viewname,
|
||||
|
@ -504,7 +488,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
# View was modified, update with latest info
|
||||
if current_viewname != foldername:
|
||||
log("viewid: %s new viewname: %s" % (folderid, foldername), 1)
|
||||
self.logMsg("viewid: %s new viewname: %s" % (folderid, foldername), 1)
|
||||
tagid = kodi_db.createTag(foldername)
|
||||
|
||||
# Update view with new info
|
||||
|
@ -518,7 +502,7 @@ class LibrarySync(threading.Thread):
|
|||
mediatype, current_viewname, folderid, current_viewtype, True)
|
||||
# Delete video node
|
||||
if mediatype != "musicvideos":
|
||||
vnodes.viewNode(
|
||||
self.vnodes.viewNode(
|
||||
indexnumber=None,
|
||||
tagname=current_viewname,
|
||||
mediatype=mediatype,
|
||||
|
@ -532,7 +516,7 @@ class LibrarySync(threading.Thread):
|
|||
playlists.append(foldername)
|
||||
# Add new video node
|
||||
if foldername not in nodes and mediatype != "musicvideos":
|
||||
vnodes.viewNode(sorted_views.index(foldername), foldername,
|
||||
self.vnodes.viewNode(sorted_views.index(foldername), foldername,
|
||||
mediatype, viewtype, folderid)
|
||||
if viewtype == "mixed": # Change the value
|
||||
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
|
||||
|
@ -554,7 +538,7 @@ class LibrarySync(threading.Thread):
|
|||
playlists.append(foldername)
|
||||
# Create the video node if not already exists
|
||||
if foldername not in nodes and mediatype != "musicvideos":
|
||||
vnodes.viewNode(sorted_views.index(foldername), foldername,
|
||||
self.vnodes.viewNode(sorted_views.index(foldername), foldername,
|
||||
mediatype, viewtype, folderid)
|
||||
if viewtype == "mixed": # Change the value
|
||||
sorted_views[sorted_views.index(foldername)] = "%ss" % foldername
|
||||
|
@ -562,32 +546,30 @@ class LibrarySync(threading.Thread):
|
|||
totalnodes += 1
|
||||
else:
|
||||
# Add video nodes listings
|
||||
vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites")
|
||||
self.vnodes.singleNode(totalnodes, "Favorite movies", "movies", "favourites")
|
||||
totalnodes += 1
|
||||
vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites")
|
||||
self.vnodes.singleNode(totalnodes, "Favorite tvshows", "tvshows", "favourites")
|
||||
totalnodes += 1
|
||||
vnodes.singleNode(totalnodes, "channels", "movies", "channels")
|
||||
self.vnodes.singleNode(totalnodes, "channels", "movies", "channels")
|
||||
totalnodes += 1
|
||||
# Save total
|
||||
utils.window('Emby.nodes.total', str(totalnodes))
|
||||
|
||||
# Remove any old referenced views
|
||||
log("Removing views: %s" % current_views, 1)
|
||||
self.logMsg("Removing views: %s" % current_views, 1)
|
||||
for view in current_views:
|
||||
emby_db.removeView(view)
|
||||
|
||||
def movies(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
# Get movies from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
movies = itemtypes.Movies(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('movies')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
##### PROCESS MOVIES #####
|
||||
for view in views:
|
||||
|
@ -596,21 +578,18 @@ class LibrarySync(threading.Thread):
|
|||
return False
|
||||
|
||||
# Get items per view
|
||||
viewId = view['id']
|
||||
viewName = view['name']
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (lang(33017), viewName))
|
||||
message="%s %s..." % (lang(33017), view['name']))
|
||||
|
||||
# Initial or repair sync
|
||||
all_embymovies = emby.getMovies(viewId, dialog=pdialog)
|
||||
all_embymovies = self.emby.getMovies(view['id'], dialog=pdialog)
|
||||
total = all_embymovies['TotalRecordCount']
|
||||
embymovies = all_embymovies['Items']
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||
pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
|
||||
|
||||
count = 0
|
||||
for embymovie in embymovies:
|
||||
|
@ -623,16 +602,16 @@ class LibrarySync(threading.Thread):
|
|||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
count += 1
|
||||
movies.add_update(embymovie, viewName, viewId)
|
||||
movies.add_update(embymovie, view['name'], view['id'])
|
||||
else:
|
||||
log("Movies finished.", 2)
|
||||
self.logMsg("Movies finished.", 2)
|
||||
|
||||
|
||||
##### PROCESS BOXSETS #####
|
||||
if pdialog:
|
||||
pdialog.update(heading="Emby for Kodi", message=lang(33018))
|
||||
|
||||
boxsets = emby.getBoxset(dialog=pdialog)
|
||||
boxsets = self.emby.getBoxset(dialog=pdialog)
|
||||
total = boxsets['TotalRecordCount']
|
||||
embyboxsets = boxsets['Items']
|
||||
|
||||
|
@ -652,20 +631,18 @@ class LibrarySync(threading.Thread):
|
|||
count += 1
|
||||
movies.add_updateBoxset(boxset)
|
||||
else:
|
||||
log("Boxsets finished.", 2)
|
||||
self.logMsg("Boxsets finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
def musicvideos(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
# Get musicvideos from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('musicvideos')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
for view in views:
|
||||
|
||||
|
@ -682,7 +659,7 @@ class LibrarySync(threading.Thread):
|
|||
message="%s %s..." % (utils.language(33019), viewName))
|
||||
|
||||
# Initial or repair sync
|
||||
all_embymvideos = emby.getMusicVideos(viewId, dialog=pdialog)
|
||||
all_embymvideos = self.emby.getMusicVideos(viewId, dialog=pdialog)
|
||||
total = all_embymvideos['TotalRecordCount']
|
||||
embymvideos = all_embymvideos['Items']
|
||||
|
||||
|
@ -702,21 +679,19 @@ class LibrarySync(threading.Thread):
|
|||
count += 1
|
||||
mvideos.add_update(embymvideo, viewName, viewId)
|
||||
else:
|
||||
log("MusicVideos finished.", 2)
|
||||
self.logMsg("MusicVideos finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
def tvshows(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
# Get shows from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
tvshows = itemtypes.TVShows(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('tvshows')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
for view in views:
|
||||
|
||||
|
@ -724,20 +699,17 @@ class LibrarySync(threading.Thread):
|
|||
return False
|
||||
|
||||
# Get items per view
|
||||
viewId = view['id']
|
||||
viewName = view['name']
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33020), viewName))
|
||||
message="%s %s..." % (utils.language(33020), view['name']))
|
||||
|
||||
all_embytvshows = emby.getShows(viewId, dialog=pdialog)
|
||||
all_embytvshows = self.emby.getShows(view['id'], dialog=pdialog)
|
||||
total = all_embytvshows['TotalRecordCount']
|
||||
embytvshows = all_embytvshows['Items']
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(heading="Processing %s / %s items" % (viewName, total))
|
||||
pdialog.update(heading="Processing %s / %s items" % (view['name'], total))
|
||||
|
||||
count = 0
|
||||
for embytvshow in embytvshows:
|
||||
|
@ -745,16 +717,15 @@ class LibrarySync(threading.Thread):
|
|||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
itemid = embytvshow['Id']
|
||||
title = embytvshow['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
count += 1
|
||||
tvshows.add_update(embytvshow, viewName, viewId)
|
||||
tvshows.add_update(embytvshow, view['name'], view['id'])
|
||||
|
||||
# Process episodes
|
||||
all_episodes = emby.getEpisodesbyShow(itemid)
|
||||
all_episodes = self.emby.getEpisodesbyShow(embytvshow['Id'])
|
||||
for episode in all_episodes['Items']:
|
||||
|
||||
# Process individual show
|
||||
|
@ -766,24 +737,22 @@ class LibrarySync(threading.Thread):
|
|||
pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
|
||||
tvshows.add_updateEpisode(episode)
|
||||
else:
|
||||
log("TVShows finished.", 2)
|
||||
self.logMsg("TVShows finished.", 2)
|
||||
|
||||
return True
|
||||
|
||||
def music(self, embycursor, kodicursor, pdialog):
|
||||
# Get music from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
music = itemtypes.Music(embycursor, kodicursor)
|
||||
|
||||
process = {
|
||||
|
||||
'artists': [emby.getArtists, music.add_updateArtist],
|
||||
'albums': [emby.getAlbums, music.add_updateAlbum],
|
||||
'songs': [emby.getSongs, music.add_updateSong]
|
||||
'artists': [self.emby.getArtists, music.add_updateArtist],
|
||||
'albums': [self.emby.getAlbums, music.add_updateAlbum],
|
||||
'songs': [self.emby.getSongs, music.add_updateSong]
|
||||
}
|
||||
types = ['artists', 'albums', 'songs']
|
||||
for itemtype in types:
|
||||
for itemtype in ['artists', 'albums', 'songs']:
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(
|
||||
|
@ -802,11 +771,9 @@ class LibrarySync(threading.Thread):
|
|||
# Process individual item
|
||||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = embyitem['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=embyitem['Name'])
|
||||
count += 1
|
||||
|
||||
process[itemtype][1](embyitem)
|
||||
|
@ -837,13 +804,10 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def incrementalSync(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
kodiconn = utils.kodiSQL('video')
|
||||
kodicursor = kodiconn.cursor()
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
pDialog = None
|
||||
update_embydb = False
|
||||
|
@ -867,28 +831,27 @@ class LibrarySync(threading.Thread):
|
|||
'userdata': self.userdataItems,
|
||||
'remove': self.removeItems
|
||||
}
|
||||
types = ['added', 'update', 'userdata', 'remove']
|
||||
for type in types:
|
||||
for process_type in ['added', 'update', 'userdata', 'remove']:
|
||||
|
||||
if process[type] and utils.window('emby_kodiScan') != "true":
|
||||
if process[process_type] and utils.window('emby_kodiScan') != "true":
|
||||
|
||||
listItems = list(process[type])
|
||||
del process[type][:] # Reset class list
|
||||
listItems = list(process[process_type])
|
||||
del process[process_type][:] # Reset class list
|
||||
|
||||
items_process = itemtypes.Items(embycursor, kodicursor)
|
||||
update = False
|
||||
|
||||
# Prepare items according to process type
|
||||
if type == "added":
|
||||
items = emby.sortby_mediatype(listItems)
|
||||
# Prepare items according to process process_type
|
||||
if process_type == "added":
|
||||
items = self.emby.sortby_mediatype(listItems)
|
||||
|
||||
elif type in ("userdata", "remove"):
|
||||
elif process_type in ("userdata", "remove"):
|
||||
items = emby_db.sortby_mediaType(listItems, unsorted=False)
|
||||
|
||||
else:
|
||||
items = emby_db.sortby_mediaType(listItems)
|
||||
if items.get('Unsorted'):
|
||||
sorted_items = emby.sortby_mediatype(items['Unsorted'])
|
||||
sorted_items = self.emby.sortby_mediatype(items['Unsorted'])
|
||||
doupdate = items_process.itemsbyId(sorted_items, "added", pDialog)
|
||||
if doupdate:
|
||||
embyupdate, kodiupdate_video = doupdate
|
||||
|
@ -898,7 +861,7 @@ class LibrarySync(threading.Thread):
|
|||
self.forceLibraryUpdate = True
|
||||
del items['Unsorted']
|
||||
|
||||
doupdate = items_process.itemsbyId(items, type, pDialog)
|
||||
doupdate = items_process.itemsbyId(items, process_type, pDialog)
|
||||
if doupdate:
|
||||
embyupdate, kodiupdate_video = doupdate
|
||||
if embyupdate:
|
||||
|
@ -908,7 +871,7 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
if update_embydb:
|
||||
update_embydb = False
|
||||
log("Updating emby database.", 1)
|
||||
self.logMsg("Updating emby database.", 1)
|
||||
embyconn.commit()
|
||||
self.saveLastSync()
|
||||
|
||||
|
@ -917,7 +880,7 @@ class LibrarySync(threading.Thread):
|
|||
self.forceLibraryUpdate = False
|
||||
self.dbCommit(kodiconn)
|
||||
|
||||
log("Updating video library.", 1)
|
||||
self.logMsg("Updating video library.", 1)
|
||||
utils.window('emby_kodiScan', value="true")
|
||||
xbmc.executebuiltin('UpdateLibrary(video)')
|
||||
|
||||
|
@ -959,23 +922,21 @@ class LibrarySync(threading.Thread):
|
|||
|
||||
def run_internal(self):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
dialog = xbmcgui.Dialog()
|
||||
|
||||
startupComplete = False
|
||||
monitor = self.monitor
|
||||
|
||||
log("---===### Starting LibrarySync ###===---", 0)
|
||||
self.logMsg("---===### Starting LibrarySync ###===---", 0)
|
||||
|
||||
while not monitor.abortRequested():
|
||||
while not self.monitor.abortRequested():
|
||||
|
||||
# In the event the server goes offline
|
||||
while self.suspend_thread:
|
||||
# Set in service.py
|
||||
if monitor.waitForAbort(5):
|
||||
if self.monitor.waitForAbort(5):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
|
@ -986,12 +947,12 @@ class LibrarySync(threading.Thread):
|
|||
uptoDate = self.compareDBVersion(currentVersion, minVersion)
|
||||
|
||||
if not uptoDate:
|
||||
log("Database version out of date: %s minimum version required: %s"
|
||||
self.logMsg("Database version out of date: %s minimum version required: %s"
|
||||
% (currentVersion, minVersion), 0)
|
||||
|
||||
resp = dialog.yesno("Emby for Kodi", lang(33022))
|
||||
if not resp:
|
||||
log("Database version is out of date! USER IGNORED!", 0)
|
||||
self.logMsg("Database version is out of date! USER IGNORED!", 0)
|
||||
dialog.ok("Emby for Kodi", lang(33023))
|
||||
else:
|
||||
utils.reset()
|
||||
|
@ -1006,7 +967,7 @@ class LibrarySync(threading.Thread):
|
|||
videoDb = utils.getKodiVideoDBPath()
|
||||
if not xbmcvfs.exists(videoDb):
|
||||
# Database does not exists
|
||||
log(
|
||||
self.logMsg(
|
||||
"The current Kodi version is incompatible "
|
||||
"with the Emby for Kodi add-on. Please visit "
|
||||
"https://github.com/MediaBrowser/Emby.Kodi/wiki "
|
||||
|
@ -1018,12 +979,12 @@ class LibrarySync(threading.Thread):
|
|||
break
|
||||
|
||||
# Run start up sync
|
||||
log("Database version: %s" % settings('dbCreatedWithVersion'), 0)
|
||||
log("SyncDatabase (started)", 1)
|
||||
self.logMsg("Database version: %s" % settings('dbCreatedWithVersion'), 0)
|
||||
self.logMsg("SyncDatabase (started)", 1)
|
||||
startTime = datetime.now()
|
||||
librarySync = self.startSync()
|
||||
elapsedTime = datetime.now() - startTime
|
||||
log("SyncDatabase (finished in: %s) %s"
|
||||
self.logMsg("SyncDatabase (finished in: %s) %s"
|
||||
% (str(elapsedTime).split('.')[0], librarySync), 1)
|
||||
# Only try the initial sync once per kodi session regardless
|
||||
# This will prevent an infinite loop in case something goes wrong.
|
||||
|
@ -1038,20 +999,20 @@ class LibrarySync(threading.Thread):
|
|||
# Set in kodimonitor.py
|
||||
window('emby_onWake', clear=True)
|
||||
if window('emby_syncRunning') != "true":
|
||||
log("SyncDatabase onWake (started)", 0)
|
||||
self.logMsg("SyncDatabase onWake (started)", 0)
|
||||
librarySync = self.startSync()
|
||||
log("SyncDatabase onWake (finished) %s" % librarySync, 0)
|
||||
self.logMsg("SyncDatabase onWake (finished) %s" % librarySync, 0)
|
||||
|
||||
if self.stop_thread:
|
||||
# Set in service.py
|
||||
log("Service terminated thread.", 2)
|
||||
self.logMsg("Service terminated thread.", 2)
|
||||
break
|
||||
|
||||
if monitor.waitForAbort(1):
|
||||
if self.monitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
|
||||
log("###===--- LibrarySync Stopped ---===###", 0)
|
||||
self.logMsg("###===--- LibrarySync Stopped ---===###", 0)
|
||||
|
||||
def stopThread(self):
|
||||
self.stop_thread = True
|
||||
|
@ -1080,16 +1041,14 @@ class ManualSync(LibrarySync):
|
|||
|
||||
def movies(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
# Get movies from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
movies = itemtypes.Movies(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('movies')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
# Pull the list of movies and boxsets in Kodi
|
||||
try:
|
||||
|
@ -1121,7 +1080,7 @@ class ManualSync(LibrarySync):
|
|||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (lang(33026), viewName))
|
||||
|
||||
all_embymovies = emby.getMovies(viewId, basic=True, dialog=pdialog)
|
||||
all_embymovies = self.emby.getMovies(viewId, basic=True, dialog=pdialog)
|
||||
for embymovie in all_embymovies['Items']:
|
||||
|
||||
if self.shouldStop():
|
||||
|
@ -1136,8 +1095,8 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
|
||||
log("Movies to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embymovies = emby.getFullItems(updatelist)
|
||||
self.logMsg("Movies to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embymovies = self.emby.getFullItems(updatelist)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
||||
|
@ -1150,16 +1109,15 @@ class ManualSync(LibrarySync):
|
|||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = embymovie['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=embymovie['Name'])
|
||||
count += 1
|
||||
movies.add_update(embymovie, viewName, viewId)
|
||||
|
||||
##### PROCESS BOXSETS #####
|
||||
|
||||
boxsets = emby.getBoxset(dialog=pdialog)
|
||||
boxsets = self.emby.getBoxset(dialog=pdialog)
|
||||
embyboxsets = []
|
||||
|
||||
if pdialog:
|
||||
|
@ -1171,16 +1129,15 @@ class ManualSync(LibrarySync):
|
|||
return False
|
||||
|
||||
# Boxset has no real userdata, so using etag to compare
|
||||
checksum = boxset['Etag']
|
||||
itemid = boxset['Id']
|
||||
all_embyboxsetsIds.add(itemid)
|
||||
|
||||
if all_kodisets.get(itemid) != checksum:
|
||||
# Only update if boxset is not in Kodi or checksum is different
|
||||
if all_kodisets.get(itemid) != boxset['Etag']:
|
||||
# Only update if boxset is not in Kodi or boxset['Etag'] is different
|
||||
updatelist.append(itemid)
|
||||
embyboxsets.append(boxset)
|
||||
|
||||
log("Boxsets to update: %s" % updatelist, 1)
|
||||
self.logMsg("Boxsets to update: %s" % updatelist, 1)
|
||||
total = len(updatelist)
|
||||
|
||||
if pdialog:
|
||||
|
@ -1192,10 +1149,9 @@ class ManualSync(LibrarySync):
|
|||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = boxset['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=boxset['Name'])
|
||||
count += 1
|
||||
movies.add_updateBoxset(boxset)
|
||||
|
||||
|
@ -1205,26 +1161,24 @@ class ManualSync(LibrarySync):
|
|||
if kodimovie not in all_embymoviesIds:
|
||||
movies.remove(kodimovie)
|
||||
else:
|
||||
log("Movies compare finished.", 1)
|
||||
self.logMsg("Movies compare finished.", 1)
|
||||
|
||||
for boxset in all_kodisets:
|
||||
if boxset not in all_embyboxsetsIds:
|
||||
movies.remove(boxset)
|
||||
else:
|
||||
log("Boxsets compare finished.", 1)
|
||||
self.logMsg("Boxsets compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
def musicvideos(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
# Get musicvideos from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
mvideos = itemtypes.MusicVideos(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('musicvideos')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
# Pull the list of musicvideos in Kodi
|
||||
try:
|
||||
|
@ -1249,7 +1203,7 @@ class ManualSync(LibrarySync):
|
|||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33028), viewName))
|
||||
|
||||
all_embymvideos = emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
|
||||
all_embymvideos = self.emby.getMusicVideos(viewId, basic=True, dialog=pdialog)
|
||||
for embymvideo in all_embymvideos['Items']:
|
||||
|
||||
if self.shouldStop():
|
||||
|
@ -1264,8 +1218,8 @@ class ManualSync(LibrarySync):
|
|||
# Only update if musicvideo is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
|
||||
log("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embymvideos = emby.getFullItems(updatelist)
|
||||
self.logMsg("MusicVideos to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embymvideos = self.emby.getFullItems(updatelist)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
||||
|
@ -1279,10 +1233,9 @@ class ManualSync(LibrarySync):
|
|||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = embymvideo['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=embymvideo['Name'])
|
||||
count += 1
|
||||
mvideos.add_update(embymvideo, viewName, viewId)
|
||||
|
||||
|
@ -1292,22 +1245,20 @@ class ManualSync(LibrarySync):
|
|||
if kodimvideo not in all_embymvideosIds:
|
||||
mvideos.remove(kodimvideo)
|
||||
else:
|
||||
log("MusicVideos compare finished.", 1)
|
||||
self.logMsg("MusicVideos compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
def tvshows(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
# Get shows from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
tvshows = itemtypes.TVShows(embycursor, kodicursor)
|
||||
|
||||
views = emby_db.getView_byType('tvshows')
|
||||
views += emby_db.getView_byType('mixed')
|
||||
log("Media folders: %s" % views, 1)
|
||||
self.logMsg("Media folders: %s" % views, 1)
|
||||
|
||||
# Pull the list of tvshows and episodes in Kodi
|
||||
try:
|
||||
|
@ -1339,7 +1290,7 @@ class ManualSync(LibrarySync):
|
|||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (lang(33029), viewName))
|
||||
|
||||
all_embytvshows = emby.getShows(viewId, basic=True, dialog=pdialog)
|
||||
all_embytvshows = self.emby.getShows(viewId, basic=True, dialog=pdialog)
|
||||
for embytvshow in all_embytvshows['Items']:
|
||||
|
||||
if self.shouldStop():
|
||||
|
@ -1354,8 +1305,8 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
|
||||
log("TVShows to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embytvshows = emby.getFullItems(updatelist)
|
||||
self.logMsg("TVShows to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embytvshows = self.emby.getFullItems(updatelist)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
||||
|
@ -1384,7 +1335,7 @@ class ManualSync(LibrarySync):
|
|||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (lang(33030), viewName))
|
||||
|
||||
all_embyepisodes = emby.getEpisodes(viewId, basic=True, dialog=pdialog)
|
||||
all_embyepisodes = self.emby.getEpisodes(viewId, basic=True, dialog=pdialog)
|
||||
for embyepisode in all_embyepisodes['Items']:
|
||||
|
||||
if self.shouldStop():
|
||||
|
@ -1398,8 +1349,8 @@ class ManualSync(LibrarySync):
|
|||
# Only update if movie is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
|
||||
log("Episodes to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embyepisodes = emby.getFullItems(updatelist)
|
||||
self.logMsg("Episodes to update for %s: %s" % (viewName, updatelist), 1)
|
||||
embyepisodes = self.emby.getFullItems(updatelist)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
||||
|
@ -1410,11 +1361,9 @@ class ManualSync(LibrarySync):
|
|||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = episode['SeriesName']
|
||||
episodetitle = episode['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message="%s - %s" % (title, episodetitle))
|
||||
pdialog.update(percentage, message="%s - %s" % (episode['SeriesName'], episode['Name']))
|
||||
count += 1
|
||||
tvshows.add_updateEpisode(episode)
|
||||
|
||||
|
@ -1424,21 +1373,19 @@ class ManualSync(LibrarySync):
|
|||
if koditvshow not in all_embytvshowsIds:
|
||||
tvshows.remove(koditvshow)
|
||||
else:
|
||||
log("TVShows compare finished.", 1)
|
||||
self.logMsg("TVShows compare finished.", 1)
|
||||
|
||||
for kodiepisode in all_kodiepisodes:
|
||||
if kodiepisode not in all_embyepisodesIds:
|
||||
tvshows.remove(kodiepisode)
|
||||
else:
|
||||
log("Episodes compare finished.", 1)
|
||||
self.logMsg("Episodes compare finished.", 1)
|
||||
|
||||
return True
|
||||
|
||||
def music(self, embycursor, kodicursor, pdialog):
|
||||
|
||||
log = self.logMsg
|
||||
# Get music from emby
|
||||
emby = self.emby
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
music = itemtypes.Music(embycursor, kodicursor)
|
||||
|
||||
|
@ -1465,35 +1412,30 @@ class ManualSync(LibrarySync):
|
|||
|
||||
process = {
|
||||
|
||||
'artists': [emby.getArtists, music.add_updateArtist],
|
||||
'albums': [emby.getAlbums, music.add_updateAlbum],
|
||||
'songs': [emby.getSongs, music.add_updateSong]
|
||||
'artists': [self.emby.getArtists, music.add_updateArtist],
|
||||
'albums': [self.emby.getAlbums, music.add_updateAlbum],
|
||||
'songs': [self.emby.getSongs, music.add_updateSong]
|
||||
}
|
||||
types = ['artists', 'albums', 'songs']
|
||||
for type in types:
|
||||
|
||||
for data_type in ['artists', 'albums', 'songs']:
|
||||
if pdialog:
|
||||
pdialog.update(
|
||||
heading="Emby for Kodi",
|
||||
message="%s %s..." % (utils.language(33031), type))
|
||||
|
||||
if type != "artists":
|
||||
all_embyitems = process[type][0](basic=True, dialog=pdialog)
|
||||
message="%s %s..." % (utils.language(33031), data_type))
|
||||
if data_type != "artists":
|
||||
all_embyitems = process[data_type][0](basic=True, dialog=pdialog)
|
||||
else:
|
||||
all_embyitems = process[type][0](dialog=pdialog)
|
||||
all_embyitems = process[data_type][0](dialog=pdialog)
|
||||
for embyitem in all_embyitems['Items']:
|
||||
|
||||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
API = api.API(embyitem)
|
||||
itemid = embyitem['Id']
|
||||
if type == "artists":
|
||||
if data_type == "artists":
|
||||
all_embyartistsIds.add(itemid)
|
||||
if all_kodiartists.get(itemid) != API.getChecksum():
|
||||
# Only update if artist is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
elif type == "albums":
|
||||
elif data_type == "albums":
|
||||
all_embyalbumsIds.add(itemid)
|
||||
if all_kodialbums.get(itemid) != API.getChecksum():
|
||||
# Only update if album is not in Kodi or checksum is different
|
||||
|
@ -1503,47 +1445,36 @@ class ManualSync(LibrarySync):
|
|||
if all_kodisongs.get(itemid) != API.getChecksum():
|
||||
# Only update if songs is not in Kodi or checksum is different
|
||||
updatelist.append(itemid)
|
||||
|
||||
log("%s to update: %s" % (type, updatelist), 1)
|
||||
embyitems = emby.getFullItems(updatelist)
|
||||
self.logMsg("%s to update: %s" % (data_type, updatelist), 1)
|
||||
embyitems = self.emby.getFullItems(updatelist)
|
||||
total = len(updatelist)
|
||||
del updatelist[:]
|
||||
|
||||
if pdialog:
|
||||
pdialog.update(heading="Processing %s / %s items" % (type, total))
|
||||
|
||||
pdialog.update(heading="Processing %s / %s items" % (data_type, total))
|
||||
count = 0
|
||||
for embyitem in embyitems:
|
||||
# Process individual item
|
||||
if self.shouldStop():
|
||||
return False
|
||||
|
||||
title = embyitem['Name']
|
||||
if pdialog:
|
||||
percentage = int((float(count) / float(total))*100)
|
||||
pdialog.update(percentage, message=title)
|
||||
pdialog.update(percentage, message=embyitem['Name'])
|
||||
count += 1
|
||||
|
||||
process[type][1](embyitem)
|
||||
|
||||
process[data_type][1](embyitem)
|
||||
##### PROCESS DELETES #####
|
||||
|
||||
for kodiartist in all_kodiartists:
|
||||
if kodiartist not in all_embyartistsIds and all_kodiartists[kodiartist] is not None:
|
||||
music.remove(kodiartist)
|
||||
else:
|
||||
log("Artist compare finished.", 1)
|
||||
|
||||
self.logMsg("Artist compare finished.", 1)
|
||||
for kodialbum in all_kodialbums:
|
||||
if kodialbum not in all_embyalbumsIds:
|
||||
music.remove(kodialbum)
|
||||
else:
|
||||
log("Albums compare finished.", 1)
|
||||
|
||||
self.logMsg("Albums compare finished.", 1)
|
||||
for kodisong in all_kodisongs:
|
||||
if kodisong not in all_embysongsIds:
|
||||
music.remove(kodisong)
|
||||
else:
|
||||
log("Songs compare finished.", 1)
|
||||
|
||||
self.logMsg("Songs compare finished.", 1)
|
||||
return True
|
|
@ -195,6 +195,7 @@ def getSongTags(file):
|
|||
if pic.type == 3 and pic.data:
|
||||
#the file has an embedded cover
|
||||
hasEmbeddedCover = True
|
||||
break
|
||||
if audio.get("rating"):
|
||||
rating = float(audio.get("rating")[0])
|
||||
#flac rating is 0-100 and needs to be converted to 0-5 range
|
||||
|
|
|
@ -48,17 +48,13 @@ class PlaybackUtils():
|
|||
|
||||
def play(self, itemid, dbid=None):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
|
||||
doUtils = self.doUtils
|
||||
item = self.item
|
||||
API = self.API
|
||||
listitem = xbmcgui.ListItem()
|
||||
playutils = putils.PlayUtils(item)
|
||||
playutils = putils.PlayUtils(self.item)
|
||||
|
||||
log("Play called.", 1)
|
||||
self.logMsg("Play called.", 1)
|
||||
playurl = playutils.getPlayUrl()
|
||||
if not playurl:
|
||||
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
|
||||
|
@ -81,32 +77,32 @@ class PlaybackUtils():
|
|||
introsPlaylist = False
|
||||
dummyPlaylist = False
|
||||
|
||||
log("Playlist start position: %s" % startPos, 2)
|
||||
log("Playlist plugin position: %s" % currentPosition, 2)
|
||||
log("Playlist size: %s" % sizePlaylist, 2)
|
||||
self.logMsg("Playlist start position: %s" % startPos, 2)
|
||||
self.logMsg("Playlist plugin position: %s" % currentPosition, 2)
|
||||
self.logMsg("Playlist size: %s" % sizePlaylist, 2)
|
||||
|
||||
############### RESUME POINT ################
|
||||
|
||||
userdata = API.getUserData()
|
||||
seektime = API.adjustResume(userdata['Resume'])
|
||||
userdata = self.API.getUserData()
|
||||
seektime = self.API.adjustResume(userdata['Resume'])
|
||||
|
||||
# We need to ensure we add the intro and additional parts only once.
|
||||
# Otherwise we get a loop.
|
||||
if not propertiesPlayback:
|
||||
|
||||
window('emby_playbackProps', value="true")
|
||||
log("Setting up properties in playlist.", 1)
|
||||
self.logMsg("Setting up properties in playlist.", 1)
|
||||
|
||||
if (not homeScreen and not seektime and
|
||||
window('emby_customPlaylist') != "true"):
|
||||
|
||||
log("Adding dummy file to playlist.", 2)
|
||||
self.logMsg("Adding dummy file to playlist.", 2)
|
||||
dummyPlaylist = True
|
||||
playlist.add(playurl, listitem, index=startPos)
|
||||
# Remove the original item from playlist
|
||||
self.pl.removefromPlaylist(startPos+1)
|
||||
# Readd the original item to playlist - via jsonrpc so we have full metadata
|
||||
self.pl.insertintoPlaylist(currentPosition+1, dbid, item['Type'].lower())
|
||||
self.pl.insertintoPlaylist(currentPosition+1, dbid, self.item['Type'].lower())
|
||||
currentPosition += 1
|
||||
|
||||
############### -- CHECK FOR INTROS ################
|
||||
|
@ -114,7 +110,7 @@ class PlaybackUtils():
|
|||
if settings('enableCinema') == "true" and not seektime:
|
||||
# if we have any play them when the movie/show is not being resumed
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s/Intros?format=json" % itemid
|
||||
intros = doUtils(url)
|
||||
intros = self.doUtils(url)
|
||||
|
||||
if intros['TotalRecordCount'] != 0:
|
||||
getTrailers = True
|
||||
|
@ -124,14 +120,14 @@ class PlaybackUtils():
|
|||
if not resp:
|
||||
# User selected to not play trailers
|
||||
getTrailers = False
|
||||
log("Skip trailers.", 1)
|
||||
self.logMsg("Skip trailers.", 1)
|
||||
|
||||
if getTrailers:
|
||||
for intro in intros['Items']:
|
||||
# The server randomly returns intros, process them.
|
||||
introListItem = xbmcgui.ListItem()
|
||||
introPlayurl = putils.PlayUtils(intro).getPlayUrl()
|
||||
log("Adding Intro: %s" % introPlayurl, 1)
|
||||
self.logMsg("Adding Intro: %s" % introPlayurl, 1)
|
||||
|
||||
# Set listitem and properties for intros
|
||||
pbutils = PlaybackUtils(intro)
|
||||
|
@ -147,24 +143,24 @@ class PlaybackUtils():
|
|||
if homeScreen and not seektime and not sizePlaylist:
|
||||
# Extend our current playlist with the actual item to play
|
||||
# only if there's no playlist first
|
||||
log("Adding main item to playlist.", 1)
|
||||
self.pl.addtoPlaylist(dbid, item['Type'].lower())
|
||||
self.logMsg("Adding main item to playlist.", 1)
|
||||
self.pl.addtoPlaylist(dbid, self.item['Type'].lower())
|
||||
|
||||
# Ensure that additional parts are played after the main item
|
||||
currentPosition += 1
|
||||
|
||||
############### -- CHECK FOR ADDITIONAL PARTS ################
|
||||
|
||||
if item.get('PartCount'):
|
||||
if self.item.get('PartCount'):
|
||||
# Only add to the playlist after intros have played
|
||||
partcount = item['PartCount']
|
||||
partcount = self.item['PartCount']
|
||||
url = "{server}/emby/Videos/%s/AdditionalParts?format=json" % itemid
|
||||
parts = doUtils(url)
|
||||
parts = self.doUtils(url)
|
||||
for part in parts['Items']:
|
||||
|
||||
additionalListItem = xbmcgui.ListItem()
|
||||
additionalPlayurl = putils.PlayUtils(part).getPlayUrl()
|
||||
log("Adding additional part: %s" % partcount, 1)
|
||||
self.logMsg("Adding additional part: %s" % partcount, 1)
|
||||
|
||||
# Set listitem and properties for each additional parts
|
||||
pbutils = PlaybackUtils(part)
|
||||
|
@ -178,13 +174,13 @@ class PlaybackUtils():
|
|||
if dummyPlaylist:
|
||||
# Added a dummy file to the playlist,
|
||||
# because the first item is going to fail automatically.
|
||||
log("Processed as a playlist. First item is skipped.", 1)
|
||||
self.logMsg("Processed as a playlist. First item is skipped.", 1)
|
||||
return xbmcplugin.setResolvedUrl(int(sys.argv[1]), False, listitem)
|
||||
|
||||
|
||||
# We just skipped adding properties. Reset flag for next time.
|
||||
elif propertiesPlayback:
|
||||
log("Resetting properties playback flag.", 2)
|
||||
self.logMsg("Resetting properties playback flag.", 2)
|
||||
window('emby_playbackProps', clear=True)
|
||||
|
||||
#self.pl.verifyPlaylist()
|
||||
|
@ -201,35 +197,34 @@ class PlaybackUtils():
|
|||
############### PLAYBACK ################
|
||||
|
||||
if homeScreen and seektime and window('emby_customPlaylist') != "true":
|
||||
log("Play as a widget item.", 1)
|
||||
self.logMsg("Play as a widget item.", 1)
|
||||
self.setListItem(listitem)
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
|
||||
|
||||
elif ((introsPlaylist and window('emby_customPlaylist') == "true") or
|
||||
(homeScreen and not sizePlaylist)):
|
||||
# Playlist was created just now, play it.
|
||||
log("Play playlist.", 1)
|
||||
self.logMsg("Play playlist.", 1)
|
||||
xbmc.Player().play(playlist, startpos=startPos)
|
||||
|
||||
else:
|
||||
log("Play as a regular item.", 1)
|
||||
self.logMsg("Play as a regular item.", 1)
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listitem)
|
||||
|
||||
def setProperties(self, playurl, listitem):
|
||||
|
||||
window = utils.window
|
||||
# Set all properties necessary for plugin path playback
|
||||
item = self.item
|
||||
itemid = item['Id']
|
||||
itemtype = item['Type']
|
||||
itemid = self.item['Id']
|
||||
itemtype = self.item['Type']
|
||||
|
||||
embyitem = "emby_%s" % playurl
|
||||
window('%s.runtime' % embyitem, value=str(item.get('RunTimeTicks')))
|
||||
window('%s.runtime' % embyitem, value=str(self.item.get('RunTimeTicks')))
|
||||
window('%s.type' % embyitem, value=itemtype)
|
||||
window('%s.itemid' % embyitem, value=itemid)
|
||||
|
||||
if itemtype == "Episode":
|
||||
window('%s.refreshid' % embyitem, value=item.get('SeriesId'))
|
||||
window('%s.refreshid' % embyitem, value=self.item.get('SeriesId'))
|
||||
else:
|
||||
window('%s.refreshid' % embyitem, value=itemid)
|
||||
|
||||
|
@ -248,10 +243,9 @@ class PlaybackUtils():
|
|||
externalsubs = []
|
||||
mapping = {}
|
||||
|
||||
item = self.item
|
||||
itemid = item['Id']
|
||||
itemid = self.item['Id']
|
||||
try:
|
||||
mediastreams = item['MediaSources'][0]['MediaStreams']
|
||||
mediastreams = self.item['MediaSources'][0]['MediaStreams']
|
||||
except (TypeError, KeyError, IndexError):
|
||||
return
|
||||
|
||||
|
@ -280,10 +274,7 @@ class PlaybackUtils():
|
|||
|
||||
def setArtwork(self, listItem):
|
||||
# Set up item and item info
|
||||
item = self.item
|
||||
artwork = self.artwork
|
||||
|
||||
allartwork = artwork.getAllArtwork(item, parentInfo=True)
|
||||
allartwork = self.artwork.getAllArtwork(self.item, parentInfo=True)
|
||||
# Set artwork for listitem
|
||||
arttypes = {
|
||||
|
||||
|
@ -320,33 +311,30 @@ class PlaybackUtils():
|
|||
|
||||
def setListItem(self, listItem):
|
||||
|
||||
item = self.item
|
||||
itemtype = item['Type']
|
||||
API = self.API
|
||||
people = API.getPeople()
|
||||
studios = API.getStudios()
|
||||
people = self.API.getPeople()
|
||||
studios = self.API.getStudios()
|
||||
|
||||
metadata = {
|
||||
|
||||
'title': item.get('Name', "Missing name"),
|
||||
'year': item.get('ProductionYear'),
|
||||
'plot': API.getOverview(),
|
||||
'title': self.item.get('Name', "Missing name"),
|
||||
'year': self.item.get('ProductionYear'),
|
||||
'plot': self.API.getOverview(),
|
||||
'director': people.get('Director'),
|
||||
'writer': people.get('Writer'),
|
||||
'mpaa': API.getMpaa(),
|
||||
'genre': " / ".join(item['Genres']),
|
||||
'mpaa': self.API.getMpaa(),
|
||||
'genre': " / ".join(self.item['Genres']),
|
||||
'studio': " / ".join(studios),
|
||||
'aired': API.getPremiereDate(),
|
||||
'rating': item.get('CommunityRating'),
|
||||
'votes': item.get('VoteCount')
|
||||
'aired': self.API.getPremiereDate(),
|
||||
'rating': self.item.get('CommunityRating'),
|
||||
'votes': self.item.get('VoteCount')
|
||||
}
|
||||
|
||||
if "Episode" in itemtype:
|
||||
if "Episode" in self.item['Type']:
|
||||
# Only for tv shows
|
||||
thumbId = item.get('SeriesId')
|
||||
season = item.get('ParentIndexNumber', -1)
|
||||
episode = item.get('IndexNumber', -1)
|
||||
show = item.get('SeriesName', "")
|
||||
thumbId = self.item.get('SeriesId')
|
||||
season = self.item.get('ParentIndexNumber', -1)
|
||||
episode = self.item.get('IndexNumber', -1)
|
||||
show = self.item.get('SeriesName', "")
|
||||
|
||||
metadata['TVShowTitle'] = show
|
||||
metadata['season'] = season
|
||||
|
|
|
@ -49,15 +49,13 @@ class Player(xbmc.Player):
|
|||
|
||||
def onPlayBackStarted(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
# Will be called when xbmc starts playing a file
|
||||
xbmcplayer = self.xbmcplayer
|
||||
self.stopAll()
|
||||
|
||||
# Get current file
|
||||
try:
|
||||
currentFile = xbmcplayer.getPlayingFile()
|
||||
currentFile = self.xbmcplayer.getPlayingFile()
|
||||
xbmc.sleep(300)
|
||||
except:
|
||||
currentFile = ""
|
||||
|
@ -65,11 +63,11 @@ class Player(xbmc.Player):
|
|||
while not currentFile:
|
||||
xbmc.sleep(100)
|
||||
try:
|
||||
currentFile = xbmcplayer.getPlayingFile()
|
||||
currentFile = self.xbmcplayer.getPlayingFile()
|
||||
except: pass
|
||||
|
||||
if count == 5: # try 5 times
|
||||
log("Cancelling playback report...", 1)
|
||||
self.logMsg("Cancelling playback report...", 1)
|
||||
break
|
||||
else: count += 1
|
||||
|
||||
|
@ -86,12 +84,12 @@ class Player(xbmc.Player):
|
|||
xbmc.sleep(200)
|
||||
itemId = window("emby_%s.itemid" % currentFile)
|
||||
if tryCount == 20: # try 20 times or about 10 seconds
|
||||
log("Could not find itemId, cancelling playback report...", 1)
|
||||
self.logMsg("Could not find itemId, cancelling playback report...", 1)
|
||||
break
|
||||
else: tryCount += 1
|
||||
|
||||
else:
|
||||
log("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
|
||||
self.logMsg("ONPLAYBACK_STARTED: %s itemid: %s" % (currentFile, itemId), 0)
|
||||
|
||||
# Only proceed if an itemId was found.
|
||||
embyitem = "emby_%s" % currentFile
|
||||
|
@ -104,11 +102,11 @@ class Player(xbmc.Player):
|
|||
customseek = window('emby_customPlaylist.seektime')
|
||||
if window('emby_customPlaylist') == "true" and customseek:
|
||||
# Start at, when using custom playlist (play to Kodi from webclient)
|
||||
log("Seeking to: %s" % customseek, 1)
|
||||
xbmcplayer.seekTime(int(customseek)/10000000.0)
|
||||
self.logMsg("Seeking to: %s" % customseek, 1)
|
||||
self.xbmcplayer.seekTime(int(customseek)/10000000.0)
|
||||
window('emby_customPlaylist.seektime', clear=True)
|
||||
|
||||
seekTime = xbmcplayer.getTime()
|
||||
seekTime = self.xbmcplayer.getTime()
|
||||
|
||||
# Get playback volume
|
||||
volume_query = {
|
||||
|
@ -191,7 +189,7 @@ class Player(xbmc.Player):
|
|||
|
||||
if mapping: # Set in playbackutils.py
|
||||
|
||||
log("Mapping for external subtitles index: %s" % mapping, 2)
|
||||
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
|
||||
externalIndex = json.loads(mapping)
|
||||
|
||||
if externalIndex.get(str(indexSubs)):
|
||||
|
@ -209,15 +207,15 @@ class Player(xbmc.Player):
|
|||
|
||||
|
||||
# Post playback to server
|
||||
log("Sending POST play started: %s." % postdata, 2)
|
||||
self.doUtils(url, postBody=postdata, type="POST")
|
||||
self.logMsg("Sending POST play started: %s." % postdata, 2)
|
||||
self.doUtils(url, postBody=postdata, action_type="POST")
|
||||
|
||||
# Ensure we do have a runtime
|
||||
try:
|
||||
runtime = int(runtime)
|
||||
except ValueError:
|
||||
runtime = xbmcplayer.getTotalTime()
|
||||
log("Runtime is missing, Kodi runtime: %s" % runtime, 1)
|
||||
runtime = self.xbmcplayer.getTotalTime()
|
||||
self.logMsg("Runtime is missing, Kodi runtime: %s" % runtime, 1)
|
||||
|
||||
# Save data map for updates and position calls
|
||||
data = {
|
||||
|
@ -234,7 +232,7 @@ class Player(xbmc.Player):
|
|||
}
|
||||
|
||||
self.played_info[currentFile] = data
|
||||
log("ADDING_FILE: %s" % self.played_info, 1)
|
||||
self.logMsg("ADDING_FILE: %s" % self.played_info, 1)
|
||||
|
||||
# log some playback stats
|
||||
'''if(itemType != None):
|
||||
|
@ -253,10 +251,7 @@ class Player(xbmc.Player):
|
|||
|
||||
def reportPlayback(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
log("reportPlayback Called", 2)
|
||||
xbmcplayer = self.xbmcplayer
|
||||
self.logMsg("reportPlayback Called", 2)
|
||||
|
||||
# Get current file
|
||||
currentFile = self.currentFile
|
||||
|
@ -354,7 +349,7 @@ class Player(xbmc.Player):
|
|||
|
||||
if mapping: # Set in PlaybackUtils.py
|
||||
|
||||
log("Mapping for external subtitles index: %s" % mapping, 2)
|
||||
self.logMsg("Mapping for external subtitles index: %s" % mapping, 2)
|
||||
externalIndex = json.loads(mapping)
|
||||
|
||||
if externalIndex.get(str(indexSubs)):
|
||||
|
@ -374,7 +369,7 @@ class Player(xbmc.Player):
|
|||
|
||||
# Report progress via websocketclient
|
||||
postdata = json.dumps(postdata)
|
||||
log("Report: %s" % postdata, 2)
|
||||
self.logMsg("Report: %s" % postdata, 2)
|
||||
self.ws.sendProgressUpdate(postdata)
|
||||
|
||||
def onPlayBackPaused(self):
|
||||
|
@ -410,14 +405,13 @@ class Player(xbmc.Player):
|
|||
|
||||
def onPlayBackStopped(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
# Will be called when user stops xbmc playing a file
|
||||
log("ONPLAYBACK_STOPPED", 2)
|
||||
self.logMsg("ONPLAYBACK_STOPPED", 2)
|
||||
window('emby_customPlaylist', clear=True)
|
||||
window('emby_customPlaylist.seektime', clear=True)
|
||||
window('emby_playbackProps', clear=True)
|
||||
log("Clear playlist properties.", 1)
|
||||
self.logMsg("Clear playlist properties.", 1)
|
||||
self.stopAll()
|
||||
|
||||
def onPlayBackEnded(self):
|
||||
|
@ -428,31 +422,28 @@ class Player(xbmc.Player):
|
|||
|
||||
def stopAll(self):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
settings = utils.settings
|
||||
|
||||
doUtils = self.doUtils
|
||||
|
||||
if not self.played_info:
|
||||
return
|
||||
|
||||
log("Played_information: %s" % self.played_info, 1)
|
||||
self.logMsg("Played_information: %s" % self.played_info, 1)
|
||||
# Process each items
|
||||
for item in self.played_info:
|
||||
|
||||
data = self.played_info.get(item)
|
||||
if data:
|
||||
|
||||
log("Item path: %s" % item, 2)
|
||||
log("Item data: %s" % data, 2)
|
||||
self.logMsg("Item path: %s" % item, 2)
|
||||
self.logMsg("Item data: %s" % data, 2)
|
||||
|
||||
runtime = data['runtime']
|
||||
currentPosition = data['currentPosition']
|
||||
itemid = data['item_id']
|
||||
refresh_id = data['refresh_id']
|
||||
currentFile = data['currentfile']
|
||||
type = data['Type']
|
||||
media_type = data['Type']
|
||||
playMethod = data['playmethod']
|
||||
|
||||
# Prevent manually mark as watched in Kodi monitor
|
||||
|
@ -466,15 +457,15 @@ class Player(xbmc.Player):
|
|||
percentComplete = 0
|
||||
|
||||
markPlayedAt = float(settings('markPlayed')) / 100
|
||||
log("Percent complete: %s Mark played at: %s"
|
||||
self.logMsg("Percent complete: %s Mark played at: %s"
|
||||
% (percentComplete, markPlayedAt), 1)
|
||||
|
||||
# Send the delete action to the server.
|
||||
offerDelete = False
|
||||
|
||||
if type == "Episode" and settings('deleteTV') == "true":
|
||||
if media_type == "Episode" and settings('deleteTV') == "true":
|
||||
offerDelete = True
|
||||
elif type == "Movie" and settings('deleteMovies') == "true":
|
||||
elif media_type == "Movie" and settings('deleteMovies') == "true":
|
||||
offerDelete = True
|
||||
|
||||
if settings('offerDelete') != "true":
|
||||
|
@ -484,21 +475,21 @@ class Player(xbmc.Player):
|
|||
if percentComplete >= markPlayedAt and offerDelete:
|
||||
resp = xbmcgui.Dialog().yesno(lang(30091), lang(33015), autoclose=120000)
|
||||
if not resp:
|
||||
log("User skipped deletion.", 1)
|
||||
self.logMsg("User skipped deletion.", 1)
|
||||
continue
|
||||
|
||||
url = "{server}/emby/Items/%s?format=json" % itemid
|
||||
log("Deleting request: %s" % itemid, 1)
|
||||
doUtils(url, type="DELETE")
|
||||
self.logMsg("Deleting request: %s" % itemid, 1)
|
||||
self.doUtils(url, action_type="DELETE")
|
||||
|
||||
self.stopPlayback(data)
|
||||
|
||||
# Stop transcoding
|
||||
if playMethod == "Transcode":
|
||||
log("Transcoding for %s terminated." % itemid, 1)
|
||||
self.logMsg("Transcoding for %s terminated." % itemid, 1)
|
||||
deviceId = self.clientInfo.getDeviceId()
|
||||
url = "{server}/emby/Videos/ActiveEncodings?DeviceId=%s" % deviceId
|
||||
doUtils(url, type="DELETE")
|
||||
self.doUtils(url, action_type="DELETE")
|
||||
|
||||
self.played_info.clear()
|
||||
|
||||
|
@ -517,4 +508,4 @@ class Player(xbmc.Player):
|
|||
'MediaSourceId': itemId,
|
||||
'PositionTicks': positionTicks
|
||||
}
|
||||
self.doUtils(url, postBody=postdata, type="POST")
|
||||
self.doUtils(url, postBody=postdata, action_type="POST")
|
|
@ -39,7 +39,6 @@ class Playlist():
|
|||
|
||||
def playAll(self, itemids, startat):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
|
@ -50,8 +49,8 @@ class Playlist():
|
|||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
playlist.clear()
|
||||
|
||||
log("---*** PLAY ALL ***---", 1)
|
||||
log("Items: %s and start at: %s" % (itemids, startat), 1)
|
||||
self.logMsg("---*** PLAY ALL ***---", 1)
|
||||
self.logMsg("Items: %s and start at: %s" % (itemids, startat), 1)
|
||||
|
||||
started = False
|
||||
window('emby_customplaylist', value="true")
|
||||
|
@ -67,14 +66,14 @@ class Playlist():
|
|||
mediatype = embydb_item[4]
|
||||
except TypeError:
|
||||
# Item is not found in our database, add item manually
|
||||
log("Item was not found in the database, manually adding item.", 1)
|
||||
self.logMsg("Item was not found in the database, manually adding item.", 1)
|
||||
item = self.emby.getItem(itemid)
|
||||
self.addtoPlaylist_xbmc(playlist, item)
|
||||
else:
|
||||
# Add to playlist
|
||||
self.addtoPlaylist(dbid, mediatype)
|
||||
|
||||
log("Adding %s to playlist." % itemid, 1)
|
||||
self.logMsg("Adding %s to playlist." % itemid, 1)
|
||||
|
||||
if not started:
|
||||
started = True
|
||||
|
@ -85,14 +84,12 @@ class Playlist():
|
|||
|
||||
def modifyPlaylist(self, itemids):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
embyconn = utils.kodiSQL('emby')
|
||||
embycursor = embyconn.cursor()
|
||||
emby_db = embydb.Embydb_Functions(embycursor)
|
||||
|
||||
log("---*** ADD TO PLAYLIST ***---", 1)
|
||||
log("Items: %s" % itemids, 1)
|
||||
self.logMsg("---*** ADD TO PLAYLIST ***---", 1)
|
||||
self.logMsg("Items: %s" % itemids, 1)
|
||||
|
||||
player = xbmc.Player()
|
||||
playlist = xbmc.PlayList(xbmc.PLAYLIST_VIDEO)
|
||||
|
@ -110,7 +107,7 @@ class Playlist():
|
|||
# Add to playlist
|
||||
self.addtoPlaylist(dbid, mediatype)
|
||||
|
||||
log("Adding %s to playlist." % itemid, 1)
|
||||
self.logMsg("Adding %s to playlist." % itemid, 1)
|
||||
|
||||
self.verifyPlaylist()
|
||||
embycursor.close()
|
||||
|
@ -133,12 +130,10 @@ class Playlist():
|
|||
else:
|
||||
pl['params']['item'] = {'file': url}
|
||||
|
||||
result = xbmc.executeJSONRPC(json.dumps(pl))
|
||||
self.logMsg(result, 2)
|
||||
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
|
||||
|
||||
def addtoPlaylist_xbmc(self, playlist, item):
|
||||
|
||||
itemid = item['Id']
|
||||
playurl = playutils.PlayUtils(item).getPlayUrl()
|
||||
if not playurl:
|
||||
# Playurl failed
|
||||
|
@ -169,8 +164,7 @@ class Playlist():
|
|||
else:
|
||||
pl['params']['item'] = {'file': url}
|
||||
|
||||
result = xbmc.executeJSONRPC(json.dumps(pl))
|
||||
self.logMsg(result, 2)
|
||||
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
|
||||
|
||||
def verifyPlaylist(self):
|
||||
|
||||
|
@ -184,8 +178,7 @@ class Playlist():
|
|||
'playlistid': 1
|
||||
}
|
||||
}
|
||||
result = xbmc.executeJSONRPC(json.dumps(pl))
|
||||
self.logMsg(result, 2)
|
||||
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
|
||||
|
||||
def removefromPlaylist(self, position):
|
||||
|
||||
|
@ -200,5 +193,4 @@ class Playlist():
|
|||
'position': position
|
||||
}
|
||||
}
|
||||
result = xbmc.executeJSONRPC(json.dumps(pl))
|
||||
self.logMsg(result, 2)
|
||||
self.logMsg(xbmc.executeJSONRPC(json.dumps(pl)), 2)
|
||||
|
|
|
@ -33,28 +33,26 @@ class PlayUtils():
|
|||
|
||||
def getPlayUrl(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
|
||||
item = self.item
|
||||
playurl = None
|
||||
|
||||
if (item.get('Type') in ("Recording", "TvChannel") and
|
||||
item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http"):
|
||||
if (self.item.get('Type') in ("Recording", "TvChannel") and
|
||||
self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http"):
|
||||
# Play LiveTV or recordings
|
||||
log("File protocol is http (livetv).", 1)
|
||||
playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, item['Id'])
|
||||
self.logMsg("File protocol is http (livetv).", 1)
|
||||
playurl = "%s/emby/Videos/%s/live.m3u8?static=true" % (self.server, self.item['Id'])
|
||||
window('emby_%s.playmethod' % playurl, value="Transcode")
|
||||
|
||||
elif item.get('MediaSources') and item['MediaSources'][0]['Protocol'] == "Http":
|
||||
elif self.item.get('MediaSources') and self.item['MediaSources'][0]['Protocol'] == "Http":
|
||||
# Only play as http, used for channels, or online hosting of content
|
||||
log("File protocol is http.", 1)
|
||||
self.logMsg("File protocol is http.", 1)
|
||||
playurl = self.httpPlay()
|
||||
window('emby_%s.playmethod' % playurl, value="DirectStream")
|
||||
|
||||
elif self.isDirectPlay():
|
||||
|
||||
log("File is direct playing.", 1)
|
||||
self.logMsg("File is direct playing.", 1)
|
||||
playurl = self.directPlay()
|
||||
playurl = playurl.encode('utf-8')
|
||||
# Set playmethod property
|
||||
|
@ -62,14 +60,14 @@ class PlayUtils():
|
|||
|
||||
elif self.isDirectStream():
|
||||
|
||||
log("File is direct streaming.", 1)
|
||||
self.logMsg("File is direct streaming.", 1)
|
||||
playurl = self.directStream()
|
||||
# Set playmethod property
|
||||
window('emby_%s.playmethod' % playurl, value="DirectStream")
|
||||
|
||||
elif self.isTranscoding():
|
||||
|
||||
log("File is transcoding.", 1)
|
||||
self.logMsg("File is transcoding.", 1)
|
||||
playurl = self.transcoding()
|
||||
# Set playmethod property
|
||||
window('emby_%s.playmethod' % playurl, value="Transcode")
|
||||
|
@ -78,35 +76,31 @@ class PlayUtils():
|
|||
|
||||
def httpPlay(self):
|
||||
# Audio, Video, Photo
|
||||
item = self.item
|
||||
server = self.server
|
||||
|
||||
itemid = item['Id']
|
||||
mediatype = item['MediaType']
|
||||
itemid = self.item['Id']
|
||||
mediatype = self.item['MediaType']
|
||||
|
||||
if mediatype == "Audio":
|
||||
playurl = "%s/emby/Audio/%s/stream" % (server, itemid)
|
||||
playurl = "%s/emby/Audio/%s/stream" % (self.server, itemid)
|
||||
else:
|
||||
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
|
||||
playurl = "%s/emby/Videos/%s/stream?static=true" % (self.server, itemid)
|
||||
|
||||
return playurl
|
||||
|
||||
def isDirectPlay(self):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
settings = utils.settings
|
||||
dialog = xbmcgui.Dialog()
|
||||
|
||||
item = self.item
|
||||
|
||||
# Requirement: Filesystem, Accessible path
|
||||
if settings('playFromStream') == "true":
|
||||
# User forcing to play via HTTP
|
||||
log("Can't direct play, play from HTTP enabled.", 1)
|
||||
self.logMsg("Can't direct play, play from HTTP enabled.", 1)
|
||||
return False
|
||||
|
||||
videotrack = item['MediaSources'][0]['Name']
|
||||
videotrack = self.item['MediaSources'][0]['Name']
|
||||
transcodeH265 = settings('transcodeH265')
|
||||
|
||||
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
|
||||
|
@ -118,27 +112,27 @@ class PlayUtils():
|
|||
'2': 720,
|
||||
'3': 1080
|
||||
}
|
||||
log("Resolution is: %sP, transcode for resolution: %sP+"
|
||||
self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
|
||||
% (resolution, res[transcodeH265]), 1)
|
||||
if res[transcodeH265] <= resolution:
|
||||
return False
|
||||
|
||||
canDirectPlay = item['MediaSources'][0]['SupportsDirectPlay']
|
||||
canDirectPlay = self.item['MediaSources'][0]['SupportsDirectPlay']
|
||||
# Make sure direct play is supported by the server
|
||||
if not canDirectPlay:
|
||||
log("Can't direct play, server doesn't allow/support it.", 1)
|
||||
self.logMsg("Can't direct play, server doesn't allow/support it.", 1)
|
||||
return False
|
||||
|
||||
location = item['LocationType']
|
||||
location = self.item['LocationType']
|
||||
if location == "FileSystem":
|
||||
# Verify the path
|
||||
if not self.fileExists():
|
||||
log("Unable to direct play.")
|
||||
self.logMsg("Unable to direct play.")
|
||||
try:
|
||||
count = int(settings('failCount'))
|
||||
except ValueError:
|
||||
count = 0
|
||||
log("Direct play failed: %s times." % count, 1)
|
||||
self.logMsg("Direct play failed: %s times." % count, 1)
|
||||
|
||||
if count < 2:
|
||||
# Let the user know that direct play failed
|
||||
|
@ -163,20 +157,16 @@ class PlayUtils():
|
|||
|
||||
def directPlay(self):
|
||||
|
||||
item = self.item
|
||||
|
||||
try:
|
||||
playurl = item['MediaSources'][0]['Path']
|
||||
playurl = self.item['MediaSources'][0]['Path']
|
||||
except (IndexError, KeyError):
|
||||
playurl = item['Path']
|
||||
playurl = self.item['Path']
|
||||
|
||||
if item.get('VideoType'):
|
||||
if self.item.get('VideoType'):
|
||||
# Specific format modification
|
||||
type = item['VideoType']
|
||||
|
||||
if type == "Dvd":
|
||||
if self.item['VideoType'] == "Dvd":
|
||||
playurl = "%s/VIDEO_TS/VIDEO_TS.IFO" % playurl
|
||||
elif type == "BluRay":
|
||||
elif self.item['VideoType'] == "BluRay":
|
||||
playurl = "%s/BDMV/index.bdmv" % playurl
|
||||
|
||||
# Assign network protocol
|
||||
|
@ -192,35 +182,30 @@ class PlayUtils():
|
|||
|
||||
def fileExists(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
if 'Path' not in self.item:
|
||||
# File has no path defined in server
|
||||
return False
|
||||
|
||||
# Convert path to direct play
|
||||
path = self.directPlay()
|
||||
log("Verifying path: %s" % path, 1)
|
||||
self.logMsg("Verifying path: %s" % path, 1)
|
||||
|
||||
if xbmcvfs.exists(path):
|
||||
log("Path exists.", 1)
|
||||
self.logMsg("Path exists.", 1)
|
||||
return True
|
||||
|
||||
elif ":" not in path:
|
||||
log("Can't verify path, assumed linux. Still try to direct play.", 1)
|
||||
self.logMsg("Can't verify path, assumed linux. Still try to direct play.", 1)
|
||||
return True
|
||||
|
||||
else:
|
||||
log("Failed to find file.", 1)
|
||||
self.logMsg("Failed to find file.", 1)
|
||||
return False
|
||||
|
||||
def isDirectStream(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
item = self.item
|
||||
|
||||
videotrack = item['MediaSources'][0]['Name']
|
||||
videotrack = self.item['MediaSources'][0]['Name']
|
||||
transcodeH265 = utils.settings('transcodeH265')
|
||||
|
||||
if transcodeH265 in ("1", "2", "3") and ("HEVC" in videotrack or "H265" in videotrack):
|
||||
|
@ -232,54 +217,47 @@ class PlayUtils():
|
|||
'2': 720,
|
||||
'3': 1080
|
||||
}
|
||||
log("Resolution is: %sP, transcode for resolution: %sP+"
|
||||
self.logMsg("Resolution is: %sP, transcode for resolution: %sP+"
|
||||
% (resolution, res[transcodeH265]), 1)
|
||||
if res[transcodeH265] <= resolution:
|
||||
return False
|
||||
|
||||
# Requirement: BitRate, supported encoding
|
||||
canDirectStream = item['MediaSources'][0]['SupportsDirectStream']
|
||||
canDirectStream = self.item['MediaSources'][0]['SupportsDirectStream']
|
||||
# Make sure the server supports it
|
||||
if not canDirectStream:
|
||||
return False
|
||||
|
||||
# Verify the bitrate
|
||||
if not self.isNetworkSufficient():
|
||||
log("The network speed is insufficient to direct stream file.", 1)
|
||||
self.logMsg("The network speed is insufficient to direct stream file.", 1)
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def directStream(self):
|
||||
|
||||
item = self.item
|
||||
server = self.server
|
||||
|
||||
itemid = item['Id']
|
||||
itemtype = item['Type']
|
||||
|
||||
if 'Path' in item and item['Path'].endswith('.strm'):
|
||||
if 'Path' in self.item and self.item['Path'].endswith('.strm'):
|
||||
# Allow strm loading when direct streaming
|
||||
playurl = self.directPlay()
|
||||
elif itemtype == "Audio":
|
||||
playurl = "%s/emby/Audio/%s/stream.mp3" % (server, itemid)
|
||||
elif self.item['Type'] == "Audio":
|
||||
playurl = "%s/emby/Audio/%s/stream.mp3" % (self.server, self.item['Id'])
|
||||
else:
|
||||
playurl = "%s/emby/Videos/%s/stream?static=true" % (server, itemid)
|
||||
playurl = "%s/emby/Videos/%s/stream?static=true" % (self.server, self.item['Id'])
|
||||
|
||||
return playurl
|
||||
|
||||
def isNetworkSufficient(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
settings = self.getBitrate()*1000
|
||||
|
||||
try:
|
||||
sourceBitrate = int(self.item['MediaSources'][0]['Bitrate'])
|
||||
except (KeyError, TypeError):
|
||||
log("Bitrate value is missing.", 1)
|
||||
self.logMsg("Bitrate value is missing.", 1)
|
||||
else:
|
||||
log("The add-on settings bitrate is: %s, the video bitrate required is: %s"
|
||||
self.logMsg("The add-on settings bitrate is: %s, the video bitrate required is: %s"
|
||||
% (settings, sourceBitrate), 1)
|
||||
if settings < sourceBitrate:
|
||||
return False
|
||||
|
@ -287,25 +265,19 @@ class PlayUtils():
|
|||
return True
|
||||
|
||||
def isTranscoding(self):
|
||||
|
||||
item = self.item
|
||||
|
||||
canTranscode = item['MediaSources'][0]['SupportsTranscoding']
|
||||
# Make sure the server supports it
|
||||
if not canTranscode:
|
||||
if not self.item['MediaSources'][0]['SupportsTranscoding']:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def transcoding(self):
|
||||
|
||||
item = self.item
|
||||
|
||||
if 'Path' in item and item['Path'].endswith('.strm'):
|
||||
if 'Path' in self.item and self.item['Path'].endswith('.strm'):
|
||||
# Allow strm loading when transcoding
|
||||
playurl = self.directPlay()
|
||||
else:
|
||||
itemid = item['Id']
|
||||
itemid = self.item['Id']
|
||||
deviceId = self.clientInfo.getDeviceId()
|
||||
playurl = (
|
||||
"%s/emby/Videos/%s/master.m3u8?MediaSourceId=%s"
|
||||
|
@ -320,7 +292,6 @@ class PlayUtils():
|
|||
def getBitrate(self):
|
||||
|
||||
# get the addon video quality
|
||||
videoQuality = utils.settings('videoBitrate')
|
||||
bitrate = {
|
||||
|
||||
'0': 664,
|
||||
|
@ -345,11 +316,10 @@ class PlayUtils():
|
|||
}
|
||||
|
||||
# max bit rate supported by server (max signed 32bit integer)
|
||||
return bitrate.get(videoQuality, 2147483)
|
||||
return bitrate.get(utils.settings('videoBitrate'), 2147483)
|
||||
|
||||
def audioSubsPref(self, url, listitem):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
dialog = xbmcgui.Dialog()
|
||||
# For transcoding only
|
||||
|
@ -364,9 +334,8 @@ class PlayUtils():
|
|||
selectSubsIndex = ""
|
||||
playurlprefs = "%s" % url
|
||||
|
||||
item = self.item
|
||||
try:
|
||||
mediasources = item['MediaSources'][0]
|
||||
mediasources = self.item['MediaSources'][0]
|
||||
mediastreams = mediasources['MediaStreams']
|
||||
except (TypeError, KeyError, IndexError):
|
||||
return
|
||||
|
@ -374,9 +343,8 @@ class PlayUtils():
|
|||
for stream in mediastreams:
|
||||
# Since Emby returns all possible tracks together, have to sort them.
|
||||
index = stream['Index']
|
||||
type = stream['Type']
|
||||
|
||||
if 'Audio' in type:
|
||||
if 'Audio' in stream['Type']:
|
||||
codec = stream['Codec']
|
||||
channelLayout = stream.get('ChannelLayout', "")
|
||||
|
||||
|
@ -389,7 +357,7 @@ class PlayUtils():
|
|||
audioStreamsList[track] = index
|
||||
audioStreams.append(track)
|
||||
|
||||
elif 'Subtitle' in type:
|
||||
elif 'Subtitle' in stream['Type']:
|
||||
try:
|
||||
track = "%s - %s" % (index, stream['Language'])
|
||||
except:
|
||||
|
@ -436,10 +404,10 @@ class PlayUtils():
|
|||
# Load subtitles in the listitem if downloadable
|
||||
if selectSubsIndex in downloadableStreams:
|
||||
|
||||
itemid = item['Id']
|
||||
itemid = self.item['Id']
|
||||
url = [("%s/Videos/%s/%s/Subtitles/%s/Stream.srt"
|
||||
% (self.server, itemid, itemid, selectSubsIndex))]
|
||||
log("Set up subtitles: %s %s" % (selectSubsIndex, url), 1)
|
||||
self.logMsg("Set up subtitles: %s %s" % (selectSubsIndex, url), 1)
|
||||
listitem.setSubtitles(url)
|
||||
else:
|
||||
# Burn subtitles
|
||||
|
|
|
@ -42,8 +42,7 @@ class Read_EmbyServer():
|
|||
# This will return the full item
|
||||
item = {}
|
||||
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s?format=json" % itemid
|
||||
result = self.doUtils(url)
|
||||
result = self.doUtils("{server}/metaman/Users/{UserId}/Items/%s?format=json" % itemid)
|
||||
if result:
|
||||
item = result
|
||||
|
||||
|
@ -56,13 +55,12 @@ class Read_EmbyServer():
|
|||
itemlists = self.split_list(itemlist, 50)
|
||||
for itemlist in itemlists:
|
||||
# Will return basic information
|
||||
url = "{server}/emby/Users/{UserId}/Items?&format=json"
|
||||
params = {
|
||||
|
||||
'Ids': ",".join(itemlist),
|
||||
'Fields': "Etag"
|
||||
}
|
||||
result = self.doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Users/{UserId}/Items?&format=json", parameters=params)
|
||||
if result:
|
||||
items.extend(result['Items'])
|
||||
|
||||
|
@ -75,7 +73,6 @@ class Read_EmbyServer():
|
|||
itemlists = self.split_list(itemlist, 50)
|
||||
for itemlist in itemlists:
|
||||
|
||||
url = "{server}/emby/Users/{UserId}/Items?format=json"
|
||||
params = {
|
||||
|
||||
"Ids": ",".join(itemlist),
|
||||
|
@ -89,7 +86,7 @@ class Read_EmbyServer():
|
|||
"MediaSources"
|
||||
)
|
||||
}
|
||||
result = self.doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
|
||||
if result:
|
||||
items.extend(result['Items'])
|
||||
|
||||
|
@ -98,13 +95,10 @@ class Read_EmbyServer():
|
|||
def getView_embyId(self, itemid):
|
||||
# Returns ancestors using embyId
|
||||
viewId = None
|
||||
url = "{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid
|
||||
result = self.doUtils(url)
|
||||
|
||||
for view in result:
|
||||
for view in self.doUtils("{server}/emby/Items/%s/Ancestors?UserId={UserId}&format=json" % itemid):
|
||||
|
||||
viewtype = view['Type']
|
||||
if viewtype == "CollectionFolder":
|
||||
if view['Type'] == "CollectionFolder":
|
||||
# Found view
|
||||
viewId = view['Id']
|
||||
|
||||
|
@ -131,8 +125,6 @@ class Read_EmbyServer():
|
|||
return [viewName, viewId, mediatype]
|
||||
|
||||
def getFilteredSection(self, parentid, itemtype=None, sortby="SortName", recursive=True, limit=None, sortorder="Ascending", filter=""):
|
||||
doUtils = self.doUtils
|
||||
url = "{server}/emby/Users/{UserId}/Items?format=json"
|
||||
params = {
|
||||
|
||||
'ParentId': parentid,
|
||||
|
@ -151,11 +143,9 @@ class Read_EmbyServer():
|
|||
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
|
||||
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
|
||||
}
|
||||
return doUtils(url, parameters=params)
|
||||
return self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
|
||||
|
||||
def getTvChannels(self):
|
||||
doUtils = self.doUtils
|
||||
url = "{server}/emby/LiveTv/Channels/?userid={UserId}&format=json"
|
||||
params = {
|
||||
|
||||
'EnableImages': True,
|
||||
|
@ -165,11 +155,9 @@ class Read_EmbyServer():
|
|||
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
|
||||
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
|
||||
}
|
||||
return doUtils(url, parameters=params)
|
||||
return self.doUtils("{server}/emby/LiveTv/Channels/?userid={UserId}&format=json", parameters=params)
|
||||
|
||||
def getTvRecordings(self, groupid):
|
||||
doUtils = self.doUtils
|
||||
url = "{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json"
|
||||
if groupid == "root": groupid = ""
|
||||
params = {
|
||||
|
||||
|
@ -181,13 +169,10 @@ class Read_EmbyServer():
|
|||
"CriticRating,CriticRatingSummary,Etag,ShortOverview,ProductionLocations,"
|
||||
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers")
|
||||
}
|
||||
return doUtils(url, parameters=params)
|
||||
return self.doUtils("{server}/emby/LiveTv/Recordings/?userid={UserId}&format=json", parameters=params)
|
||||
|
||||
def getSection(self, parentid, itemtype=None, sortby="SortName", basic=False, dialog=None):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
doUtils = self.doUtils
|
||||
items = {
|
||||
|
||||
'Items': [],
|
||||
|
@ -206,13 +191,13 @@ class Read_EmbyServer():
|
|||
'Recursive': True,
|
||||
'Limit': 1
|
||||
}
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils(url, parameters=params)
|
||||
try:
|
||||
total = result['TotalRecordCount']
|
||||
items['TotalRecordCount'] = total
|
||||
|
||||
except TypeError: # Failed to retrieve
|
||||
log("%s:%s Failed to retrieve the server response." % (url, params), 2)
|
||||
self.logMsg("%s:%s Failed to retrieve the server response." % (url, params), 2)
|
||||
|
||||
else:
|
||||
index = 0
|
||||
|
@ -247,34 +232,34 @@ class Read_EmbyServer():
|
|||
"Tags,ProviderIds,ParentId,RemoteTrailers,SpecialEpisodeNumbers,"
|
||||
"MediaSources"
|
||||
)
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils(url, parameters=params)
|
||||
try:
|
||||
items['Items'].extend(result['Items'])
|
||||
except TypeError:
|
||||
# Something happened to the connection
|
||||
if not throttled:
|
||||
throttled = True
|
||||
log("Throttle activated.", 1)
|
||||
self.logMsg("Throttle activated.", 1)
|
||||
|
||||
if jump == highestjump:
|
||||
# We already tried with the highestjump, but it failed. Reset value.
|
||||
log("Reset highest value.", 1)
|
||||
self.logMsg("Reset highest value.", 1)
|
||||
highestjump = 0
|
||||
|
||||
# Lower the number by half
|
||||
if highestjump:
|
||||
throttled = False
|
||||
jump = highestjump
|
||||
log("Throttle deactivated.", 1)
|
||||
self.logMsg("Throttle deactivated.", 1)
|
||||
else:
|
||||
jump = int(jump/4)
|
||||
log("Set jump limit to recover: %s" % jump, 2)
|
||||
self.logMsg("Set jump limit to recover: %s" % jump, 2)
|
||||
|
||||
retry = 0
|
||||
while utils.window('emby_online') != "true":
|
||||
# Wait server to come back online
|
||||
if retry == 5:
|
||||
log("Unable to reconnect to server. Abort process.", 1)
|
||||
self.logMsg("Unable to reconnect to server. Abort process.", 1)
|
||||
return items
|
||||
|
||||
retry += 1
|
||||
|
@ -302,12 +287,11 @@ class Read_EmbyServer():
|
|||
increment = 10
|
||||
|
||||
jump += increment
|
||||
log("Increase jump limit to: %s" % jump, 1)
|
||||
self.logMsg("Increase jump limit to: %s" % jump, 1)
|
||||
return items
|
||||
|
||||
def getViews(self, mediatype="", root=False, sortedlist=False):
|
||||
# Build a list of user views
|
||||
doUtils = self.doUtils
|
||||
views = []
|
||||
mediatype = mediatype.lower()
|
||||
|
||||
|
@ -316,7 +300,7 @@ class Read_EmbyServer():
|
|||
else: # Views ungrouped
|
||||
url = "{server}/emby/Users/{UserId}/Items?Sortby=SortName&format=json"
|
||||
|
||||
result = doUtils(url)
|
||||
result = self.doUtils(url)
|
||||
try:
|
||||
items = result['Items']
|
||||
except TypeError:
|
||||
|
@ -324,11 +308,8 @@ class Read_EmbyServer():
|
|||
else:
|
||||
for item in items:
|
||||
|
||||
name = item['Name']
|
||||
itemId = item['Id']
|
||||
viewtype = item['Type']
|
||||
|
||||
if viewtype == "Channel":
|
||||
item['Name'] = item['Name']
|
||||
if item['Type'] == "Channel":
|
||||
# Filter view types
|
||||
continue
|
||||
|
||||
|
@ -339,20 +320,20 @@ class Read_EmbyServer():
|
|||
# Assumed missing is mixed then.
|
||||
'''if itemtype is None:
|
||||
url = "{server}/emby/Library/MediaFolders?format=json"
|
||||
result = doUtils(url)
|
||||
result = self.doUtils(url)
|
||||
|
||||
for folder in result['Items']:
|
||||
if itemId == folder['Id']:
|
||||
if item['Id'] == folder['Id']:
|
||||
itemtype = folder.get('CollectionType', "mixed")'''
|
||||
|
||||
if name not in ('Collections', 'Trailers'):
|
||||
if item['Name'] not in ('Collections', 'Trailers'):
|
||||
|
||||
if sortedlist:
|
||||
views.append({
|
||||
|
||||
'name': name,
|
||||
'name': item['Name'],
|
||||
'type': itemtype,
|
||||
'id': itemId
|
||||
'id': item['Id']
|
||||
})
|
||||
|
||||
elif (itemtype == mediatype or
|
||||
|
@ -360,9 +341,9 @@ class Read_EmbyServer():
|
|||
|
||||
views.append({
|
||||
|
||||
'name': name,
|
||||
'name': item['Name'],
|
||||
'type': itemtype,
|
||||
'id': itemId
|
||||
'id': item['Id']
|
||||
})
|
||||
|
||||
return views
|
||||
|
@ -370,8 +351,6 @@ class Read_EmbyServer():
|
|||
def verifyView(self, parentid, itemid):
|
||||
|
||||
belongs = False
|
||||
|
||||
url = "{server}/emby/Users/{UserId}/Items?format=json"
|
||||
params = {
|
||||
|
||||
'ParentId': parentid,
|
||||
|
@ -381,7 +360,7 @@ class Read_EmbyServer():
|
|||
'Recursive': True,
|
||||
'Ids': itemid
|
||||
}
|
||||
result = self.doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Users/{UserId}/Items?format=json", parameters=params)
|
||||
try:
|
||||
total = result['TotalRecordCount']
|
||||
except TypeError:
|
||||
|
@ -394,40 +373,23 @@ class Read_EmbyServer():
|
|||
return belongs
|
||||
|
||||
def getMovies(self, parentId, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(parentId, "Movie", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(parentId, "Movie", basic=basic, dialog=dialog)
|
||||
|
||||
def getBoxset(self, dialog=None):
|
||||
|
||||
items = self.getSection(None, "BoxSet", dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(None, "BoxSet", dialog=dialog)
|
||||
|
||||
def getMovies_byBoxset(self, boxsetid):
|
||||
|
||||
items = self.getSection(boxsetid, "Movie")
|
||||
|
||||
return items
|
||||
return self.getSection(boxsetid, "Movie")
|
||||
|
||||
def getMusicVideos(self, parentId, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(parentId, "MusicVideo", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(parentId, "MusicVideo", basic=basic, dialog=dialog)
|
||||
|
||||
def getHomeVideos(self, parentId):
|
||||
|
||||
items = self.getSection(parentId, "Video")
|
||||
|
||||
return items
|
||||
return self.getSection(parentId, "Video")
|
||||
|
||||
def getShows(self, parentId, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(parentId, "Series", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(parentId, "Series", basic=basic, dialog=dialog)
|
||||
|
||||
def getSeasons(self, showId):
|
||||
|
||||
|
@ -437,13 +399,12 @@ class Read_EmbyServer():
|
|||
'TotalRecordCount': 0
|
||||
}
|
||||
|
||||
url = "{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId
|
||||
params = {
|
||||
|
||||
'IsVirtualUnaired': False,
|
||||
'Fields': "Etag"
|
||||
}
|
||||
result = self.doUtils(url, parameters=params)
|
||||
result = self.doUtils("{server}/emby/Shows/%s/Seasons?UserId={UserId}&format=json" % showId, parameters=params)
|
||||
if result:
|
||||
items = result
|
||||
|
||||
|
@ -451,25 +412,19 @@ class Read_EmbyServer():
|
|||
|
||||
def getEpisodes(self, parentId, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(parentId, "Episode", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(parentId, "Episode", basic=basic, dialog=dialog)
|
||||
|
||||
def getEpisodesbyShow(self, showId):
|
||||
|
||||
items = self.getSection(showId, "Episode")
|
||||
|
||||
return items
|
||||
return self.getSection(showId, "Episode")
|
||||
|
||||
def getEpisodesbySeason(self, seasonId):
|
||||
|
||||
items = self.getSection(seasonId, "Episode")
|
||||
return self.getSection(seasonId, "Episode")
|
||||
|
||||
return items
|
||||
|
||||
def getArtists(self, dialog=None):
|
||||
|
||||
doUtils = self.doUtils
|
||||
items = {
|
||||
|
||||
'Items': [],
|
||||
|
@ -483,7 +438,7 @@ class Read_EmbyServer():
|
|||
'Recursive': True,
|
||||
'Limit': 1
|
||||
}
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils(url, parameters=params)
|
||||
try:
|
||||
total = result['TotalRecordCount']
|
||||
items['TotalRecordCount'] = total
|
||||
|
@ -513,7 +468,7 @@ class Read_EmbyServer():
|
|||
"AirTime,DateCreated,MediaStreams,People,ProviderIds,Overview"
|
||||
)
|
||||
}
|
||||
result = doUtils(url, parameters=params)
|
||||
result = self.doUtils(url, parameters=params)
|
||||
items['Items'].extend(result['Items'])
|
||||
|
||||
index += jump
|
||||
|
@ -523,28 +478,17 @@ class Read_EmbyServer():
|
|||
return items
|
||||
|
||||
def getAlbums(self, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(None, "MusicAlbum", sortby="DateCreated", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(None, "MusicAlbum", sortby="DateCreated", basic=basic, dialog=dialog)
|
||||
|
||||
def getAlbumsbyArtist(self, artistId):
|
||||
|
||||
items = self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
|
||||
|
||||
return items
|
||||
return self.getSection(artistId, "MusicAlbum", sortby="DateCreated")
|
||||
|
||||
def getSongs(self, basic=False, dialog=None):
|
||||
|
||||
items = self.getSection(None, "Audio", basic=basic, dialog=dialog)
|
||||
|
||||
return items
|
||||
return self.getSection(None, "Audio", basic=basic, dialog=dialog)
|
||||
|
||||
def getSongsbyAlbum(self, albumId):
|
||||
return self.getSection(albumId, "Audio")
|
||||
|
||||
items = self.getSection(albumId, "Audio")
|
||||
|
||||
return items
|
||||
|
||||
def getAdditionalParts(self, itemId):
|
||||
|
||||
|
@ -554,8 +498,7 @@ class Read_EmbyServer():
|
|||
'TotalRecordCount': 0
|
||||
}
|
||||
|
||||
url = "{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId
|
||||
result = self.doUtils(url)
|
||||
result = self.doUtils("{server}/emby/Videos/%s/AdditionalParts?UserId={UserId}&format=json" % itemId)
|
||||
if result:
|
||||
items = result
|
||||
|
||||
|
@ -577,24 +520,18 @@ class Read_EmbyServer():
|
|||
|
||||
def updateUserRating(self, itemid, like=None, favourite=None, deletelike=False):
|
||||
# Updates the user rating to Emby
|
||||
doUtils = self.doUtils
|
||||
|
||||
if favourite:
|
||||
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
|
||||
doUtils(url, type="POST")
|
||||
self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="POST")
|
||||
elif favourite == False:
|
||||
url = "{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid
|
||||
doUtils(url, type="DELETE")
|
||||
self.doUtils("{server}/emby/Users/{UserId}/FavoriteItems/%s?format=json" % itemid, action_type="DELETE")
|
||||
|
||||
if not deletelike and like:
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid
|
||||
doUtils(url, type="POST")
|
||||
elif not deletelike and like == False:
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid
|
||||
doUtil(url, type="POST")
|
||||
self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=true&format=json" % itemid, action_type="POST")
|
||||
elif not deletelike and like is False:
|
||||
self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?Likes=false&format=json" % itemid, action_type="POST")
|
||||
elif deletelike:
|
||||
url = "{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid
|
||||
doUtils(url, type="DELETE")
|
||||
self.doUtils("{server}/emby/Users/{UserId}/Items/%s/Rating?format=json" % itemid, action_type="DELETE")
|
||||
|
||||
self.logMsg("Update user rating to emby for itemid: %s "
|
||||
"| like: %s | favourite: %s | deletelike: %s"
|
||||
|
|
|
@ -81,7 +81,6 @@ class UserClient(threading.Thread):
|
|||
|
||||
def getUserId(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
|
||||
|
@ -94,17 +93,17 @@ class UserClient(threading.Thread):
|
|||
if not s_userId:
|
||||
# Save access token if it's missing from settings
|
||||
settings('userId%s' % username, value=w_userId)
|
||||
log("Returning userId from WINDOW for username: %s UserId: %s"
|
||||
self.logMsg("Returning userId from WINDOW for username: %s UserId: %s"
|
||||
% (username, w_userId), 2)
|
||||
return w_userId
|
||||
# Verify the settings
|
||||
elif s_userId:
|
||||
log("Returning userId from SETTINGS for username: %s userId: %s"
|
||||
self.logMsg("Returning userId from SETTINGS for username: %s userId: %s"
|
||||
% (username, s_userId), 2)
|
||||
return s_userId
|
||||
# No userId found
|
||||
else:
|
||||
log("No userId saved for username: %s." % username, 1)
|
||||
self.logMsg("No userId saved for username: %s." % username, 1)
|
||||
|
||||
def getServer(self, prefix=True):
|
||||
|
||||
|
@ -142,7 +141,6 @@ class UserClient(threading.Thread):
|
|||
|
||||
def getToken(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
|
||||
|
@ -156,17 +154,17 @@ class UserClient(threading.Thread):
|
|||
if not s_token:
|
||||
# Save access token if it's missing from settings
|
||||
settings('accessToken', value=w_token)
|
||||
log("Returning accessToken from WINDOW for username: %s accessToken: %s"
|
||||
self.logMsg("Returning accessToken from WINDOW for username: %s accessToken: %s"
|
||||
% (username, w_token), 2)
|
||||
return w_token
|
||||
# Verify the settings
|
||||
elif s_token:
|
||||
log("Returning accessToken from SETTINGS for username: %s accessToken: %s"
|
||||
self.logMsg("Returning accessToken from SETTINGS for username: %s accessToken: %s"
|
||||
% (username, s_token), 2)
|
||||
window('emby_accessToken%s' % username, value=s_token)
|
||||
return s_token
|
||||
else:
|
||||
log("No token found.", 1)
|
||||
self.logMsg("No token found.", 1)
|
||||
return ""
|
||||
|
||||
def getSSLverify(self):
|
||||
|
@ -198,46 +196,37 @@ class UserClient(threading.Thread):
|
|||
def setUserPref(self):
|
||||
|
||||
doUtils = self.doUtils.downloadUrl
|
||||
art = artwork.Artwork()
|
||||
|
||||
url = "{server}/emby/Users/{UserId}?format=json"
|
||||
result = doUtils(url)
|
||||
result = doUtils("{server}/emby/Users/{UserId}?format=json")
|
||||
self.userSettings = result
|
||||
# Set user image for skin display
|
||||
if result.get('PrimaryImageTag'):
|
||||
utils.window('EmbyUserImage', value=art.getUserArtwork(result['Id'], 'Primary'))
|
||||
utils.window('EmbyUserImage', value=artwork.Artwork().getUserArtwork(result['Id'], 'Primary'))
|
||||
|
||||
# Set resume point max
|
||||
url = "{server}/emby/System/Configuration?format=json"
|
||||
result = doUtils(url)
|
||||
result = doUtils("{server}/emby/System/Configuration?format=json")
|
||||
|
||||
utils.settings('markPlayed', value=str(result['MaxResumePct']))
|
||||
|
||||
def getPublicUsers(self):
|
||||
|
||||
server = self.getServer()
|
||||
|
||||
# Get public Users
|
||||
url = "%s/emby/Users/Public?format=json" % server
|
||||
result = self.doUtils.downloadUrl(url, authenticate=False)
|
||||
|
||||
result = self.doUtils.downloadUrl("%s/emby/Users/Public?format=json" % self.getServer(), authenticate=False)
|
||||
if result != "":
|
||||
return result
|
||||
else:
|
||||
# Server connection failed
|
||||
return False
|
||||
|
||||
|
||||
def hasAccess(self):
|
||||
# hasAccess is verified in service.py
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
|
||||
url = "{server}/emby/Users?format=json"
|
||||
result = self.doUtils.downloadUrl(url)
|
||||
result = self.doUtils.downloadUrl("{server}/emby/Users?format=json")
|
||||
|
||||
if result == False:
|
||||
# Access is restricted, set in downloadutils.py via exception
|
||||
log("Access is restricted.", 1)
|
||||
self.logMsg("Access is restricted.", 1)
|
||||
self.HasAccess = False
|
||||
|
||||
elif window('emby_online') != "true":
|
||||
|
@ -245,7 +234,7 @@ class UserClient(threading.Thread):
|
|||
pass
|
||||
|
||||
elif window('emby_serverStatus') == "restricted":
|
||||
log("Access is granted.", 1)
|
||||
self.logMsg("Access is granted.", 1)
|
||||
self.HasAccess = True
|
||||
window('emby_serverStatus', clear=True)
|
||||
xbmcgui.Dialog().notification("Emby for Kodi", utils.language(33007))
|
||||
|
@ -301,7 +290,6 @@ class UserClient(threading.Thread):
|
|||
|
||||
def authenticate(self):
|
||||
|
||||
log = self.logMsg
|
||||
lang = utils.language
|
||||
window = utils.window
|
||||
settings = utils.settings
|
||||
|
@ -316,24 +304,24 @@ class UserClient(threading.Thread):
|
|||
|
||||
# If there's no settings.xml
|
||||
if not hasSettings:
|
||||
log("No settings.xml found.", 1)
|
||||
self.logMsg("No settings.xml found.", 1)
|
||||
self.auth = False
|
||||
return
|
||||
# If no user information
|
||||
elif not server or not username:
|
||||
log("Missing server information.", 1)
|
||||
self.logMsg("Missing server information.", 1)
|
||||
self.auth = False
|
||||
return
|
||||
# If there's a token, load the user
|
||||
elif self.getToken():
|
||||
result = self.loadCurrUser()
|
||||
|
||||
if result == False:
|
||||
if result is False:
|
||||
pass
|
||||
else:
|
||||
log("Current user: %s" % self.currUser, 1)
|
||||
log("Current userId: %s" % self.currUserId, 1)
|
||||
log("Current accessToken: %s" % self.currToken, 2)
|
||||
self.logMsg("Current user: %s" % self.currUser, 1)
|
||||
self.logMsg("Current userId: %s" % self.currUserId, 1)
|
||||
self.logMsg("Current accessToken: %s" % self.currToken, 2)
|
||||
return
|
||||
|
||||
##### AUTHENTICATE USER #####
|
||||
|
@ -353,7 +341,7 @@ class UserClient(threading.Thread):
|
|||
option=xbmcgui.ALPHANUM_HIDE_INPUT)
|
||||
# If password dialog is cancelled
|
||||
if not password:
|
||||
log("No password entered.", 0)
|
||||
self.logMsg("No password entered.", 0)
|
||||
window('emby_serverStatus', value="Stop")
|
||||
self.auth = False
|
||||
return
|
||||
|
@ -367,40 +355,38 @@ class UserClient(threading.Thread):
|
|||
sha1 = sha1.hexdigest()
|
||||
|
||||
# Authenticate username and password
|
||||
url = "%s/emby/Users/AuthenticateByName?format=json" % server
|
||||
data = {'username': username, 'password': sha1}
|
||||
log(data, 2)
|
||||
self.logMsg(data, 2)
|
||||
|
||||
result = self.doUtils.downloadUrl(url, postBody=data, type="POST", authenticate=False)
|
||||
result = self.doUtils.downloadUrl("%s/emby/Users/AuthenticateByName?format=json" % server, postBody=data, action_type="POST", authenticate=False)
|
||||
|
||||
try:
|
||||
log("Auth response: %s" % result, 1)
|
||||
self.logMsg("Auth response: %s" % result, 1)
|
||||
accessToken = result['AccessToken']
|
||||
|
||||
except (KeyError, TypeError):
|
||||
log("Failed to retrieve the api key.", 1)
|
||||
self.logMsg("Failed to retrieve the api key.", 1)
|
||||
accessToken = None
|
||||
|
||||
if accessToken is not None:
|
||||
self.currUser = username
|
||||
dialog.notification("Emby for Kodi",
|
||||
"%s %s!" % (lang(33000), self.currUser.decode('utf-8')))
|
||||
userId = result['User']['Id']
|
||||
settings('accessToken', value=accessToken)
|
||||
settings('userId%s' % username, value=userId)
|
||||
log("User Authenticated: %s" % accessToken, 1)
|
||||
settings('userId%s' % username, value=result['User']['Id'])
|
||||
self.logMsg("User Authenticated: %s" % accessToken, 1)
|
||||
self.loadCurrUser(authenticated=True)
|
||||
window('emby_serverStatus', clear=True)
|
||||
self.retry = 0
|
||||
else:
|
||||
log("User authentication failed.", 1)
|
||||
self.logMsg("User authentication failed.", 1)
|
||||
settings('accessToken', value="")
|
||||
settings('userId%s' % username, value="")
|
||||
dialog.ok(lang(33001), lang(33009))
|
||||
|
||||
# Give two attempts at entering password
|
||||
if self.retry == 2:
|
||||
log("Too many retries. "
|
||||
self.logMsg("Too many retries. "
|
||||
"You can retry by resetting attempts in the addon settings.", 1)
|
||||
window('emby_serverStatus', value="Stop")
|
||||
dialog.ok(lang(33001), lang(33010))
|
||||
|
@ -410,28 +396,23 @@ class UserClient(threading.Thread):
|
|||
|
||||
def resetClient(self):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
log("Reset UserClient authentication.", 1)
|
||||
userId = self.getUserId()
|
||||
|
||||
self.logMsg("Reset UserClient authentication.", 1)
|
||||
if self.currToken is not None:
|
||||
# In case of 401, removed saved token
|
||||
utils.settings('accessToken', value="")
|
||||
utils.window('emby_accessToken%s' % userId, clear=True)
|
||||
utils.window('emby_accessToken%s' % self.getUserId(), clear=True)
|
||||
self.currToken = None
|
||||
log("User token has been removed.", 1)
|
||||
self.logMsg("User token has been removed.", 1)
|
||||
|
||||
self.auth = True
|
||||
self.currUser = None
|
||||
|
||||
def run(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
|
||||
monitor = xbmc.Monitor()
|
||||
log("----===## Starting UserClient ##===----", 0)
|
||||
self.logMsg("----===## Starting UserClient ##===----", 0)
|
||||
|
||||
while not monitor.abortRequested():
|
||||
|
||||
|
@ -466,8 +447,8 @@ class UserClient(threading.Thread):
|
|||
# The status Stop is for when user cancelled password dialog.
|
||||
if server and username and status != "Stop":
|
||||
# Only if there's information found to login
|
||||
log("Server found: %s" % server, 2)
|
||||
log("Username found: %s" % username, 2)
|
||||
self.logMsg("Server found: %s" % server, 2)
|
||||
self.logMsg("Username found: %s" % username, 2)
|
||||
self.auth = True
|
||||
|
||||
|
||||
|
@ -480,7 +461,7 @@ class UserClient(threading.Thread):
|
|||
break
|
||||
|
||||
self.doUtils.stopSession()
|
||||
log("##===---- UserClient Stopped ----===##", 0)
|
||||
self.logMsg("##===---- UserClient Stopped ----===##", 0)
|
||||
|
||||
def stopClient(self):
|
||||
# When emby for kodi terminates
|
||||
|
|
|
@ -62,26 +62,23 @@ def window(property, value=None, clear=False, windowid=10000):
|
|||
|
||||
def settings(setting, value=None):
|
||||
# Get or add addon setting
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
|
||||
if value is not None:
|
||||
addon.setSetting(setting, value)
|
||||
xbmcaddon.Addon(id='plugin.video.metaman').setSetting(setting, value)
|
||||
else:
|
||||
return addon.getSetting(setting) #returns unicode object
|
||||
return xbmcaddon.Addon(id='plugin.video.metaman').getSetting(setting) #returns unicode object
|
||||
|
||||
def language(stringid):
|
||||
# Central string retrieval
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
string = addon.getLocalizedString(stringid) #returns unicode object
|
||||
string = xbmcaddon.Addon(id='plugin.video.emby').getLocalizedString(stringid) #returns unicode object
|
||||
return string
|
||||
|
||||
def kodiSQL(type="video"):
|
||||
def kodiSQL(media_type="video"):
|
||||
|
||||
if type == "emby":
|
||||
if media_type == "emby":
|
||||
dbPath = xbmc.translatePath("special://database/emby.db").decode('utf-8')
|
||||
elif type == "music":
|
||||
elif media_type == "music":
|
||||
dbPath = getKodiMusicDBPath()
|
||||
elif type == "texture":
|
||||
elif media_type == "texture":
|
||||
dbPath = xbmc.translatePath("special://database/Textures13.db").decode('utf-8')
|
||||
else:
|
||||
dbPath = getKodiVideoDBPath()
|
||||
|
@ -91,7 +88,6 @@ def kodiSQL(type="video"):
|
|||
|
||||
def getKodiVideoDBPath():
|
||||
|
||||
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
|
||||
dbVersion = {
|
||||
|
||||
"13": 78, # Gotham
|
||||
|
@ -102,12 +98,11 @@ def getKodiVideoDBPath():
|
|||
|
||||
dbPath = xbmc.translatePath(
|
||||
"special://database/MyVideos%s.db"
|
||||
% dbVersion.get(kodibuild, "")).decode('utf-8')
|
||||
% dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
|
||||
return dbPath
|
||||
|
||||
def getKodiMusicDBPath():
|
||||
|
||||
kodibuild = xbmc.getInfoLabel('System.BuildVersion')[:2]
|
||||
dbVersion = {
|
||||
|
||||
"13": 46, # Gotham
|
||||
|
@ -118,7 +113,7 @@ def getKodiMusicDBPath():
|
|||
|
||||
dbPath = xbmc.translatePath(
|
||||
"special://database/MyMusic%s.db"
|
||||
% dbVersion.get(kodibuild, "")).decode('utf-8')
|
||||
% dbVersion.get(xbmc.getInfoLabel('System.BuildVersion')[:2], "")).decode('utf-8')
|
||||
return dbPath
|
||||
|
||||
def getScreensaver():
|
||||
|
@ -133,11 +128,7 @@ def getScreensaver():
|
|||
'setting': "screensaver.mode"
|
||||
}
|
||||
}
|
||||
result = xbmc.executeJSONRPC(json.dumps(query))
|
||||
result = json.loads(result)
|
||||
screensaver = result['result']['value']
|
||||
|
||||
return screensaver
|
||||
return json.loads(xbmc.executeJSONRPC(json.dumps(query)))['result']['value']
|
||||
|
||||
def setScreensaver(value):
|
||||
# Toggle the screensaver
|
||||
|
@ -152,15 +143,13 @@ def setScreensaver(value):
|
|||
'value': value
|
||||
}
|
||||
}
|
||||
result = xbmc.executeJSONRPC(json.dumps(query))
|
||||
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, result), 1)
|
||||
logMsg("EMBY", "Toggling screensaver: %s %s" % (value, xbmc.executeJSONRPC(json.dumps(query))), 1)
|
||||
|
||||
def reset():
|
||||
|
||||
dialog = xbmcgui.Dialog()
|
||||
|
||||
resp = dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?")
|
||||
if resp == 0:
|
||||
if dialog.yesno("Warning", "Are you sure you want to reset your local Kodi database?") == 0:
|
||||
return
|
||||
|
||||
# first stop any db sync
|
||||
|
@ -222,7 +211,7 @@ def reset():
|
|||
cursor.close()
|
||||
|
||||
# Offer to wipe cached thumbnails
|
||||
resp = dialog.yesno("Warning", "Removed all cached artwork?")
|
||||
resp = dialog.yesno("Warning", "Remove all cached artwork?")
|
||||
if resp:
|
||||
logMsg("EMBY", "Resetting all cached artwork.", 0)
|
||||
# Remove all existing textures first
|
||||
|
@ -418,9 +407,7 @@ def passwordsXML():
|
|||
|
||||
elif option == 1:
|
||||
# User selected remove
|
||||
iterator = root.getiterator('passwords')
|
||||
|
||||
for paths in iterator:
|
||||
for paths in root.getiterator('passwords'):
|
||||
for path in paths:
|
||||
if path.find('.//from').text == "smb://%s/" % credentials:
|
||||
paths.remove(path)
|
||||
|
|
|
@ -55,7 +55,6 @@ class VideoNodes(object):
|
|||
def viewNode(self, indexnumber, tagname, mediatype, viewtype, viewid, delete=False):
|
||||
|
||||
window = utils.window
|
||||
kodiversion = self.kodiversion
|
||||
|
||||
if viewtype == "mixed":
|
||||
dirname = "%s - %s" % (viewid, mediatype)
|
||||
|
@ -203,10 +202,10 @@ class VideoNodes(object):
|
|||
elif nodetype == "nextepisodes":
|
||||
# Custom query
|
||||
path = "plugin://plugin.video.emby/?id=%s&mode=nextup&limit=25" % tagname
|
||||
elif kodiversion == 14 and nodetype == "recentepisodes":
|
||||
elif self.kodiversion == 14 and nodetype == "recentepisodes":
|
||||
# Custom query
|
||||
path = "plugin://plugin.video.emby/?id=%s&mode=recentepisodes&limit=25" % tagname
|
||||
elif kodiversion == 14 and nodetype == "inprogressepisodes":
|
||||
elif self.kodiversion == 14 and nodetype == "inprogressepisodes":
|
||||
# Custom query
|
||||
path = "plugin://plugin.video.emby/?id=%s&mode=inprogressepisodes&limit=25"% tagname
|
||||
else:
|
||||
|
@ -247,7 +246,7 @@ class VideoNodes(object):
|
|||
|
||||
# Create the root
|
||||
if (nodetype == "nextepisodes" or mediatype == "homevideos" or
|
||||
(kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
|
||||
(self.kodiversion == 14 and nodetype in ('recentepisodes', 'inprogressepisodes'))):
|
||||
# Folder type with plugin path
|
||||
root = self.commonRoot(order=node, label=label, tagname=tagname, roottype=2)
|
||||
etree.SubElement(root, 'path').text = path
|
||||
|
|
|
@ -455,7 +455,6 @@ class WebSocket(object):
|
|||
self._handshake(hostname, port, resource, **options)
|
||||
|
||||
def _handshake(self, host, port, resource, **options):
|
||||
sock = self.sock
|
||||
headers = []
|
||||
headers.append("GET %s HTTP/1.1" % resource)
|
||||
headers.append("Upgrade: websocket")
|
||||
|
|
|
@ -51,9 +51,7 @@ class WebSocket_Client(threading.Thread):
|
|||
|
||||
def sendProgressUpdate(self, data):
|
||||
|
||||
log = self.logMsg
|
||||
|
||||
log("sendProgressUpdate", 2)
|
||||
self.logMsg("sendProgressUpdate", 2)
|
||||
try:
|
||||
messageData = {
|
||||
|
||||
|
@ -62,14 +60,13 @@ class WebSocket_Client(threading.Thread):
|
|||
}
|
||||
messageString = json.dumps(messageData)
|
||||
self.client.send(messageString)
|
||||
log("Message data: %s" % messageString, 2)
|
||||
self.logMsg("Message data: %s" % messageString, 2)
|
||||
|
||||
except Exception as e:
|
||||
log("Exception: %s" % e, 1)
|
||||
self.logMsg("Exception: %s" % e, 1)
|
||||
|
||||
def on_message(self, ws, message):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
lang = utils.language
|
||||
|
||||
|
@ -79,7 +76,7 @@ class WebSocket_Client(threading.Thread):
|
|||
|
||||
if messageType not in ('SessionEnded'):
|
||||
# Mute certain events
|
||||
log("Message: %s" % message, 1)
|
||||
self.logMsg("Message: %s" % message, 1)
|
||||
|
||||
if messageType == "Play":
|
||||
# A remote control play command has been sent from the server.
|
||||
|
@ -129,10 +126,10 @@ class WebSocket_Client(threading.Thread):
|
|||
seekto = data['SeekPositionTicks']
|
||||
seektime = seekto / 10000000.0
|
||||
action(seektime)
|
||||
log("Seek to %s." % seektime, 1)
|
||||
self.logMsg("Seek to %s." % seektime, 1)
|
||||
else:
|
||||
action()
|
||||
log("Command: %s completed." % command, 1)
|
||||
self.logMsg("Command: %s completed." % command, 1)
|
||||
|
||||
window('emby_command', value="true")
|
||||
|
||||
|
@ -279,26 +276,21 @@ class WebSocket_Client(threading.Thread):
|
|||
|
||||
def run(self):
|
||||
|
||||
log = self.logMsg
|
||||
window = utils.window
|
||||
monitor = self.monitor
|
||||
|
||||
loglevel = int(window('emby_logLevel'))
|
||||
# websocket.enableTrace(True)
|
||||
|
||||
userId = window('emby_currUser')
|
||||
server = window('emby_server%s' % userId)
|
||||
token = window('emby_accessToken%s' % userId)
|
||||
deviceId = self.deviceId
|
||||
|
||||
# Get the appropriate prefix for the websocket
|
||||
if "https" in server:
|
||||
server = server.replace('https', "wss")
|
||||
else:
|
||||
server = server.replace('http', "ws")
|
||||
|
||||
websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, deviceId)
|
||||
log("websocket url: %s" % websocket_url, 1)
|
||||
websocket_url = "%s?api_key=%s&deviceId=%s" % (server, token, self.deviceId)
|
||||
self.logMsg("websocket url: %s" % websocket_url, 1)
|
||||
|
||||
self.client = websocket.WebSocketApp(websocket_url,
|
||||
on_message=self.on_message,
|
||||
|
@ -306,19 +298,19 @@ class WebSocket_Client(threading.Thread):
|
|||
on_close=self.on_close)
|
||||
|
||||
self.client.on_open = self.on_open
|
||||
log("----===## Starting WebSocketClient ##===----", 0)
|
||||
self.logMsg("----===## Starting WebSocketClient ##===----", 0)
|
||||
|
||||
while not monitor.abortRequested():
|
||||
while not self.monitor.abortRequested():
|
||||
|
||||
self.client.run_forever(ping_interval=10)
|
||||
if self.stopWebsocket:
|
||||
break
|
||||
|
||||
if monitor.waitForAbort(5):
|
||||
if self.monitor.waitForAbort(5):
|
||||
# Abort was requested, exit
|
||||
break
|
||||
|
||||
log("##===---- WebSocketClient Stopped ----===##", 0)
|
||||
self.logMsg("##===---- WebSocketClient Stopped ----===##", 0)
|
||||
|
||||
def stopClient(self):
|
||||
|
||||
|
|
Loading…
Reference in a new issue