Merge pull request #3 from MediaBrowser/database_changes
Database changes
This commit is contained in:
commit
5f486468ba
16 changed files with 1792 additions and 2694 deletions
77
default.py
77
default.py
|
@ -2,6 +2,7 @@ import xbmcaddon
|
||||||
import xbmcplugin
|
import xbmcplugin
|
||||||
import xbmc
|
import xbmc
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
|
import xbmcvfs
|
||||||
import os
|
import os
|
||||||
import threading
|
import threading
|
||||||
import json
|
import json
|
||||||
|
@ -12,24 +13,80 @@ cwd = addonSettings.getAddonInfo('path')
|
||||||
BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) )
|
BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) )
|
||||||
sys.path.append(BASE_RESOURCE_PATH)
|
sys.path.append(BASE_RESOURCE_PATH)
|
||||||
|
|
||||||
WINDOW = xbmcgui.Window( 10000 )
|
|
||||||
|
WINDOW = xbmcgui.Window(10000)
|
||||||
|
|
||||||
import Utils as utils
|
import Utils as utils
|
||||||
from PlaybackUtils import PlaybackUtils
|
from PlaybackUtils import PlaybackUtils
|
||||||
|
from DownloadUtils import DownloadUtils
|
||||||
|
from ReadEmbyDB import ReadEmbyDB
|
||||||
|
from API import API
|
||||||
|
|
||||||
try:
|
try:
|
||||||
params=utils.get_params(sys.argv[2])
|
params = utils.get_params(sys.argv[2])
|
||||||
mode = params.get('mode',"")
|
mode = params['mode']
|
||||||
id = params.get('id',"")
|
id = params['id']
|
||||||
except:
|
except:
|
||||||
params={}
|
params = {}
|
||||||
mode=None
|
mode = None
|
||||||
id=None
|
|
||||||
|
if mode == "play":
|
||||||
|
# Play items via plugin://plugin.video.emby/
|
||||||
|
url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id
|
||||||
|
result = DownloadUtils().downloadUrl(url)
|
||||||
|
item = PlaybackUtils().PLAY(result, setup="default")
|
||||||
|
|
||||||
|
|
||||||
|
#get extrafanart for listitem - this will only be used for skins that actually call the listitem's path + fanart dir...
|
||||||
|
elif "extrafanart" in sys.argv[0]:
|
||||||
|
itemPath = ""
|
||||||
|
embyId = ""
|
||||||
|
|
||||||
|
try:
|
||||||
|
#only do this if the listitem has actually changed
|
||||||
|
itemPath = xbmc.getInfoLabel("ListItem.FileNameAndPath")
|
||||||
|
|
||||||
|
if not itemPath:
|
||||||
|
itemPath = xbmc.getInfoLabel("ListItem.Path")
|
||||||
|
|
||||||
|
if ("/tvshows/" in itemPath or "/musicvideos/" in itemPath or "/movies/" in itemPath):
|
||||||
|
embyId = itemPath.split("/")[-2]
|
||||||
|
|
||||||
|
#we need to store the images locally for this to work because of the caching system in xbmc
|
||||||
|
fanartDir = xbmc.translatePath("special://thumbnails/emby/" + embyId + "/")
|
||||||
|
|
||||||
|
if not xbmcvfs.exists(fanartDir):
|
||||||
|
#download the images to the cache directory
|
||||||
|
xbmcvfs.mkdir(fanartDir)
|
||||||
|
item = ReadEmbyDB().getFullItem(embyId)
|
||||||
|
if item != None:
|
||||||
|
if item.has_key("BackdropImageTags"):
|
||||||
|
if(len(item["BackdropImageTags"]) > 1):
|
||||||
|
totalbackdrops = len(item["BackdropImageTags"])
|
||||||
|
for index in range(1,totalbackdrops):
|
||||||
|
backgroundUrl = API().getArtwork(item, "Backdrop",str(index))
|
||||||
|
fanartFile = os.path.join(fanartDir,"fanart" + str(index) + ".jpg")
|
||||||
|
li = xbmcgui.ListItem(str(index), path=fanartFile)
|
||||||
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=fanartFile, listitem=li)
|
||||||
|
xbmcvfs.copy(backgroundUrl,fanartFile)
|
||||||
|
|
||||||
|
else:
|
||||||
|
#use existing cached images
|
||||||
|
dirs, files = xbmcvfs.listdir(fanartDir)
|
||||||
|
count = 1
|
||||||
|
for file in files:
|
||||||
|
count +=1
|
||||||
|
li = xbmcgui.ListItem(file, path=os.path.join(fanartDir,file))
|
||||||
|
xbmcplugin.addDirectoryItem(handle=int(sys.argv[1]), url=os.path.join(fanartDir,file), listitem=li)
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
#always do endofdirectory to prevent errors in the logs
|
||||||
|
xbmcplugin.endOfDirectory(int(sys.argv[1]))
|
||||||
|
|
||||||
|
|
||||||
if mode != None and mode == "play":
|
|
||||||
PlaybackUtils().PLAY(id)
|
|
||||||
elif sys.argv[1] == "reset":
|
elif sys.argv[1] == "reset":
|
||||||
utils.reset()
|
utils.reset()
|
||||||
else:
|
else:
|
||||||
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
|
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
|
||||||
|
|
||||||
|
|
|
@ -84,6 +84,7 @@ class API():
|
||||||
width = ''
|
width = ''
|
||||||
aspectratio = '1:1'
|
aspectratio = '1:1'
|
||||||
aspectfloat = 1.85
|
aspectfloat = 1.85
|
||||||
|
Video3DFormat = ''
|
||||||
|
|
||||||
if mediaSources == True:
|
if mediaSources == True:
|
||||||
mediaSources = item.get("MediaSources")
|
mediaSources = item.get("MediaSources")
|
||||||
|
@ -99,9 +100,10 @@ class API():
|
||||||
for mediaStream in MediaStreams:
|
for mediaStream in MediaStreams:
|
||||||
if(mediaStream.get("Type") == "Video"):
|
if(mediaStream.get("Type") == "Video"):
|
||||||
videocodec = mediaStream.get("Codec")
|
videocodec = mediaStream.get("Codec")
|
||||||
height = str(mediaStream.get("Height"))
|
height = int(mediaStream.get("Height"))
|
||||||
width = str(mediaStream.get("Width"))
|
width = int(mediaStream.get("Width"))
|
||||||
aspectratio = mediaStream.get("AspectRatio")
|
aspectratio = mediaStream.get("AspectRatio")
|
||||||
|
Video3DFormat = item.get("Video3DFormat")
|
||||||
if aspectratio != None and len(aspectratio) >= 3:
|
if aspectratio != None and len(aspectratio) >= 3:
|
||||||
try:
|
try:
|
||||||
aspectwidth,aspectheight = aspectratio.split(':')
|
aspectwidth,aspectheight = aspectratio.split(':')
|
||||||
|
@ -116,9 +118,30 @@ class API():
|
||||||
'audiocodec' : audiocodec,
|
'audiocodec' : audiocodec,
|
||||||
'height' : height,
|
'height' : height,
|
||||||
'width' : width,
|
'width' : width,
|
||||||
'aspectratio' : str(aspectfloat)
|
'aspectratio' : aspectfloat,
|
||||||
|
'3dformat' : Video3DFormat
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def getChecksum(self, item):
|
||||||
|
# use the etags checksum for this if available
|
||||||
|
# AND the userdata
|
||||||
|
checksum = ""
|
||||||
|
|
||||||
|
if item.get("Etag") != None:
|
||||||
|
checksum = item.get("Etag")
|
||||||
|
userData = item.get("UserData")
|
||||||
|
if(userData != None):
|
||||||
|
checksum += str(userData.get("Played"))
|
||||||
|
checksum += str(userData.get("IsFavorite"))
|
||||||
|
if userData.get('UnplayedItemCount') != None:
|
||||||
|
checksum += str(userData.get("UnplayedItemCount"))
|
||||||
|
if userData.get('LastPlayedDate') != None:
|
||||||
|
checksum += str(userData.get("LastPlayedDate"))
|
||||||
|
if userData.get('PlaybackPositionTicks') != None:
|
||||||
|
checksum += str(userData.get("PlaybackPositionTicks"))
|
||||||
|
|
||||||
|
return checksum
|
||||||
|
|
||||||
def getUserData(self, item):
|
def getUserData(self, item):
|
||||||
userData = item.get("UserData")
|
userData = item.get("UserData")
|
||||||
resumeTime = 0
|
resumeTime = 0
|
||||||
|
@ -128,9 +151,9 @@ class API():
|
||||||
else:
|
else:
|
||||||
watched="False"
|
watched="False"
|
||||||
if userData.get("IsFavorite") == True:
|
if userData.get("IsFavorite") == True:
|
||||||
favorite="True"
|
favorite=True
|
||||||
else:
|
else:
|
||||||
favorite="False"
|
favorite=False
|
||||||
if(userData.get("Played") == True):
|
if(userData.get("Played") == True):
|
||||||
playcount="1"
|
playcount="1"
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -116,12 +116,12 @@ class ConnectionManager():
|
||||||
return
|
return
|
||||||
|
|
||||||
# Option to play from http
|
# Option to play from http
|
||||||
setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?")
|
#setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?")
|
||||||
if setPlayback == 1:
|
#if setPlayback == 1:
|
||||||
self.logMsg("Playback will be set using HTTP.", 1)
|
#self.logMsg("Playback will be set using HTTP.", 1)
|
||||||
addon.setSetting("playFromStream", "true")
|
#addon.setSetting("playFromStream", "true")
|
||||||
else:
|
#else:
|
||||||
self.logMsg("Playback will be set using SMB.", 1)
|
#self.logMsg("Playback will be set using SMB.", 1)
|
||||||
|
|
||||||
def getServerDetails(self):
|
def getServerDetails(self):
|
||||||
|
|
||||||
|
|
|
@ -11,8 +11,8 @@ from ClientInformation import ClientInformation
|
||||||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||||
|
|
||||||
# Disable requests logging
|
# Disable requests logging
|
||||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||||
logging.getLogger("requests").setLevel(logging.WARNING)
|
# logging.getLogger("requests").setLevel(logging.WARNING)
|
||||||
|
|
||||||
class DownloadUtils():
|
class DownloadUtils():
|
||||||
|
|
||||||
|
@ -67,26 +67,22 @@ class DownloadUtils():
|
||||||
|
|
||||||
def postCapabilities(self, deviceId):
|
def postCapabilities(self, deviceId):
|
||||||
|
|
||||||
# Get sessionId
|
# Post settings to session
|
||||||
url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId
|
url = "{server}/mediabrowser/Sessions/Capabilities/Full"
|
||||||
result = self.downloadUrl(url)
|
data = {
|
||||||
# sessionId result
|
'PlayableMediaTypes': "Audio,Video",
|
||||||
self.logMsg("Session result: %s" % result, 2)
|
'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext",
|
||||||
self.sessionId = result[0][u'Id']
|
'SupportsMediaControl': True
|
||||||
self.WINDOW.setProperty('sessionId%s' % self.username, self.sessionId)
|
}
|
||||||
|
|
||||||
# Settings for capabilities
|
|
||||||
playableMediaTypes = "Audio,Video"
|
|
||||||
supportedCommands = "Play,Playstate,SendString,DisplayMessage,PlayNext"
|
|
||||||
|
|
||||||
# Post settings to sessionId
|
|
||||||
url = "{server}/mediabrowser/Sessions/Capabilities?Id=%s&PlayableMediaTypes=%s&SupportedCommands=%s&SupportsMediaControl=True" % (self.sessionId, playableMediaTypes, supportedCommands)
|
|
||||||
data = {}
|
|
||||||
self.logMsg("Capabilities URL: %s" % url, 2)
|
self.logMsg("Capabilities URL: %s" % url, 2)
|
||||||
self.logMsg("PostData: %s" % data, 2)
|
self.logMsg("PostData: %s" % data, 2)
|
||||||
|
|
||||||
self.downloadUrl(url, postBody=data, type="POST")
|
try:
|
||||||
self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1)
|
self.downloadUrl(url, postBody=data, type="POST")
|
||||||
|
self.logMsg("Posted capabilities to %s" % self.server, 1)
|
||||||
|
except:
|
||||||
|
self.logMsg("Posted capabilities failed.")
|
||||||
|
|
||||||
def startSession(self):
|
def startSession(self):
|
||||||
|
|
||||||
|
@ -99,9 +95,11 @@ class DownloadUtils():
|
||||||
header = self.getHeader()
|
header = self.getHeader()
|
||||||
|
|
||||||
# If user enabled host certificate verification
|
# If user enabled host certificate verification
|
||||||
if self.sslverify:
|
try:
|
||||||
verify = True
|
verify = self.sslverify
|
||||||
cert = self.sslclient
|
cert = self.sslclient
|
||||||
|
except:
|
||||||
|
self.logMsg("Could not load SSL settings.", 1)
|
||||||
|
|
||||||
# Start session
|
# Start session
|
||||||
self.s = requests.Session()
|
self.s = requests.Session()
|
||||||
|
@ -153,52 +151,86 @@ class DownloadUtils():
|
||||||
timeout = self.timeout
|
timeout = self.timeout
|
||||||
default_link = ""
|
default_link = ""
|
||||||
|
|
||||||
# If user is authenticated
|
|
||||||
if (authenticate):
|
|
||||||
# Get requests session
|
|
||||||
s = self.s
|
|
||||||
# Replace for the real values and append api_key
|
|
||||||
url = url.replace("{server}", self.server, 1)
|
|
||||||
url = url.replace("{UserId}", self.userId, 1)
|
|
||||||
#url = "%s&api_key=%s" % (url, self.token)
|
|
||||||
|
|
||||||
self.logMsg("URL: %s" % url, 2)
|
|
||||||
# Prepare request
|
|
||||||
if type == "GET":
|
|
||||||
r = s.get(url, json=postBody, 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 user is not authenticated
|
|
||||||
elif not authenticate:
|
|
||||||
|
|
||||||
self.logMsg("URL: %s" % url, 1)
|
|
||||||
header = self.getHeader(authenticate=False)
|
|
||||||
verifyssl = False
|
|
||||||
|
|
||||||
# If user enables ssl verification
|
|
||||||
try:
|
|
||||||
verifyssl = self.sslverify
|
|
||||||
except AttributeError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Prepare request
|
|
||||||
if type == "GET":
|
|
||||||
r = requests.get(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
|
|
||||||
elif type == "POST":
|
|
||||||
r = requests.post(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
|
|
||||||
|
|
||||||
# Process the response
|
|
||||||
try:
|
try:
|
||||||
r.raise_for_status()
|
|
||||||
|
|
||||||
|
# If user is authenticated
|
||||||
|
if (authenticate):
|
||||||
|
# Get requests session
|
||||||
|
try:
|
||||||
|
s = self.s
|
||||||
|
# Replace for the real values and append api_key
|
||||||
|
url = url.replace("{server}", self.server, 1)
|
||||||
|
url = url.replace("{UserId}", self.userId, 1)
|
||||||
|
#url = "%s&api_key=%s" % (url, self.token)
|
||||||
|
|
||||||
|
self.logMsg("URL: %s" % url, 2)
|
||||||
|
# Prepare request
|
||||||
|
if type == "GET":
|
||||||
|
r = s.get(url, json=postBody, timeout=timeout)
|
||||||
|
elif type == "POST":
|
||||||
|
r = s.post(url, json=postBody, timeout=timeout)
|
||||||
|
elif type == "DELETE":
|
||||||
|
r = s.delete(url, json=postBody, timeout=timeout)
|
||||||
|
|
||||||
|
except AttributeError:
|
||||||
|
|
||||||
|
# Get user information
|
||||||
|
self.username = WINDOW.getProperty('currUser')
|
||||||
|
self.userId = WINDOW.getProperty('userId%s' % self.username)
|
||||||
|
self.server = WINDOW.getProperty('server%s' % self.username)
|
||||||
|
self.token = WINDOW.getProperty('accessToken%s' % self.username)
|
||||||
|
header = self.getHeader()
|
||||||
|
verifyssl = False
|
||||||
|
cert = None
|
||||||
|
|
||||||
|
# IF user enables ssl verification
|
||||||
|
try:
|
||||||
|
if self.addon.getSetting('sslverify') == "true":
|
||||||
|
verifyssl = True
|
||||||
|
if self.addon.getSetting('sslcert') != "None":
|
||||||
|
cert = self.addon.getSetting('sslcert')
|
||||||
|
except:
|
||||||
|
self.logMsg("Could not load SSL settings.", 1)
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Replace for the real values and append api_key
|
||||||
|
url = url.replace("{server}", self.server, 1)
|
||||||
|
url = url.replace("{UserId}", self.userId, 1)
|
||||||
|
|
||||||
|
self.logMsg("URL: %s" % url, 2)
|
||||||
|
# Prepare request
|
||||||
|
if type == "GET":
|
||||||
|
r = requests.get(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
|
||||||
|
elif type == "POST":
|
||||||
|
r = requests.post(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
|
||||||
|
elif type == "DELETE":
|
||||||
|
r = requests.delete(url, json=postBody, headers=header, timeout=timeout, cert=cert, verify=verifyssl)
|
||||||
|
|
||||||
|
# If user is not authenticated
|
||||||
|
elif not authenticate:
|
||||||
|
|
||||||
|
self.logMsg("URL: %s" % url, 2)
|
||||||
|
header = self.getHeader(authenticate=False)
|
||||||
|
verifyssl = False
|
||||||
|
|
||||||
|
# If user enables ssl verification
|
||||||
|
try:
|
||||||
|
verifyssl = self.sslverify
|
||||||
|
except AttributeError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# Prepare request
|
||||||
|
if type == "GET":
|
||||||
|
r = requests.get(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
|
||||||
|
elif type == "POST":
|
||||||
|
r = requests.post(url, json=postBody, headers=header, timeout=timeout, verify=verifyssl)
|
||||||
|
|
||||||
|
# Process the response
|
||||||
if r.status_code == 204:
|
if r.status_code == 204:
|
||||||
# No response in body
|
# No body in the response
|
||||||
self.logMsg("====== 204 Success ======", 2)
|
self.logMsg("====== 204 Success ======", 2)
|
||||||
return default_link
|
return default_link
|
||||||
# Response code 200
|
|
||||||
elif r.status_code == requests.codes.ok:
|
elif r.status_code == requests.codes.ok:
|
||||||
try:
|
try:
|
||||||
# UTF-8 - JSON object
|
# UTF-8 - JSON object
|
||||||
|
@ -207,13 +239,19 @@ class DownloadUtils():
|
||||||
return r
|
return r
|
||||||
except:
|
except:
|
||||||
self.logMsg("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()
|
||||||
|
|
||||||
return default_link
|
return default_link
|
||||||
|
|
||||||
# TO REVIEW EXCEPTIONS
|
# TO REVIEW EXCEPTIONS
|
||||||
except requests.exceptions.ConnectionError as e:
|
except requests.exceptions.ConnectionError as e:
|
||||||
self.logMsg("Server unreachable at: %s" % url, 0)
|
# Make the addon aware of status
|
||||||
self.logMsg(e, 1)
|
if WINDOW.getProperty("Server_online") != "false":
|
||||||
|
self.logMsg("Server unreachable at: %s" % url, 0)
|
||||||
|
self.logMsg(e, 2)
|
||||||
|
WINDOW.setProperty("Server_online", "false")
|
||||||
|
pass
|
||||||
|
|
||||||
except requests.exceptions.ConnectTimeout as e:
|
except requests.exceptions.ConnectTimeout as e:
|
||||||
self.logMsg("Server timeout at: %s" % url, 0)
|
self.logMsg("Server timeout at: %s" % url, 0)
|
||||||
|
@ -230,6 +268,7 @@ class DownloadUtils():
|
||||||
# Tell UserClient token has been revoked.
|
# Tell UserClient token has been revoked.
|
||||||
WINDOW.setProperty("Server_status", "401")
|
WINDOW.setProperty("Server_status", "401")
|
||||||
self.logMsg("HTTP Error: %s" % e, 0)
|
self.logMsg("HTTP Error: %s" % e, 0)
|
||||||
|
xbmcgui.Dialog().notification("Error connecting", "Unauthorized.", xbmcgui.NOTIFICATION_ERROR)
|
||||||
|
|
||||||
elif (r.status_code == 301) or (r.status_code == 302):
|
elif (r.status_code == 301) or (r.status_code == 302):
|
||||||
# Redirects
|
# Redirects
|
||||||
|
|
|
@ -11,8 +11,10 @@ import json
|
||||||
import Utils as utils
|
import Utils as utils
|
||||||
from WriteKodiDB import WriteKodiDB
|
from WriteKodiDB import WriteKodiDB
|
||||||
from ReadKodiDB import ReadKodiDB
|
from ReadKodiDB import ReadKodiDB
|
||||||
|
from LibrarySync import LibrarySync
|
||||||
from PlayUtils import PlayUtils
|
from PlayUtils import PlayUtils
|
||||||
from DownloadUtils import DownloadUtils
|
from DownloadUtils import DownloadUtils
|
||||||
|
from PlaybackUtils import PlaybackUtils
|
||||||
|
|
||||||
class Kodi_Monitor(xbmc.Monitor):
|
class Kodi_Monitor(xbmc.Monitor):
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
|
@ -26,65 +28,7 @@ class Kodi_Monitor(xbmc.Monitor):
|
||||||
def onNotification (self,sender,method,data):
|
def onNotification (self,sender,method,data):
|
||||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||||
downloadUtils = DownloadUtils()
|
downloadUtils = DownloadUtils()
|
||||||
print "onNotification:" + method + ":" + sender + ":" + str(data)
|
|
||||||
#player started playing an item -
|
|
||||||
if method == "Player.OnPlay":
|
|
||||||
print "playlist onadd is called"
|
|
||||||
jsondata = json.loads(data)
|
|
||||||
if jsondata != None:
|
|
||||||
if jsondata.has_key("item"):
|
|
||||||
if jsondata.get("item").has_key("id") and jsondata.get("item").has_key("type"):
|
|
||||||
id = jsondata.get("item").get("id")
|
|
||||||
type = jsondata.get("item").get("type")
|
|
||||||
embyid = ReadKodiDB().getEmbyIdByKodiId(id,type)
|
|
||||||
|
|
||||||
if embyid != None:
|
|
||||||
|
|
||||||
WINDOW = xbmcgui.Window( 10000 )
|
|
||||||
|
|
||||||
username = WINDOW.getProperty('currUser')
|
|
||||||
userid = WINDOW.getProperty('userId%s' % username)
|
|
||||||
server = WINDOW.getProperty('server%s' % username)
|
|
||||||
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % embyid
|
|
||||||
result = downloadUtils.downloadUrl(url)
|
|
||||||
|
|
||||||
userData = result[u'UserData']
|
|
||||||
|
|
||||||
playurl = PlayUtils().getPlayUrl(server, embyid, result)
|
|
||||||
|
|
||||||
watchedurl = "%s/mediabrowser/Users/%s/PlayedItems/%s" % (server, userid, embyid)
|
|
||||||
positionurl = "%s/mediabrowser/Users/%s/PlayingItems/%s" % (server, userid, embyid)
|
|
||||||
deleteurl = "%s/mediabrowser/Items/%s" % (server, embyid)
|
|
||||||
|
|
||||||
# set the current playing info
|
|
||||||
WINDOW.setProperty(playurl+"watchedurl", watchedurl)
|
|
||||||
WINDOW.setProperty(playurl+"positionurl", positionurl)
|
|
||||||
WINDOW.setProperty(playurl+"deleteurl", "")
|
|
||||||
WINDOW.setProperty(playurl+"deleteurl", deleteurl)
|
|
||||||
if result[u'Type']=="Episode":
|
|
||||||
WINDOW.setProperty(playurl+"refresh_id", result[u'SeriesId'])
|
|
||||||
else:
|
|
||||||
WINDOW.setProperty(playurl+"refresh_id", embyid)
|
|
||||||
|
|
||||||
WINDOW.setProperty(playurl+"runtimeticks", str(result[u'RunTimeTicks']))
|
|
||||||
WINDOW.setProperty(playurl+"type", result[u'Type'])
|
|
||||||
WINDOW.setProperty(playurl+"item_id", embyid)
|
|
||||||
|
|
||||||
if PlayUtils().isDirectPlay(result) == True:
|
|
||||||
playMethod = "DirectPlay"
|
|
||||||
else:
|
|
||||||
playMethod = "Transcode"
|
|
||||||
|
|
||||||
WINDOW.setProperty(playurl+"playmethod", playMethod)
|
|
||||||
|
|
||||||
mediaSources = result[u'MediaSources']
|
|
||||||
if(mediaSources != None):
|
|
||||||
if mediaSources[0].get('DefaultAudioStreamIndex') != None:
|
|
||||||
WINDOW.setProperty(playurl+"AudioStreamIndex", str(mediaSources[0][u'DefaultAudioStreamIndex']))
|
|
||||||
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
|
||||||
WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0][u'DefaultSubtitleStreamIndex']))
|
|
||||||
|
|
||||||
if method == "VideoLibrary.OnUpdate":
|
if method == "VideoLibrary.OnUpdate":
|
||||||
jsondata = json.loads(data)
|
jsondata = json.loads(data)
|
||||||
if jsondata != None:
|
if jsondata != None:
|
||||||
|
@ -97,6 +41,12 @@ class Kodi_Monitor(xbmc.Monitor):
|
||||||
utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2)
|
utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2)
|
||||||
WriteKodiDB().updatePlayCountFromKodi(item, type, playcount)
|
WriteKodiDB().updatePlayCountFromKodi(item, type, playcount)
|
||||||
|
|
||||||
|
if method == "System.OnWake":
|
||||||
|
xbmc.sleep(10000) #Allow network to wake up
|
||||||
|
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",1)
|
||||||
|
libSync = LibrarySync().FullLibrarySync()
|
||||||
|
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),1)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -35,7 +35,7 @@ class PlaybackUtils():
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def PLAY(self, id):
|
def PLAY(self, result, setup="service"):
|
||||||
xbmc.log("PLAY Called")
|
xbmc.log("PLAY Called")
|
||||||
WINDOW = xbmcgui.Window(10000)
|
WINDOW = xbmcgui.Window(10000)
|
||||||
|
|
||||||
|
@ -43,43 +43,22 @@ class PlaybackUtils():
|
||||||
userid = WINDOW.getProperty('userId%s' % username)
|
userid = WINDOW.getProperty('userId%s' % username)
|
||||||
server = WINDOW.getProperty('server%s' % username)
|
server = WINDOW.getProperty('server%s' % username)
|
||||||
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id
|
try:
|
||||||
result = self.downloadUtils.downloadUrl(url)
|
id = result["Id"]
|
||||||
|
except:
|
||||||
|
return
|
||||||
|
|
||||||
userData = result[u'UserData']
|
userData = result['UserData']
|
||||||
resume_result = 0
|
resume_result = 0
|
||||||
seekTime = 0
|
seekTime = 0
|
||||||
|
|
||||||
#get the resume point from Kodi DB for a Movie
|
if userData.get("PlaybackPositionTicks") != 0:
|
||||||
kodiItem = ReadKodiDB().getKodiMovie(id)
|
reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
|
||||||
if kodiItem != None:
|
seekTime = reasonableTicks / 10000
|
||||||
seekTime = int(round(kodiItem['resume'].get("position")))
|
|
||||||
else:
|
|
||||||
#get the resume point from Kodi DB for an episode
|
|
||||||
episodeItem = ReadEmbyDB().getItem(id)
|
|
||||||
if episodeItem != None and str(episodeItem["Type"]) == "Episode":
|
|
||||||
kodiItem = ReadKodiDB().getKodiEpisodeByMbItem(id,episodeItem["SeriesId"])
|
|
||||||
if kodiItem != None:
|
|
||||||
seekTime = int(round(kodiItem['resume'].get("position")))
|
|
||||||
|
|
||||||
playurl = PlayUtils().getPlayUrl(server, id, result)
|
playurl = PlayUtils().getPlayUrl(server, id, result)
|
||||||
|
|
||||||
isStrmFile = False
|
|
||||||
thumbPath = API().getArtwork(result, "Primary")
|
thumbPath = API().getArtwork(result, "Primary")
|
||||||
|
|
||||||
#workaround for when the file to play is a strm file itself
|
|
||||||
if playurl.endswith(".strm"):
|
|
||||||
isStrmFile = True
|
|
||||||
tempPath = os.path.join(addondir,"library","temp.strm")
|
|
||||||
xbmcvfs.copy(playurl, tempPath)
|
|
||||||
sfile = open(tempPath, 'r')
|
|
||||||
playurl = sfile.readline()
|
|
||||||
sfile.close()
|
|
||||||
xbmcvfs.delete(tempPath)
|
|
||||||
WINDOW.setProperty("virtualstrm", id)
|
|
||||||
WINDOW.setProperty("virtualstrmtype", result.get("Type"))
|
|
||||||
|
|
||||||
listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath)
|
listItem = xbmcgui.ListItem(path=playurl, iconImage=thumbPath, thumbnailImage=thumbPath)
|
||||||
self.setListItemProps(server, id, listItem, result)
|
self.setListItemProps(server, id, listItem, result)
|
||||||
|
|
||||||
|
@ -97,17 +76,19 @@ class PlaybackUtils():
|
||||||
WINDOW.setProperty(playurl+"deleteurl", "")
|
WINDOW.setProperty(playurl+"deleteurl", "")
|
||||||
WINDOW.setProperty(playurl+"deleteurl", deleteurl)
|
WINDOW.setProperty(playurl+"deleteurl", deleteurl)
|
||||||
|
|
||||||
if seekTime != 0:
|
#show the additional resume dialog if launched from a widget
|
||||||
displayTime = str(datetime.timedelta(seconds=seekTime))
|
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||||
display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)]
|
if seekTime != 0:
|
||||||
resumeScreen = xbmcgui.Dialog()
|
displayTime = str(datetime.timedelta(seconds=seekTime))
|
||||||
resume_result = resumeScreen.select(self.language(30105), display_list)
|
display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)]
|
||||||
if resume_result == 0:
|
resumeScreen = xbmcgui.Dialog()
|
||||||
WINDOW.setProperty(playurl+"seektime", str(seekTime))
|
resume_result = resumeScreen.select(self.language(30105), display_list)
|
||||||
|
if resume_result == 0:
|
||||||
|
WINDOW.setProperty(playurl+"seektime", str(seekTime))
|
||||||
|
else:
|
||||||
|
WINDOW.clearProperty(playurl+"seektime")
|
||||||
else:
|
else:
|
||||||
WINDOW.clearProperty(playurl+"seektime")
|
WINDOW.clearProperty(playurl+"seektime")
|
||||||
else:
|
|
||||||
WINDOW.clearProperty(playurl+"seektime")
|
|
||||||
|
|
||||||
if result.get("Type")=="Episode":
|
if result.get("Type")=="Episode":
|
||||||
WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId"))
|
WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId"))
|
||||||
|
@ -132,15 +113,15 @@ class PlaybackUtils():
|
||||||
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
||||||
WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex')))
|
WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex')))
|
||||||
|
|
||||||
#this launches the playback
|
#launch the playback
|
||||||
#artwork only works with both resolvedurl and player command
|
if setup == "service":
|
||||||
if isStrmFile:
|
xbmc.Player().play(playurl,listItem)
|
||||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
elif setup == "default":
|
||||||
else:
|
#artwork only works from widgets (home screen) with player command as there is no listitem selected
|
||||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||||
if(addon.getSetting("addExtraPlaybackArt") == "true"):
|
|
||||||
utils.logMsg("PLAY", "Doing second xbmc.Player().play to add extra art")
|
|
||||||
xbmc.Player().play(playurl,listItem)
|
xbmc.Player().play(playurl,listItem)
|
||||||
|
else:
|
||||||
|
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
||||||
|
|
||||||
def setArt(self, list,name,path):
|
def setArt(self, list,name,path):
|
||||||
if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators':
|
if name=='thumb' or name=='fanart_image' or name=='small_poster' or name=='tiny_poster' or name == "medium_landscape" or name=='medium_poster' or name=='small_fanartimage' or name=='medium_fanartimage' or name=='fanart_noindicators':
|
||||||
|
|
|
@ -90,9 +90,9 @@ class Player( xbmc.Player ):
|
||||||
self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt))
|
self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt))
|
||||||
self.stopPlayback(data)
|
self.stopPlayback(data)
|
||||||
|
|
||||||
if(refresh_id != None):
|
#if(refresh_id != None):
|
||||||
#report updates playcount and resume status to Kodi and MB3
|
#report updates playcount and resume status to Kodi and MB3
|
||||||
librarySync.updatePlayCount(item_id)
|
#librarySync.updatePlayCount(item_id)
|
||||||
|
|
||||||
|
|
||||||
self.played_information.clear()
|
self.played_information.clear()
|
||||||
|
@ -138,6 +138,10 @@ class Player( xbmc.Player ):
|
||||||
|
|
||||||
self.logMsg("reportPlayback Called", 2)
|
self.logMsg("reportPlayback Called", 2)
|
||||||
xbmcplayer = self.xbmcplayer
|
xbmcplayer = self.xbmcplayer
|
||||||
|
|
||||||
|
if not xbmcplayer.isPlaying():
|
||||||
|
self.logMsg("reportPlayback: Not playing anything so returning", 0)
|
||||||
|
return
|
||||||
|
|
||||||
currentFile = xbmcplayer.getPlayingFile()
|
currentFile = xbmcplayer.getPlayingFile()
|
||||||
data = self.played_information.get(currentFile)
|
data = self.played_information.get(currentFile)
|
||||||
|
@ -176,7 +180,7 @@ class Player( xbmc.Player ):
|
||||||
postdata['SubtitleStreamIndex'] = subtitleindex
|
postdata['SubtitleStreamIndex'] = subtitleindex
|
||||||
|
|
||||||
postdata = json.dumps(postdata)
|
postdata = json.dumps(postdata)
|
||||||
self.logMsg("Report: %s" % postdata)
|
self.logMsg("Report: %s" % postdata, 2)
|
||||||
self.ws.sendProgressUpdate(postdata)
|
self.ws.sendProgressUpdate(postdata)
|
||||||
|
|
||||||
def onPlayBackPaused( self ):
|
def onPlayBackPaused( self ):
|
||||||
|
@ -204,7 +208,11 @@ class Player( xbmc.Player ):
|
||||||
self.stopAll()
|
self.stopAll()
|
||||||
|
|
||||||
if xbmcplayer.isPlaying():
|
if xbmcplayer.isPlaying():
|
||||||
currentFile = xbmcplayer.getPlayingFile()
|
|
||||||
|
currentFile = ""
|
||||||
|
try:
|
||||||
|
currentFile = xbmcplayer.getPlayingFile()
|
||||||
|
except: pass
|
||||||
self.logMsg("onPlayBackStarted: %s" % currentFile, 0)
|
self.logMsg("onPlayBackStarted: %s" % currentFile, 0)
|
||||||
|
|
||||||
# we may need to wait until the info is available
|
# we may need to wait until the info is available
|
||||||
|
@ -321,14 +329,11 @@ class Player( xbmc.Player ):
|
||||||
def autoPlayPlayback(self):
|
def autoPlayPlayback(self):
|
||||||
currentFile = xbmc.Player().getPlayingFile()
|
currentFile = xbmc.Player().getPlayingFile()
|
||||||
data = self.played_information.get(currentFile)
|
data = self.played_information.get(currentFile)
|
||||||
|
|
||||||
# only report playback if emby has initiated the playback (item_id has value)
|
# only report playback if emby has initiated the playback (item_id has value)
|
||||||
if(data != None and data.get("item_id") != None):
|
if(data != None and data.get("item_id") != None):
|
||||||
addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
|
addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
|
||||||
|
|
||||||
item_id = data.get("item_id")
|
item_id = data.get("item_id")
|
||||||
type = data.get("Type")
|
type = data.get("Type")
|
||||||
|
|
||||||
# if its an episode see if autoplay is enabled
|
# if its an episode see if autoplay is enabled
|
||||||
if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode":
|
if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode":
|
||||||
WINDOW = xbmcgui.Window( 10000 )
|
WINDOW = xbmcgui.Window( 10000 )
|
||||||
|
@ -343,8 +348,10 @@ class Player( xbmc.Player ):
|
||||||
seasonId = MB3Episode["SeasonId"]
|
seasonId = MB3Episode["SeasonId"]
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json" % seasonId
|
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&ImageTypeLimit=1&Limit=1&SortBy=SortName&SortOrder=Ascending&Filters=IsUnPlayed&IncludeItemTypes=Episode&IsVirtualUnaired=false&Recursive=true&IsMissing=False&format=json" % seasonId
|
||||||
jsonData = self.doUtils.downloadUrl(url)
|
jsonData = self.doUtils.downloadUrl(url)
|
||||||
|
|
||||||
if(jsonData != ""):
|
if(jsonData != ""):
|
||||||
seasonData = json.loads(jsonData)
|
seasonData = jsonData
|
||||||
|
|
||||||
if seasonData.get("Items") != None:
|
if seasonData.get("Items") != None:
|
||||||
item = seasonData.get("Items")[0]
|
item = seasonData.get("Items")[0]
|
||||||
pDialog.create("Auto Play next episode", str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play")
|
pDialog.create("Auto Play next episode", str(item.get("ParentIndexNumber")) + "x" + str(item.get("IndexNumber")) + ". " + item["Name"] + " found","Cancel to stop automatic play")
|
||||||
|
@ -365,5 +372,5 @@ class Player( xbmc.Player ):
|
||||||
xbmc.sleep(500)
|
xbmc.sleep(500)
|
||||||
playTime = xbmc.Player().getTime()
|
playTime = xbmc.Player().getTime()
|
||||||
totalTime = xbmc.Player().getTotalTime()
|
totalTime = xbmc.Player().getTotalTime()
|
||||||
|
|
||||||
PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items"))
|
PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items"))
|
|
@ -6,30 +6,22 @@ import xbmc
|
||||||
import xbmcgui
|
import xbmcgui
|
||||||
import xbmcaddon
|
import xbmcaddon
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
from DownloadUtils import DownloadUtils
|
from DownloadUtils import DownloadUtils
|
||||||
|
|
||||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||||
|
|
||||||
class ReadEmbyDB():
|
class ReadEmbyDB():
|
||||||
|
|
||||||
def getMovies(self, id, fullinfo = False, fullSync = True, itemList = []):
|
def getMovies(self, id, itemList = []):
|
||||||
|
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
if fullSync:
|
#only get basic info for our sync-compares
|
||||||
sortstring = "&SortBy=SortName"
|
sortstring = "&SortBy=SortName"
|
||||||
else:
|
url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring)
|
||||||
if(len(itemList) > 0): # if we want a certain list specify it
|
|
||||||
#sortstring = "&Ids=" + ",".join(itemList)
|
|
||||||
sortstring = "" # work around for now until ParetnId and Id work together
|
|
||||||
else: # just get the last 20 created items
|
|
||||||
sortstring = "&Limit=20&SortBy=DateCreated"
|
|
||||||
|
|
||||||
if fullinfo:
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring)
|
|
||||||
else:
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Movie&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % (id, sortstring)
|
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -37,8 +29,8 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
if (jsonData[u'Items'] != ""):
|
if (jsonData[u'Items'] != ""):
|
||||||
result = jsonData[u'Items']
|
result = jsonData[u'Items']
|
||||||
|
|
||||||
# work around for now until ParetnId and Id work together
|
# Work around to only return items from the given list
|
||||||
if (result != None and len(result) > 0 and len(itemList) > 0):
|
if (result != None and len(result) > 0 and len(itemList) > 0):
|
||||||
newResult = []
|
newResult = []
|
||||||
for item in result:
|
for item in result:
|
||||||
|
@ -48,20 +40,14 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getMusicVideos(self, fullinfo = False, fullSync = True):
|
def getMusicVideos(self, itemList = []):
|
||||||
|
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
if not fullSync:
|
#only get basic info for our sync-compares
|
||||||
sortstring = "&Limit=20&SortBy=DateCreated"
|
sortstring = "&SortBy=SortName"
|
||||||
else:
|
url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring
|
||||||
sortstring = "&SortBy=SortName"
|
|
||||||
|
|
||||||
if fullinfo:
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&format=json&ImageTypeLimit=1" % sortstring
|
|
||||||
else:
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring
|
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -69,6 +55,14 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
if (jsonData[u'Items'] != ""):
|
if (jsonData[u'Items'] != ""):
|
||||||
result = jsonData[u'Items']
|
result = jsonData[u'Items']
|
||||||
|
|
||||||
|
# Work around to only return items from the given list
|
||||||
|
if (result != None and len(result) > 0 and len(itemList) > 0):
|
||||||
|
newResult = []
|
||||||
|
for item in result:
|
||||||
|
if (item[u'Id'] in itemList):
|
||||||
|
newResult.append(item)
|
||||||
|
result = newResult
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -98,20 +92,14 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getTVShows(self, id, fullinfo = False, fullSync = False):
|
def getTvShows(self, id, itemList = []):
|
||||||
|
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
if not fullSync:
|
|
||||||
sortstring = "&Limit=20&SortBy=DateCreated"
|
|
||||||
else:
|
|
||||||
sortstring = "&SortBy=SortName"
|
|
||||||
|
|
||||||
if fullinfo:
|
#only get basic info for our sync-compares
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
sortstring = "&SortBy=SortName"
|
||||||
else:
|
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -119,6 +107,14 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
if (jsonData[u'Items'] != ""):
|
if (jsonData[u'Items'] != ""):
|
||||||
result = jsonData[u'Items']
|
result = jsonData[u'Items']
|
||||||
|
|
||||||
|
# Work around to only return items from the given list
|
||||||
|
if (result != None and len(result) > 0 and len(itemList) > 0):
|
||||||
|
newResult = []
|
||||||
|
for item in result:
|
||||||
|
if (item[u'Id'] in itemList):
|
||||||
|
newResult.append(item)
|
||||||
|
result = newResult
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -138,15 +134,12 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def getEpisodes(self, showId, fullinfo = False):
|
def getEpisodes(self, showId, itemList = []):
|
||||||
|
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
if fullinfo:
|
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId
|
|
||||||
else:
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&IsVirtualUnaired=false&IsMissing=False&SortBy=SortName&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % showId
|
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -154,6 +147,14 @@ class ReadEmbyDB():
|
||||||
|
|
||||||
if (jsonData[u'Items'] != ""):
|
if (jsonData[u'Items'] != ""):
|
||||||
result = jsonData[u'Items']
|
result = jsonData[u'Items']
|
||||||
|
|
||||||
|
# Work around to only return items from the given list
|
||||||
|
if (result != None and len(result) > 0 and len(itemList) > 0):
|
||||||
|
newResult = []
|
||||||
|
for item in result:
|
||||||
|
if (item[u'Id'] in itemList):
|
||||||
|
newResult.append(item)
|
||||||
|
result = newResult
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
@ -167,9 +168,9 @@ class ReadEmbyDB():
|
||||||
limitString = "Ids=" + ",".join(itemList) + "&"
|
limitString = "Ids=" + ",".join(itemList) + "&"
|
||||||
|
|
||||||
if fullinfo:
|
if fullinfo:
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString
|
url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Path,Genres,SortName,Studios,Writer,ProductionYear,Taglines,CommunityRating,OfficialRating,CumulativeRunTimeTicks,Metascore,AirTime,DateCreated,MediaStreams,People,Overview,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString
|
||||||
else:
|
else:
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString
|
url = "{server}/mediabrowser/Users/{UserId}/Items?%sIsVirtualUnaired=false&IsMissing=False&Fields=ParentId,Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Episode&format=json&ImageTypeLimit=1" % limitString
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -225,33 +226,43 @@ class ReadEmbyDB():
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
viewsUrl = "{server}/mediabrowser/Users/{UserId}/Views?format=json&ImageTypeLimit=1"
|
viewsUrl = "{server}/mediabrowser/Users/{UserId}/Views?format=json&ImageTypeLimit=1"
|
||||||
jsonData = doUtils.downloadUrl(viewsUrl)
|
result = doUtils.downloadUrl(viewsUrl)
|
||||||
collections=[]
|
collections=[]
|
||||||
|
|
||||||
if (jsonData != ""):
|
if (result == ""):
|
||||||
views = views[u'Items']
|
return []
|
||||||
|
|
||||||
|
result = result[u'Items']
|
||||||
|
|
||||||
for view in views:
|
for view in result:
|
||||||
if (view[u'Type'] == 'UserView'): # Need to grab the real main node
|
if (view[u'Type'] == 'UserView'): # Need to grab the real main node
|
||||||
newViewsUrl = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s&SortBy=SortName&SortOrder=Ascending&format=json&ImageTypeLimit=1" % view[u'Id']
|
newViewsUrl = "{server}/mediabrowser/Users/{UserId}/items?ParentId=%s&SortBy=SortName&SortOrder=Ascending&format=json&ImageTypeLimit=1" % view[u'Id']
|
||||||
jsonData = doUtils.downloadUrl(newViewsUrl)
|
newViews = doUtils.downloadUrl(newViewsUrl)
|
||||||
if (jsonData != ""):
|
if (result == ""):
|
||||||
newViews = newViews[u'Items']
|
return []
|
||||||
for newView in newViews:
|
newViews = newViews[u'Items']
|
||||||
# There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node.
|
print str(newViews)
|
||||||
if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries":
|
for newView in newViews:
|
||||||
view=newView
|
# There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node.
|
||||||
if (view[u'ChildCount'] != 0):
|
if newView[u'CollectionType'] != None:
|
||||||
Name = view[u'Name']
|
if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries":
|
||||||
|
view=newView
|
||||||
total = str(view[u'ChildCount'])
|
if (view[u'ChildCount'] != 0):
|
||||||
type = view[u'CollectionType']
|
Name = view[u'Name']
|
||||||
if type == None:
|
|
||||||
type = "None" # User may not have declared the type
|
total = str(view[u'ChildCount'])
|
||||||
if type == type:
|
try:
|
||||||
collections.append( {'title' : Name,
|
itemtype = view[u'CollectionType']
|
||||||
'type' : type,
|
except:
|
||||||
'id' : view[u'Id']})
|
itemtype = "movies"
|
||||||
|
if itemtype == "MovieMovies":
|
||||||
|
itemtype = "movies"
|
||||||
|
if itemtype == "TvShowSeries":
|
||||||
|
itemtype = "tvshows"
|
||||||
|
if itemtype == type:
|
||||||
|
collections.append( {'title' : Name,
|
||||||
|
'type' : type,
|
||||||
|
'id' : view[u'Id']})
|
||||||
return collections
|
return collections
|
||||||
|
|
||||||
def getBoxSets(self):
|
def getBoxSets(self):
|
||||||
|
@ -259,7 +270,7 @@ class ReadEmbyDB():
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?SortBy=SortName&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks&Recursive=true&SortOrder=Ascending&IncludeItemTypes=BoxSet&format=json&ImageTypeLimit=1"
|
url = "{server}/mediabrowser/Users/{UserId}/Items?SortBy=SortName&IsVirtualUnaired=false&IsMissing=False&Fields=Name,SortName,CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Ascending&IncludeItemTypes=BoxSet&format=json&ImageTypeLimit=1"
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
@ -275,7 +286,7 @@ class ReadEmbyDB():
|
||||||
result = None
|
result = None
|
||||||
doUtils = DownloadUtils()
|
doUtils = DownloadUtils()
|
||||||
|
|
||||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&Fields=ItemCounts&format=json&ImageTypeLimit=1" % boxsetId
|
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s&Fields=ItemCounts,Etag&format=json&ImageTypeLimit=1" % boxsetId
|
||||||
|
|
||||||
jsonData = doUtils.downloadUrl(url)
|
jsonData = doUtils.downloadUrl(url)
|
||||||
if (jsonData == ""):
|
if (jsonData == ""):
|
||||||
|
|
|
@ -11,302 +11,49 @@ import os
|
||||||
|
|
||||||
import Utils as utils
|
import Utils as utils
|
||||||
|
|
||||||
|
|
||||||
#sleepval is used to throttle the calls to the xbmc json API
|
|
||||||
sleepVal = 15
|
|
||||||
|
|
||||||
class ReadKodiDB():
|
class ReadKodiDB():
|
||||||
|
|
||||||
def getKodiMovie(self, id):
|
|
||||||
#returns a single movie from Kodi db selected on MB item ID
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["art", "rating", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "studio", "set", "imdbnumber", "mpaa", "tagline", "plotoutline","plot", "sorttitle", "director", "lastplayed", "writer", "playcount", "tag", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMovies"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
movie = None
|
|
||||||
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
def getKodiMovies(self, connection, cursor):
|
||||||
if(result.has_key('movies')):
|
|
||||||
movies = result['movies']
|
|
||||||
movie = movies[0]
|
|
||||||
for item in movies:
|
|
||||||
if item["imdbnumber"] == id:
|
|
||||||
movie = item
|
|
||||||
break
|
|
||||||
return movie
|
|
||||||
|
|
||||||
def getEmbyIdByKodiId(self, kodiid, type):
|
|
||||||
#returns the emby id by search on kodi id
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
|
|
||||||
embyId = None
|
|
||||||
json_response = None
|
|
||||||
|
|
||||||
if type == "movie":
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovieDetails", "params": { "movieid": %d, "properties" : ["imdbnumber","file"] }, "id": "libMovies"}' %kodiid)
|
|
||||||
if type == "episode":
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": %d, "properties": ["file","uniqueid"]}, "id": 1}' %kodiid)
|
|
||||||
if type == "musicvideo":
|
|
||||||
connection = utils.KodiSQL()
|
|
||||||
cursor = connection.cursor()
|
|
||||||
cursor.execute("SELECT c23 as MBid FROM musicvideo WHERE idMVideo = ?",(kodiid,))
|
|
||||||
result = cursor.fetchone()
|
|
||||||
cursor.close()
|
|
||||||
if result != None:
|
|
||||||
embyId = result[0]
|
|
||||||
|
|
||||||
if json_response != None:
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
resulttype = type + "details"
|
|
||||||
if(result.has_key(resulttype)):
|
|
||||||
item = result[resulttype]
|
|
||||||
if type == "movie":
|
|
||||||
if item.has_key('imdbnumber'):
|
|
||||||
embyId = item['imdbnumber']
|
|
||||||
if type == "episode":
|
|
||||||
if item.has_key('uniqueid'):
|
|
||||||
if item['uniqueid'].has_key('unknown'):
|
|
||||||
embyId = item["uniqueid"]["unknown"]
|
|
||||||
|
|
||||||
return embyId
|
|
||||||
|
|
||||||
def getKodiMovies(self,fullInfo = False):
|
|
||||||
#returns all movies in Kodi db
|
#returns all movies in Kodi db
|
||||||
xbmc.sleep(sleepVal)
|
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='movie'")
|
||||||
if fullInfo:
|
allmovies = cursor.fetchall()
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["art", "rating", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "cast", "trailer", "country", "lastplayed", "studio", "set", "imdbnumber", "mpaa", "tagline", "plotoutline","plot", "sorttitle", "director", "writer", "playcount", "tag", "file"] }, "id": "libMovies"}')
|
#this will return a list with tuples of all items returned from the database
|
||||||
else:
|
return allmovies
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMovies", "params": { "properties" : ["resume", "playcount", "imdbnumber", "lastplayed", "file"] }, "id": "libMovies"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
movies = None
|
|
||||||
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('movies')):
|
|
||||||
movies = result['movies']
|
|
||||||
|
|
||||||
kodiMovieMap = None
|
|
||||||
if(movies != None and len(movies) > 0):
|
|
||||||
kodiMovieMap = {}
|
|
||||||
for kodimovie in movies:
|
|
||||||
key = kodimovie["imdbnumber"] #extract the id from the imdbnumber
|
|
||||||
kodiMovieMap[key] = kodimovie
|
|
||||||
|
|
||||||
return kodiMovieMap
|
|
||||||
|
|
||||||
def getKodiMoviesIds(self,returnMB3Ids = False):
|
def getKodiMusicVideos(self, connection, cursor):
|
||||||
# returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library
|
#returns all musicvideos in Kodi db
|
||||||
allKodiMovies = self.getKodiMovies(False)
|
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='musicvideo'")
|
||||||
|
allvideos = cursor.fetchall()
|
||||||
if(allKodiMovies == None):
|
#this will return a list with tuples of all items returned from the database
|
||||||
return list()
|
return allvideos
|
||||||
|
|
||||||
if(returnMB3Ids):
|
|
||||||
allKodiMovieIds = list(allKodiMovies.keys())
|
|
||||||
return allKodiMovieIds
|
|
||||||
else:
|
|
||||||
allKodiMovieIds = list()
|
|
||||||
for kodimovie in allKodiMovies.values():
|
|
||||||
id = str(kodimovie["movieid"])
|
|
||||||
allKodiMovieIds.append(id)
|
|
||||||
|
|
||||||
return allKodiMovieIds
|
|
||||||
|
|
||||||
def getKodiTvShowsIds(self,returnMB3Ids = False):
|
def getKodiTvShows(self, connection, cursor):
|
||||||
# returns a list of tvshowIds or MB3 Id's from all tvshows currently in the Kodi library
|
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='tvshow'")
|
||||||
allKodiTvShows = self.getKodiTvShows(False)
|
allshows = cursor.fetchall()
|
||||||
|
#this will return a list with tuples of all items returned from the database
|
||||||
if allKodiTvShows == None:
|
return allshows
|
||||||
return list()
|
|
||||||
|
|
||||||
if(returnMB3Ids):
|
|
||||||
allKodiTvShowsIds = list(allKodiTvShows.keys())
|
|
||||||
return allKodiTvShowsIds
|
|
||||||
else:
|
|
||||||
allKodiTvShowsIds = list()
|
|
||||||
for kodishow in allKodiTvShows.values():
|
|
||||||
id = str(kodishow["tvshowid"])
|
|
||||||
allKodiTvShowsIds.append(id)
|
|
||||||
|
|
||||||
return allKodiTvShowsIds
|
|
||||||
|
|
||||||
def getKodiTvShows(self,fullInfo = False):
|
|
||||||
#returns all tvshows in Kodi db inserted by MB
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
if fullInfo:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "premiered", "rating", "thumbnail", "playcount", "lastplayed", "file", "fanart", "tag"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}')
|
|
||||||
else:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["sorttitle", "title", "playcount", "lastplayed", "imdbnumber", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
tvshows = None
|
|
||||||
|
|
||||||
if(jsonobject.has_key('result')):
|
def getKodiEpisodes(self, connection, cursor, showid=None):
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('tvshows')):
|
if showid == None:
|
||||||
tvshows = result['tvshows']
|
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=?",("episode",))
|
||||||
|
|
||||||
kodiShowMap = None
|
|
||||||
if(tvshows != None and len(tvshows) > 0):
|
|
||||||
kodiShowMap = {}
|
|
||||||
for kodishow in tvshows:
|
|
||||||
key = kodishow["imdbnumber"] #extract the id from the imdb number
|
|
||||||
kodiShowMap[key] = kodishow
|
|
||||||
|
|
||||||
return kodiShowMap
|
|
||||||
|
|
||||||
def getKodiTVShow(self, id):
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetTVShows", "params": { "properties": ["art", "genre", "plot", "mpaa", "cast", "studio", "sorttitle", "title", "originaltitle", "imdbnumber", "year", "lastplayed", "premiered", "rating", "thumbnail", "playcount", "file", "fanart", "tag"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libTvShows"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
tvshow = None
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('tvshows')):
|
|
||||||
tvshows = result['tvshows']
|
|
||||||
for show in tvshows:
|
|
||||||
if show["imdbnumber"] == id:
|
|
||||||
tvshow = show
|
|
||||||
break
|
|
||||||
return tvshow
|
|
||||||
|
|
||||||
def getKodiEpisodes(self, KodiTvShowId, fullInfo = True, returnmap = True):
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
episodes = None
|
|
||||||
if fullInfo:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "plot", "season", "episode", "showtitle", "file", "lastplayed", "rating", "resume", "art", "streamdetails", "firstaired", "runtime", "writer", "cast", "director", "dateadded", "uniqueid", "thumbnail", "fanart"], "sort": {"method": "episode"}}, "id": 1}' %KodiTvShowId)
|
|
||||||
else:
|
else:
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": %d, "properties": ["title", "playcount", "season", "episode", "lastplayed", "resume","file","uniqueid"], "sort": {"method": "episode"}}, "id": 1}' %KodiTvShowId)
|
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=? AND parent_id=?",("episode", showid))
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
episodes = None
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('episodes')):
|
|
||||||
episodes = result['episodes']
|
|
||||||
if returnmap:
|
|
||||||
episodeMap = None
|
|
||||||
if(episodes != None):
|
|
||||||
episodeMap = {}
|
|
||||||
for KodiItem in episodes:
|
|
||||||
episodeMap[KodiItem["uniqueid"]["unknown"]] = KodiItem
|
|
||||||
return episodeMap
|
|
||||||
else:
|
|
||||||
return episodes
|
|
||||||
|
|
||||||
def getKodiEpisodeByMbItem(self, episodeid, tvshowid):
|
allepisodes = cursor.fetchall()
|
||||||
episode = None
|
#this will return a list with tuples of all items returned from the database
|
||||||
tvshow = self.getKodiTVShow(tvshowid)
|
return allepisodes
|
||||||
|
|
||||||
if tvshow != None:
|
def getEmbyIdByKodiId(self, id, type, connection=None, cursor=None):
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodes", "params": {"tvshowid": ' + str(tvshow['tvshowid']) + ', "properties": ["playcount","season", "resume", "episode", "lastplayed", "uniqueid", "file"], "sort": {"method": "episode"}}, "id": 1}')
|
if not connection:
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('episodes')):
|
|
||||||
episodes = result['episodes']
|
|
||||||
for ep in episodes:
|
|
||||||
if ep["uniqueid"]["unknown"] == episodeid:
|
|
||||||
episode = ep
|
|
||||||
break
|
|
||||||
|
|
||||||
return episode
|
|
||||||
|
|
||||||
def getKodiEpisodeByMbItemEx(self, id):
|
|
||||||
connection = utils.KodiSQL()
|
|
||||||
cursor = connection.cursor()
|
|
||||||
cursor.execute("SELECT idEpisode FROM episode WHERE c20 = ?", (id,))
|
|
||||||
result = cursor.fetchone()
|
|
||||||
kodiId = None
|
|
||||||
if result != None:
|
|
||||||
kodiId = result[0]
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
episode = None
|
|
||||||
if(kodiId != None):
|
|
||||||
print "Kodi Episode ID : " + str(kodiId)
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": %d, "properties": ["playcount", "season", "resume", "episode", "lastplayed", "uniqueid", "file"]}, "id": 1}' %kodiId)
|
|
||||||
#json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetEpisodeDetails", "params": {"episodeid": ' + str(kodiId) + ', "properties": ["playcount", "season", "resume", "episode", "lastplayed", "uniqueid", "file"], "sort": {"method": "episode"}}, "id": 1}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
print "Kodi_Item: " + str(jsonobject)
|
|
||||||
if(jsonobject.has_key("result")):
|
|
||||||
result = jsonobject["result"]
|
|
||||||
if(result.has_key("episodedetails")):
|
|
||||||
episode = result["episodedetails"]
|
|
||||||
|
|
||||||
return episode
|
|
||||||
|
|
||||||
def getKodiMusicVideo(self, id):
|
|
||||||
#returns a single musicvideo from Kodi db selected on MB item ID
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
#get the mediabrowser ID from DB
|
|
||||||
connection = utils.KodiSQL()
|
|
||||||
cursor = connection.cursor()
|
|
||||||
cursor.execute("SELECT idMVideo as musicvideoid FROM musicvideo WHERE c23 = ?",(id,))
|
|
||||||
result = cursor.fetchone()
|
|
||||||
musicvideoid = None
|
|
||||||
if result != None:
|
|
||||||
musicvideoid = result[0]
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
musicvideo = None
|
|
||||||
|
|
||||||
if musicvideoid != None:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideosDetails", "params": { "musicvideoid": ' + musicvideoid + ', "properties" : ["art", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "studio", "artist", "album", "track","plot", "director", "playcount", "lastplayed", "tag", "file"], "sort": { "order": "ascending", "method": "label", "ignorearticle": true } }, "id": "libMusicVideos"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
musicvideo = None
|
|
||||||
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('musicvideodetails')):
|
|
||||||
musicvideo = result['musicvideodetails']
|
|
||||||
|
|
||||||
return musicvideo
|
|
||||||
|
|
||||||
def getKodiMusicVideos(self,fullInfo = False):
|
|
||||||
#returns all musicvideos in Kodi db inserted by MB
|
|
||||||
xbmc.sleep(sleepVal)
|
|
||||||
if fullInfo:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideos", "params": { "properties" : ["art", "thumbnail", "fanart", "resume", "runtime", "year", "genre", "studio", "artist", "album", "track", "lastplayed", "plot", "director", "playcount", "tag", "file"] }, "id": "libMusicVideos"}')
|
|
||||||
else:
|
|
||||||
json_response = xbmc.executeJSONRPC('{"jsonrpc": "2.0", "method": "VideoLibrary.GetMusicVideos", "params": { "properties" : ["resume", "playcount", "lastplayed", "file", "track"] }, "id": "libMusicVideos"}')
|
|
||||||
jsonobject = json.loads(json_response.decode('utf-8','replace'))
|
|
||||||
musicvideos = None
|
|
||||||
if(jsonobject.has_key('result')):
|
|
||||||
result = jsonobject['result']
|
|
||||||
if(result.has_key('musicvideos')):
|
|
||||||
musicvideos = result['musicvideos']
|
|
||||||
|
|
||||||
kodiMusicVideoMap = None
|
|
||||||
if(musicvideos != None and len(musicvideos) > 0):
|
|
||||||
kodiMusicVideoMap = {}
|
|
||||||
connection = utils.KodiSQL()
|
connection = utils.KodiSQL()
|
||||||
cursor = connection.cursor()
|
cursor = connection.cursor()
|
||||||
for kodivideo in musicvideos:
|
cursor.execute("SELECT emby_id FROM emby WHERE media_type=? AND kodi_id=?",(type,id))
|
||||||
cursor.execute("SELECT c23 as MBid FROM musicvideo WHERE idMVideo = ?",(kodivideo["musicvideoid"],))
|
result = cursor.fetchone()
|
||||||
result = cursor.fetchone()
|
if result:
|
||||||
if result != None:
|
return result[0]
|
||||||
key = result[0]
|
|
||||||
kodiMusicVideoMap[key] = kodivideo
|
|
||||||
|
|
||||||
cursor.close()
|
|
||||||
return kodiMusicVideoMap
|
|
||||||
|
|
||||||
def getKodiMusicVideoIds(self,returnMB3Ids = False):
|
|
||||||
# returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library
|
|
||||||
allKodiMusicVideos = self.getKodiMusicVideos(False)
|
|
||||||
|
|
||||||
if(allKodiMusicVideos == None):
|
|
||||||
return list()
|
|
||||||
|
|
||||||
if(returnMB3Ids):
|
|
||||||
allKodiMusicVideoIds = list(allKodiMusicVideos.keys())
|
|
||||||
return allKodiMusicVideoIds
|
|
||||||
else:
|
else:
|
||||||
allKodiMusicVideoIds = list()
|
return None
|
||||||
for kodivideo in allKodiMusicVideos.values():
|
|
||||||
id = str(kodivideo["musicvideoid"])
|
|
||||||
allKodiMusicVideoIds.append(id)
|
|
||||||
|
|
||||||
return allKodiMusicVideoIds
|
|
||||||
|
|
|
@ -45,17 +45,17 @@ class UserClient(threading.Thread):
|
||||||
def __init__(self, *args):
|
def __init__(self, *args):
|
||||||
|
|
||||||
self.__dict__ = self._shared_state
|
self.__dict__ = self._shared_state
|
||||||
self.className = self.__class__.__name__
|
|
||||||
|
|
||||||
threading.Thread.__init__(self, *args)
|
threading.Thread.__init__(self, *args)
|
||||||
|
|
||||||
def logMsg(self, msg, lvl=1):
|
def logMsg(self, msg, lvl=1):
|
||||||
|
|
||||||
utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl))
|
className = self.__class__.__name__
|
||||||
|
utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl))
|
||||||
|
|
||||||
def getUsername(self):
|
def getUsername(self):
|
||||||
|
|
||||||
username = self.addon.getSetting('username')
|
addon = xbmcaddon.Addon(id=self.addonId)
|
||||||
|
username = addon.getSetting('username')
|
||||||
|
|
||||||
if (username == ""):
|
if (username == ""):
|
||||||
self.logMsg("No username saved.", 2)
|
self.logMsg("No username saved.", 2)
|
||||||
|
@ -90,7 +90,7 @@ class UserClient(threading.Thread):
|
||||||
def getServer(self, prefix=True):
|
def getServer(self, prefix=True):
|
||||||
|
|
||||||
# For https support
|
# For https support
|
||||||
addon = self.addon
|
addon = xbmcaddon.Addon(id=self.addonId)
|
||||||
HTTPS = addon.getSetting('https')
|
HTTPS = addon.getSetting('https')
|
||||||
host = addon.getSetting('ipaddress')
|
host = addon.getSetting('ipaddress')
|
||||||
port = addon.getSetting('port')
|
port = addon.getSetting('port')
|
||||||
|
@ -161,6 +161,9 @@ class UserClient(threading.Thread):
|
||||||
|
|
||||||
if (result != ""):
|
if (result != ""):
|
||||||
users = result
|
users = result
|
||||||
|
else:
|
||||||
|
# Server connection failed
|
||||||
|
return False
|
||||||
|
|
||||||
return users
|
return users
|
||||||
|
|
||||||
|
@ -226,9 +229,6 @@ class UserClient(threading.Thread):
|
||||||
users = self.getPublicUsers()
|
users = self.getPublicUsers()
|
||||||
password = ""
|
password = ""
|
||||||
|
|
||||||
'''if users == "":
|
|
||||||
self.WINDOW.setProperty("Server_status", "Stop")
|
|
||||||
return'''
|
|
||||||
# Find user in list
|
# Find user in list
|
||||||
for user in users:
|
for user in users:
|
||||||
name = user[u'Name']
|
name = user[u'Name']
|
||||||
|
|
|
@ -53,7 +53,7 @@ def convertEncoding(data):
|
||||||
|
|
||||||
def KodiSQL():
|
def KodiSQL():
|
||||||
connection = sqlite3.connect(getKodiDBPath())
|
connection = sqlite3.connect(getKodiDBPath())
|
||||||
|
|
||||||
return connection
|
return connection
|
||||||
|
|
||||||
def getKodiDBPath():
|
def getKodiDBPath():
|
||||||
|
@ -62,7 +62,7 @@ def getKodiDBPath():
|
||||||
dbVersion = "78"
|
dbVersion = "78"
|
||||||
if xbmc.getInfoLabel("System.BuildVersion").startswith("15"):
|
if xbmc.getInfoLabel("System.BuildVersion").startswith("15"):
|
||||||
#isengard
|
#isengard
|
||||||
dbVersion = "91"
|
dbVersion = "92"
|
||||||
else:
|
else:
|
||||||
#helix
|
#helix
|
||||||
dbVersion = "90"
|
dbVersion = "90"
|
||||||
|
|
|
@ -20,6 +20,7 @@ from DownloadUtils import DownloadUtils
|
||||||
from PlaybackUtils import PlaybackUtils
|
from PlaybackUtils import PlaybackUtils
|
||||||
from LibrarySync import LibrarySync
|
from LibrarySync import LibrarySync
|
||||||
from WriteKodiDB import WriteKodiDB
|
from WriteKodiDB import WriteKodiDB
|
||||||
|
from ReadEmbyDB import ReadEmbyDB
|
||||||
|
|
||||||
pendingUserDataList = []
|
pendingUserDataList = []
|
||||||
pendingItemsToRemove = []
|
pendingItemsToRemove = []
|
||||||
|
@ -179,39 +180,40 @@ class WebSocketThread(threading.Thread):
|
||||||
self.update_items(itemsToUpdate)
|
self.update_items(itemsToUpdate)
|
||||||
|
|
||||||
def remove_items(self, itemsRemoved):
|
def remove_items(self, itemsRemoved):
|
||||||
|
connection = utils.KodiSQL()
|
||||||
|
cursor = connection.cursor()
|
||||||
for item in itemsRemoved:
|
for item in itemsRemoved:
|
||||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0)
|
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0)
|
||||||
WriteKodiDB().deleteEpisodeFromKodiLibraryByMbId(item)
|
WriteKodiDB().deleteItemFromKodiLibrary(item, connection, cursor)
|
||||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMovieFromKodiLibrary: " + item, 0)
|
connection.commit()
|
||||||
WriteKodiDB().deleteMovieFromKodiLibrary(item)
|
cursor.close()
|
||||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMusicVideoFromKodiLibrary: " + item, 0)
|
|
||||||
WriteKodiDB().deleteMusicVideoFromKodiLibrary(item)
|
|
||||||
|
|
||||||
def update_items(self, itemsToUpdate):
|
def update_items(self, itemsToUpdate):
|
||||||
# doing adds and updates
|
# doing adds and updates
|
||||||
if(len(itemsToUpdate) > 0):
|
if(len(itemsToUpdate) > 0):
|
||||||
self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
|
self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
|
||||||
connection = utils.KodiSQL()
|
LibrarySync().IncrementalSync(itemsToUpdate)
|
||||||
cursor = connection.cursor()
|
|
||||||
LibrarySync().MoviesSync(connection, cursor, fullsync = False, installFirstRun = False, itemList = itemsToUpdate)
|
|
||||||
LibrarySync().TvShowsSync(connection, cursor, fullsync = False, installFirstRun = False, itemList = itemsToUpdate)
|
|
||||||
cursor.close()
|
|
||||||
|
|
||||||
def user_data_update(self, userDataList):
|
def user_data_update(self, userDataList):
|
||||||
|
itemsToUpdate = list()
|
||||||
for userData in userDataList:
|
for userData in userDataList:
|
||||||
self.logMsg("Message : Doing UserDataChanged : UserData : " + str(userData), 0)
|
|
||||||
itemId = userData.get("ItemId")
|
itemId = userData.get("ItemId")
|
||||||
if(itemId != None):
|
if(itemId != None):
|
||||||
self.logMsg("Message : Doing UserDataChanged : calling updatePlayCount with ID : " + str(itemId), 0)
|
itemsToUpdate.append(itemId)
|
||||||
LibrarySync().updatePlayCount(itemId)
|
if(len(itemsToUpdate) > 0):
|
||||||
|
self.logMsg("Message : Doing UserDataChanged : Processing Updated : " + str(itemsToUpdate), 0)
|
||||||
|
LibrarySync().IncrementalSync(itemsToUpdate)
|
||||||
|
|
||||||
def on_error(self, ws, error):
|
def on_error(self, ws, error):
|
||||||
self.logMsg("Error : " + str(error))
|
if "10061" in str(error):
|
||||||
|
# Server is offline
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
self.logMsg("Error: %s" % error, 1)
|
||||||
#raise
|
#raise
|
||||||
|
|
||||||
def on_close(self, ws):
|
def on_close(self, ws):
|
||||||
self.logMsg("Closed")
|
self.logMsg("Closed", 2)
|
||||||
|
|
||||||
def on_open(self, ws):
|
def on_open(self, ws):
|
||||||
pass
|
pass
|
||||||
|
@ -245,12 +247,19 @@ class WebSocketThread(threading.Thread):
|
||||||
self.client.on_open = self.on_open
|
self.client.on_open = self.on_open
|
||||||
|
|
||||||
while not self.KodiMonitor.abortRequested():
|
while not self.KodiMonitor.abortRequested():
|
||||||
self.logMsg("Client Starting")
|
|
||||||
self.client.run_forever()
|
self.client.run_forever()
|
||||||
if(self.keepRunning):
|
|
||||||
self.logMsg("Client Needs To Restart")
|
if (self.keepRunning):
|
||||||
|
# Server is not online
|
||||||
|
if WINDOW.getProperty("Server_online") == "true":
|
||||||
|
self.logMsg("Server is unreachable.", 1)
|
||||||
|
WINDOW.setProperty("Server_online", "false")
|
||||||
|
xbmcgui.Dialog().notification("Error connecting", "Server is unreachable.")
|
||||||
|
|
||||||
if self.KodiMonitor.waitForAbort(5):
|
if self.KodiMonitor.waitForAbort(5):
|
||||||
break
|
break
|
||||||
|
|
||||||
self.logMsg("Thread Exited")
|
self.logMsg("Thread Exited")
|
||||||
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -12,12 +12,9 @@
|
||||||
<setting id="deviceName" type="text" label="30016" default="Kodi" />
|
<setting id="deviceName" type="text" label="30016" default="Kodi" />
|
||||||
<setting id="playFromStream" type="bool" label="30002" visible="true" enable="true" default="false" />
|
<setting id="playFromStream" type="bool" label="30002" visible="true" enable="true" default="false" />
|
||||||
</category>
|
</category>
|
||||||
<!-- <category label="Manual sync"> <setting label="Run manual full sync now" type="action" action="RunScript(plugin.video.mbsync, fullsync)" /> <setting label="Run manual incremental sync now" type="action" action="RunScript(plugin.video.mbsync, incrementalsync)" /> <setting label="Reset entire local library" type="action" action="RunScript(plugin.video.mbsync, reset)" /> </category> -->
|
|
||||||
<category label="Sync Options">
|
<category label="Sync Options">
|
||||||
<!-- <setting id="syncMovieBoxSets" type="bool" label="30238" default="true" visible="true" enable="true" /> -->
|
<!-- <setting id="syncMovieBoxSets" type="bool" label="30238" default="true" visible="true" enable="true" /> -->
|
||||||
<setting id="enablePlayCountSync" type="bool" label="30240" default="true" visible="true" enable="true" />
|
<setting id="dbSyncIndication" type="bool" label="30241" default="false" visible="true" enable="true" />
|
||||||
<setting id="dbSyncIndication" type="labelenum" label="30241" values="None|Notify OnChange|Notify OnFinish|BG Progress|Dialog Progress" default="None" />
|
|
||||||
<setting id="playCountSyncIndication" type="labelenum" label="30242" values="None|Notify OnChange|Notify OnFinish|BG Progress|Dialog Progress" default="None" />
|
|
||||||
</category>
|
</category>
|
||||||
<category label="Playback"> <!-- Extra Sync options -->
|
<category label="Playback"> <!-- Extra Sync options -->
|
||||||
<setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" />
|
<setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" />
|
||||||
|
@ -27,6 +24,9 @@
|
||||||
<setting id="videoBitRate" type="enum" label="30160" values="664 Kbps SD|996 Kbps HD|1.3 Mbps HD|2.0 Mbps HD|3.2 Mbps HD|4.7 Mbps HD|6.2 Mbps HD|7.7 Mbps HD|9.2 Mbps HD|10.7 Mbps HD|12.2 Mbps HD|13.7 Mbps HD|15.2 Mbps HD|16.7 Mbps HD|18.2 Mbps HD|20.0 Mbps HD|40.0 Mbps HD|100.0 Mbps HD [default]|1000.0 Mbps HD" default="17" />
|
<setting id="videoBitRate" type="enum" label="30160" values="664 Kbps SD|996 Kbps HD|1.3 Mbps HD|2.0 Mbps HD|3.2 Mbps HD|4.7 Mbps HD|6.2 Mbps HD|7.7 Mbps HD|9.2 Mbps HD|10.7 Mbps HD|12.2 Mbps HD|13.7 Mbps HD|15.2 Mbps HD|16.7 Mbps HD|18.2 Mbps HD|20.0 Mbps HD|40.0 Mbps HD|100.0 Mbps HD [default]|1000.0 Mbps HD" default="17" />
|
||||||
<setting id="forceTranscodingCodecs" type="text" label="30245" />
|
<setting id="forceTranscodingCodecs" type="text" label="30245" />
|
||||||
</category>
|
</category>
|
||||||
|
<category label="Artwork">
|
||||||
|
<setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" />
|
||||||
|
</category>
|
||||||
<category label="30022">
|
<category label="30022">
|
||||||
<setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="1" />
|
<setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="1" />
|
||||||
<setting label="30239" type="action" action="RunScript(plugin.video.emby, reset)" />
|
<setting label="30239" type="action" action="RunScript(plugin.video.emby, reset)" />
|
||||||
|
|
174
service.py
174
service.py
|
@ -19,6 +19,7 @@ from ConnectionManager import ConnectionManager
|
||||||
from ClientInformation import ClientInformation
|
from ClientInformation import ClientInformation
|
||||||
from WebSocketClient import WebSocketThread
|
from WebSocketClient import WebSocketThread
|
||||||
from UserClient import UserClient
|
from UserClient import UserClient
|
||||||
|
from PlaybackUtils import PlaybackUtils
|
||||||
librarySync = LibrarySync()
|
librarySync = LibrarySync()
|
||||||
|
|
||||||
|
|
||||||
|
@ -30,7 +31,10 @@ class Service():
|
||||||
|
|
||||||
clientInfo = ClientInformation()
|
clientInfo = ClientInformation()
|
||||||
addonName = clientInfo.getAddonName()
|
addonName = clientInfo.getAddonName()
|
||||||
className = None
|
WINDOW = xbmcgui.Window(10000)
|
||||||
|
|
||||||
|
warn_auth = True
|
||||||
|
server_online = True
|
||||||
|
|
||||||
def __init__(self, *args ):
|
def __init__(self, *args ):
|
||||||
self.KodiMonitor = KodiMonitor.Kodi_Monitor()
|
self.KodiMonitor = KodiMonitor.Kodi_Monitor()
|
||||||
|
@ -40,24 +44,21 @@ class Service():
|
||||||
self.logMsg("======== START %s ========" % addonName, 0)
|
self.logMsg("======== START %s ========" % addonName, 0)
|
||||||
self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0)
|
self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 0)
|
||||||
self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)
|
self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)
|
||||||
|
self.logMsg("Platform: %s" % (self.clientInfo.getPlatform()), 0)
|
||||||
|
|
||||||
def logMsg(self, msg, lvl=1):
|
def logMsg(self, msg, lvl=1):
|
||||||
|
|
||||||
self.className = self.__class__.__name__
|
className = self.__class__.__name__
|
||||||
utils.logMsg("%s %s" % (self.addonName, self.className), str(msg), int(lvl))
|
utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl))
|
||||||
|
|
||||||
def ServiceEntryPoint(self):
|
def ServiceEntryPoint(self):
|
||||||
|
|
||||||
|
WINDOW = self.WINDOW
|
||||||
|
WINDOW.setProperty("Server_online", "")
|
||||||
|
|
||||||
ConnectionManager().checkServer()
|
ConnectionManager().checkServer()
|
||||||
|
|
||||||
lastProgressUpdate = datetime.today()
|
lastProgressUpdate = datetime.today()
|
||||||
|
|
||||||
startupComplete = False
|
startupComplete = False
|
||||||
#interval_FullSync = 600
|
|
||||||
#interval_IncrementalSync = 300
|
|
||||||
|
|
||||||
#cur_seconds_fullsync = interval_FullSync
|
|
||||||
#cur_seconds_incrsync = interval_IncrementalSync
|
|
||||||
|
|
||||||
user = UserClient()
|
user = UserClient()
|
||||||
player = Player()
|
player = Player()
|
||||||
|
@ -70,71 +71,101 @@ class Service():
|
||||||
if self.KodiMonitor.waitForAbort(1):
|
if self.KodiMonitor.waitForAbort(1):
|
||||||
# Abort was requested while waiting. We should exit
|
# Abort was requested while waiting. We should exit
|
||||||
break
|
break
|
||||||
|
|
||||||
if xbmc.Player().isPlaying():
|
|
||||||
try:
|
|
||||||
playTime = xbmc.Player().getTime()
|
|
||||||
totalTime = xbmc.Player().getTotalTime()
|
|
||||||
currentFile = xbmc.Player().getPlayingFile()
|
|
||||||
|
|
||||||
if(player.played_information.get(currentFile) != None):
|
if WINDOW.getProperty('Server_online') == "true":
|
||||||
player.played_information[currentFile]["currentPosition"] = playTime
|
# Server is online
|
||||||
|
if xbmc.Player().isPlaying():
|
||||||
# send update
|
try:
|
||||||
td = datetime.today() - lastProgressUpdate
|
playTime = xbmc.Player().getTime()
|
||||||
secDiff = td.seconds
|
totalTime = xbmc.Player().getTotalTime()
|
||||||
if(secDiff > 3):
|
currentFile = xbmc.Player().getPlayingFile()
|
||||||
try:
|
|
||||||
player.reportPlayback()
|
|
||||||
except Exception, msg:
|
|
||||||
self.logMsg("Exception reporting progress: %s" % msg)
|
|
||||||
pass
|
|
||||||
lastProgressUpdate = datetime.today()
|
|
||||||
# only try autoplay when there's 20 seconds or less remaining and only once!
|
|
||||||
if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)):
|
|
||||||
lastFile = currentFile
|
|
||||||
player.autoPlayPlayback()
|
|
||||||
|
|
||||||
except Exception, e:
|
|
||||||
self.logMsg("Exception in Playback Monitor Service: %s" % e)
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if (self.newUserClient == None):
|
|
||||||
self.newUserClient = "Started"
|
|
||||||
user.start()
|
|
||||||
# background worker for database sync
|
|
||||||
if (user.currUser != None):
|
|
||||||
|
|
||||||
# Correctly launch the websocket, if user manually launches the add-on
|
|
||||||
if (self.newWebSocketThread == None):
|
|
||||||
self.newWebSocketThread = "Started"
|
|
||||||
ws.start()
|
|
||||||
|
|
||||||
#full sync
|
|
||||||
if(startupComplete == False):
|
|
||||||
self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
|
|
||||||
libSync = librarySync.syncDatabase()
|
|
||||||
self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
|
|
||||||
countSync = librarySync.updatePlayCounts()
|
|
||||||
self.logMsg("Doing_Db_Sync: updatePlayCounts (Finished) " + str(countSync))
|
|
||||||
|
|
||||||
# Force refresh newly set thumbnails
|
if(player.played_information.get(currentFile) != None):
|
||||||
xbmc.executebuiltin("UpdateLibrary(video)")
|
player.played_information[currentFile]["currentPosition"] = playTime
|
||||||
if(libSync and countSync):
|
|
||||||
startupComplete = True
|
# send update
|
||||||
else:
|
td = datetime.today() - lastProgressUpdate
|
||||||
if self.KodiMonitor.waitForAbort(10):
|
secDiff = td.seconds
|
||||||
# Abort was requested while waiting. We should exit
|
if(secDiff > 3):
|
||||||
break
|
try:
|
||||||
WebSocketThread().processPendingActions()
|
player.reportPlayback()
|
||||||
|
except Exception, msg:
|
||||||
|
self.logMsg("Exception reporting progress: %s" % msg)
|
||||||
|
pass
|
||||||
|
lastProgressUpdate = datetime.today()
|
||||||
|
# only try autoplay when there's 20 seconds or less remaining and only once!
|
||||||
|
if (totalTime - playTime <= 20 and (lastFile==None or lastFile!=currentFile)):
|
||||||
|
lastFile = currentFile
|
||||||
|
player.autoPlayPlayback()
|
||||||
|
|
||||||
|
except Exception, e:
|
||||||
|
self.logMsg("Exception in Playback Monitor Service: %s" % e)
|
||||||
|
pass
|
||||||
else:
|
else:
|
||||||
self.logMsg("Not authenticated yet", 0)
|
# background worker for database sync
|
||||||
|
if (user.currUser != None):
|
||||||
|
self.warn_auth = True
|
||||||
|
|
||||||
|
# Correctly launch the websocket, if user manually launches the add-on
|
||||||
|
if (self.newWebSocketThread == None):
|
||||||
|
self.newWebSocketThread = "Started"
|
||||||
|
ws.start()
|
||||||
|
|
||||||
|
#full sync
|
||||||
|
if (startupComplete == False):
|
||||||
|
self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
|
||||||
|
libSync = librarySync.FullLibrarySync()
|
||||||
|
self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
|
||||||
|
|
||||||
|
if (libSync):
|
||||||
|
startupComplete = True
|
||||||
|
else:
|
||||||
|
if self.KodiMonitor.waitForAbort(1):
|
||||||
|
# Abort was requested while waiting. We should exit
|
||||||
|
break
|
||||||
|
WebSocketThread().processPendingActions()
|
||||||
|
|
||||||
|
else:
|
||||||
|
if self.warn_auth:
|
||||||
|
self.logMsg("Not authenticated yet.", 1)
|
||||||
|
self.warn_auth = False
|
||||||
|
else:
|
||||||
|
# Wait until server becomes online or shut down is requested
|
||||||
|
while not self.KodiMonitor.abortRequested():
|
||||||
|
|
||||||
self.logMsg("stopping Service", 0)
|
if user.getServer() == "":
|
||||||
|
pass
|
||||||
|
elif not user.getPublicUsers():
|
||||||
|
# Server is not online, suppress future warning
|
||||||
|
if self.server_online:
|
||||||
|
WINDOW.setProperty("Server_online", "false")
|
||||||
|
self.logMsg("Server is offline.", 1)
|
||||||
|
xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName)
|
||||||
|
self.server_online = False
|
||||||
|
else:
|
||||||
|
# Server is online
|
||||||
|
if not self.server_online:
|
||||||
|
# Server was not online when Kodi started.
|
||||||
|
# Wait for server to be fully established.
|
||||||
|
if self.KodiMonitor.waitForAbort(5):
|
||||||
|
# Abort was requested while waiting.
|
||||||
|
break
|
||||||
|
self.server_online = True
|
||||||
|
self.logMsg("Server is online and ready.", 1)
|
||||||
|
xbmcgui.Dialog().notification("Connection successful", "%s Server is online." % self.addonName, time=2000)
|
||||||
|
WINDOW.setProperty("Server_online", "true")
|
||||||
|
|
||||||
|
# Server is online, proceed.
|
||||||
|
if (self.newUserClient == None):
|
||||||
|
self.newUserClient = "Started"
|
||||||
|
user.start()
|
||||||
|
break
|
||||||
|
|
||||||
|
if self.KodiMonitor.waitForAbort(1):
|
||||||
|
# Abort was requested while waiting.
|
||||||
|
break
|
||||||
|
|
||||||
# If user reset library database.
|
# If user reset library database.
|
||||||
WINDOW = xbmcgui.Window(10000)
|
|
||||||
if WINDOW.getProperty("SyncInstallRunDone") == "false":
|
if WINDOW.getProperty("SyncInstallRunDone") == "false":
|
||||||
addon = xbmcaddon.Addon('plugin.video.emby')
|
addon = xbmcaddon.Addon('plugin.video.emby')
|
||||||
addon.setSetting("SyncInstallRunDone", "false")
|
addon.setSetting("SyncInstallRunDone", "false")
|
||||||
|
@ -143,8 +174,9 @@ class Service():
|
||||||
ws.stopClient()
|
ws.stopClient()
|
||||||
|
|
||||||
if (self.newUserClient != None):
|
if (self.newUserClient != None):
|
||||||
user.stopClient()
|
user.stopClient()
|
||||||
|
|
||||||
|
self.logMsg("======== STOP %s ========" % self.addonName, 0)
|
||||||
|
|
||||||
#start the service
|
#start the service
|
||||||
Service().ServiceEntryPoint()
|
Service().ServiceEntryPoint()
|
||||||
|
|
Loading…
Reference in a new issue