Merge pull request #3 from MediaBrowser/database_changes

Database changes
This commit is contained in:
Ian Mclaughlin 2015-05-04 17:55:16 +01:00
commit 5f486468ba
16 changed files with 1792 additions and 2694 deletions

View file

@ -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)')

View file

@ -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:

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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':

View file

@ -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"))

View file

@ -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 == ""):

View file

@ -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

View file

@ -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']

View file

@ -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"

View file

@ -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

View file

@ -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)" />

View file

@ -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()