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 xbmc
|
||||
import xbmcgui
|
||||
import xbmcvfs
|
||||
import os
|
||||
import threading
|
||||
import json
|
||||
|
@ -12,24 +13,80 @@ cwd = addonSettings.getAddonInfo('path')
|
|||
BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) )
|
||||
sys.path.append(BASE_RESOURCE_PATH)
|
||||
|
||||
WINDOW = xbmcgui.Window( 10000 )
|
||||
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
|
||||
import Utils as utils
|
||||
from PlaybackUtils import PlaybackUtils
|
||||
from DownloadUtils import DownloadUtils
|
||||
from ReadEmbyDB import ReadEmbyDB
|
||||
from API import API
|
||||
|
||||
try:
|
||||
params=utils.get_params(sys.argv[2])
|
||||
mode = params.get('mode',"")
|
||||
id = params.get('id',"")
|
||||
params = utils.get_params(sys.argv[2])
|
||||
mode = params['mode']
|
||||
id = params['id']
|
||||
except:
|
||||
params={}
|
||||
mode=None
|
||||
id=None
|
||||
params = {}
|
||||
mode = 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":
|
||||
utils.reset()
|
||||
else:
|
||||
else:
|
||||
xbmc.executebuiltin('Addon.OpenSettings(plugin.video.emby)')
|
||||
|
||||
|
|
|
@ -84,6 +84,7 @@ class API():
|
|||
width = ''
|
||||
aspectratio = '1:1'
|
||||
aspectfloat = 1.85
|
||||
Video3DFormat = ''
|
||||
|
||||
if mediaSources == True:
|
||||
mediaSources = item.get("MediaSources")
|
||||
|
@ -99,9 +100,10 @@ class API():
|
|||
for mediaStream in MediaStreams:
|
||||
if(mediaStream.get("Type") == "Video"):
|
||||
videocodec = mediaStream.get("Codec")
|
||||
height = str(mediaStream.get("Height"))
|
||||
width = str(mediaStream.get("Width"))
|
||||
height = int(mediaStream.get("Height"))
|
||||
width = int(mediaStream.get("Width"))
|
||||
aspectratio = mediaStream.get("AspectRatio")
|
||||
Video3DFormat = item.get("Video3DFormat")
|
||||
if aspectratio != None and len(aspectratio) >= 3:
|
||||
try:
|
||||
aspectwidth,aspectheight = aspectratio.split(':')
|
||||
|
@ -116,9 +118,30 @@ class API():
|
|||
'audiocodec' : audiocodec,
|
||||
'height' : height,
|
||||
'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):
|
||||
userData = item.get("UserData")
|
||||
resumeTime = 0
|
||||
|
@ -128,9 +151,9 @@ class API():
|
|||
else:
|
||||
watched="False"
|
||||
if userData.get("IsFavorite") == True:
|
||||
favorite="True"
|
||||
favorite=True
|
||||
else:
|
||||
favorite="False"
|
||||
favorite=False
|
||||
if(userData.get("Played") == True):
|
||||
playcount="1"
|
||||
else:
|
||||
|
|
|
@ -116,12 +116,12 @@ class ConnectionManager():
|
|||
return
|
||||
|
||||
# Option to play from http
|
||||
setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?")
|
||||
if setPlayback == 1:
|
||||
self.logMsg("Playback will be set using HTTP.", 1)
|
||||
addon.setSetting("playFromStream", "true")
|
||||
else:
|
||||
self.logMsg("Playback will be set using SMB.", 1)
|
||||
#setPlayback = xbmcgui.Dialog().yesno("Playback option", "Play your files using HTTP?")
|
||||
#if setPlayback == 1:
|
||||
#self.logMsg("Playback will be set using HTTP.", 1)
|
||||
#addon.setSetting("playFromStream", "true")
|
||||
#else:
|
||||
#self.logMsg("Playback will be set using SMB.", 1)
|
||||
|
||||
def getServerDetails(self):
|
||||
|
||||
|
|
|
@ -11,8 +11,8 @@ from ClientInformation import ClientInformation
|
|||
from requests.packages.urllib3.exceptions import InsecureRequestWarning
|
||||
|
||||
# Disable requests logging
|
||||
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
logging.getLogger("requests").setLevel(logging.WARNING)
|
||||
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
|
||||
# logging.getLogger("requests").setLevel(logging.WARNING)
|
||||
|
||||
class DownloadUtils():
|
||||
|
||||
|
@ -67,26 +67,22 @@ class DownloadUtils():
|
|||
|
||||
def postCapabilities(self, deviceId):
|
||||
|
||||
# Get sessionId
|
||||
url = "{server}/mediabrowser/Sessions?DeviceId=%s&format=json" % deviceId
|
||||
result = self.downloadUrl(url)
|
||||
# sessionId result
|
||||
self.logMsg("Session result: %s" % result, 2)
|
||||
self.sessionId = result[0][u'Id']
|
||||
self.WINDOW.setProperty('sessionId%s' % self.username, self.sessionId)
|
||||
# Post settings to session
|
||||
url = "{server}/mediabrowser/Sessions/Capabilities/Full"
|
||||
data = {
|
||||
'PlayableMediaTypes': "Audio,Video",
|
||||
'SupportedCommands': "Play,Playstate,SendString,DisplayMessage,PlayNext",
|
||||
'SupportsMediaControl': True
|
||||
}
|
||||
|
||||
# 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("PostData: %s" % data, 2)
|
||||
|
||||
self.downloadUrl(url, postBody=data, type="POST")
|
||||
self.logMsg("Posted capabilities to sessionId: %s" % self.sessionId, 1)
|
||||
try:
|
||||
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):
|
||||
|
||||
|
@ -99,9 +95,11 @@ class DownloadUtils():
|
|||
header = self.getHeader()
|
||||
|
||||
# If user enabled host certificate verification
|
||||
if self.sslverify:
|
||||
verify = True
|
||||
try:
|
||||
verify = self.sslverify
|
||||
cert = self.sslclient
|
||||
except:
|
||||
self.logMsg("Could not load SSL settings.", 1)
|
||||
|
||||
# Start session
|
||||
self.s = requests.Session()
|
||||
|
@ -153,52 +151,86 @@ class DownloadUtils():
|
|||
timeout = self.timeout
|
||||
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:
|
||||
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:
|
||||
# No response in body
|
||||
# No body in the response
|
||||
self.logMsg("====== 204 Success ======", 2)
|
||||
return default_link
|
||||
# Response code 200
|
||||
|
||||
elif r.status_code == requests.codes.ok:
|
||||
try:
|
||||
# UTF-8 - JSON object
|
||||
|
@ -207,13 +239,19 @@ class DownloadUtils():
|
|||
return r
|
||||
except:
|
||||
self.logMsg("Unable to convert the response for: %s" % url, 1)
|
||||
else:
|
||||
r.raise_for_status()
|
||||
|
||||
return default_link
|
||||
|
||||
# TO REVIEW EXCEPTIONS
|
||||
except requests.exceptions.ConnectionError as e:
|
||||
self.logMsg("Server unreachable at: %s" % url, 0)
|
||||
self.logMsg(e, 1)
|
||||
# Make the addon aware of status
|
||||
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:
|
||||
self.logMsg("Server timeout at: %s" % url, 0)
|
||||
|
@ -230,6 +268,7 @@ class DownloadUtils():
|
|||
# Tell UserClient token has been revoked.
|
||||
WINDOW.setProperty("Server_status", "401")
|
||||
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):
|
||||
# Redirects
|
||||
|
|
|
@ -11,8 +11,10 @@ import json
|
|||
import Utils as utils
|
||||
from WriteKodiDB import WriteKodiDB
|
||||
from ReadKodiDB import ReadKodiDB
|
||||
from LibrarySync import LibrarySync
|
||||
from PlayUtils import PlayUtils
|
||||
from DownloadUtils import DownloadUtils
|
||||
from PlaybackUtils import PlaybackUtils
|
||||
|
||||
class Kodi_Monitor(xbmc.Monitor):
|
||||
def __init__(self, *args, **kwargs):
|
||||
|
@ -26,65 +28,7 @@ class Kodi_Monitor(xbmc.Monitor):
|
|||
def onNotification (self,sender,method,data):
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
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":
|
||||
jsondata = json.loads(data)
|
||||
if jsondata != None:
|
||||
|
@ -97,6 +41,12 @@ class Kodi_Monitor(xbmc.Monitor):
|
|||
utils.logMsg("MB# Sync","Kodi_Monitor--> VideoLibrary.OnUpdate : " + str(data),2)
|
||||
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):
|
||||
pass
|
||||
|
||||
def PLAY(self, id):
|
||||
def PLAY(self, result, setup="service"):
|
||||
xbmc.log("PLAY Called")
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
|
||||
|
@ -43,43 +43,22 @@ class PlaybackUtils():
|
|||
userid = WINDOW.getProperty('userId%s' % username)
|
||||
server = WINDOW.getProperty('server%s' % username)
|
||||
|
||||
url = "{server}/mediabrowser/Users/{UserId}/Items/%s?format=json&ImageTypeLimit=1" % id
|
||||
result = self.downloadUtils.downloadUrl(url)
|
||||
|
||||
try:
|
||||
id = result["Id"]
|
||||
except:
|
||||
return
|
||||
|
||||
userData = result[u'UserData']
|
||||
userData = result['UserData']
|
||||
resume_result = 0
|
||||
seekTime = 0
|
||||
|
||||
#get the resume point from Kodi DB for a Movie
|
||||
kodiItem = ReadKodiDB().getKodiMovie(id)
|
||||
if kodiItem != None:
|
||||
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")))
|
||||
|
||||
if userData.get("PlaybackPositionTicks") != 0:
|
||||
reasonableTicks = int(userData.get("PlaybackPositionTicks")) / 1000
|
||||
seekTime = reasonableTicks / 10000
|
||||
|
||||
playurl = PlayUtils().getPlayUrl(server, id, result)
|
||||
|
||||
isStrmFile = False
|
||||
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)
|
||||
self.setListItemProps(server, id, listItem, result)
|
||||
|
||||
|
@ -97,17 +76,19 @@ class PlaybackUtils():
|
|||
WINDOW.setProperty(playurl+"deleteurl", "")
|
||||
WINDOW.setProperty(playurl+"deleteurl", deleteurl)
|
||||
|
||||
if seekTime != 0:
|
||||
displayTime = str(datetime.timedelta(seconds=seekTime))
|
||||
display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)]
|
||||
resumeScreen = xbmcgui.Dialog()
|
||||
resume_result = resumeScreen.select(self.language(30105), display_list)
|
||||
if resume_result == 0:
|
||||
WINDOW.setProperty(playurl+"seektime", str(seekTime))
|
||||
#show the additional resume dialog if launched from a widget
|
||||
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||
if seekTime != 0:
|
||||
displayTime = str(datetime.timedelta(seconds=seekTime))
|
||||
display_list = [ self.language(30106) + ' ' + displayTime, self.language(30107)]
|
||||
resumeScreen = xbmcgui.Dialog()
|
||||
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:
|
||||
WINDOW.clearProperty(playurl+"seektime")
|
||||
else:
|
||||
WINDOW.clearProperty(playurl+"seektime")
|
||||
|
||||
if result.get("Type")=="Episode":
|
||||
WINDOW.setProperty(playurl+"refresh_id", result.get("SeriesId"))
|
||||
|
@ -132,15 +113,15 @@ class PlaybackUtils():
|
|||
if mediaSources[0].get('DefaultSubtitleStreamIndex') != None:
|
||||
WINDOW.setProperty(playurl+"SubtitleStreamIndex", str(mediaSources[0].get('DefaultSubtitleStreamIndex')))
|
||||
|
||||
#this launches the playback
|
||||
#artwork only works with both resolvedurl and player command
|
||||
if isStrmFile:
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
||||
else:
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
||||
if(addon.getSetting("addExtraPlaybackArt") == "true"):
|
||||
utils.logMsg("PLAY", "Doing second xbmc.Player().play to add extra art")
|
||||
#launch the playback
|
||||
if setup == "service":
|
||||
xbmc.Player().play(playurl,listItem)
|
||||
elif setup == "default":
|
||||
#artwork only works from widgets (home screen) with player command as there is no listitem selected
|
||||
if xbmc.getCondVisibility("Window.IsActive(home)"):
|
||||
xbmc.Player().play(playurl,listItem)
|
||||
else:
|
||||
xbmcplugin.setResolvedUrl(int(sys.argv[1]), True, listItem)
|
||||
|
||||
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':
|
||||
|
|
|
@ -90,9 +90,9 @@ class Player( xbmc.Player ):
|
|||
self.logMsg("emby Service -> Percent Complete:" + str(percentComplete) + " Mark Played At:" + str(markPlayedAt))
|
||||
self.stopPlayback(data)
|
||||
|
||||
if(refresh_id != None):
|
||||
#if(refresh_id != None):
|
||||
#report updates playcount and resume status to Kodi and MB3
|
||||
librarySync.updatePlayCount(item_id)
|
||||
#librarySync.updatePlayCount(item_id)
|
||||
|
||||
|
||||
self.played_information.clear()
|
||||
|
@ -138,6 +138,10 @@ class Player( xbmc.Player ):
|
|||
|
||||
self.logMsg("reportPlayback Called", 2)
|
||||
xbmcplayer = self.xbmcplayer
|
||||
|
||||
if not xbmcplayer.isPlaying():
|
||||
self.logMsg("reportPlayback: Not playing anything so returning", 0)
|
||||
return
|
||||
|
||||
currentFile = xbmcplayer.getPlayingFile()
|
||||
data = self.played_information.get(currentFile)
|
||||
|
@ -176,7 +180,7 @@ class Player( xbmc.Player ):
|
|||
postdata['SubtitleStreamIndex'] = subtitleindex
|
||||
|
||||
postdata = json.dumps(postdata)
|
||||
self.logMsg("Report: %s" % postdata)
|
||||
self.logMsg("Report: %s" % postdata, 2)
|
||||
self.ws.sendProgressUpdate(postdata)
|
||||
|
||||
def onPlayBackPaused( self ):
|
||||
|
@ -204,7 +208,11 @@ class Player( xbmc.Player ):
|
|||
self.stopAll()
|
||||
|
||||
if xbmcplayer.isPlaying():
|
||||
currentFile = xbmcplayer.getPlayingFile()
|
||||
|
||||
currentFile = ""
|
||||
try:
|
||||
currentFile = xbmcplayer.getPlayingFile()
|
||||
except: pass
|
||||
self.logMsg("onPlayBackStarted: %s" % currentFile, 0)
|
||||
|
||||
# we may need to wait until the info is available
|
||||
|
@ -321,14 +329,11 @@ class Player( xbmc.Player ):
|
|||
def autoPlayPlayback(self):
|
||||
currentFile = xbmc.Player().getPlayingFile()
|
||||
data = self.played_information.get(currentFile)
|
||||
|
||||
# only report playback if emby has initiated the playback (item_id has value)
|
||||
if(data != None and data.get("item_id") != None):
|
||||
addonSettings = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
|
||||
item_id = data.get("item_id")
|
||||
type = data.get("Type")
|
||||
|
||||
# if its an episode see if autoplay is enabled
|
||||
if addonSettings.getSetting("autoPlaySeason")=="true" and type=="Episode":
|
||||
WINDOW = xbmcgui.Window( 10000 )
|
||||
|
@ -343,8 +348,10 @@ class Player( xbmc.Player ):
|
|||
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
|
||||
jsonData = self.doUtils.downloadUrl(url)
|
||||
|
||||
if(jsonData != ""):
|
||||
seasonData = json.loads(jsonData)
|
||||
seasonData = jsonData
|
||||
|
||||
if seasonData.get("Items") != None:
|
||||
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")
|
||||
|
@ -365,5 +372,5 @@ class Player( xbmc.Player ):
|
|||
xbmc.sleep(500)
|
||||
playTime = xbmc.Player().getTime()
|
||||
totalTime = xbmc.Player().getTotalTime()
|
||||
|
||||
|
||||
PlaybackUtils().PLAYAllEpisodes(seasonData.get("Items"))
|
|
@ -6,30 +6,22 @@ import xbmc
|
|||
import xbmcgui
|
||||
import xbmcaddon
|
||||
|
||||
|
||||
|
||||
from DownloadUtils import DownloadUtils
|
||||
|
||||
addon = xbmcaddon.Addon(id='plugin.video.emby')
|
||||
|
||||
class ReadEmbyDB():
|
||||
|
||||
def getMovies(self, id, fullinfo = False, fullSync = True, itemList = []):
|
||||
def getMovies(self, id, itemList = []):
|
||||
|
||||
result = None
|
||||
doUtils = DownloadUtils()
|
||||
|
||||
if fullSync:
|
||||
sortstring = "&SortBy=SortName"
|
||||
else:
|
||||
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)
|
||||
|
||||
#only get basic info for our sync-compares
|
||||
sortstring = "&SortBy=SortName"
|
||||
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)
|
||||
|
||||
jsonData = doUtils.downloadUrl(url)
|
||||
if (jsonData == ""):
|
||||
|
@ -37,8 +29,8 @@ class ReadEmbyDB():
|
|||
|
||||
if (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):
|
||||
newResult = []
|
||||
for item in result:
|
||||
|
@ -48,20 +40,14 @@ class ReadEmbyDB():
|
|||
|
||||
return result
|
||||
|
||||
def getMusicVideos(self, fullinfo = False, fullSync = True):
|
||||
def getMusicVideos(self, itemList = []):
|
||||
|
||||
result = None
|
||||
doUtils = DownloadUtils()
|
||||
|
||||
if not fullSync:
|
||||
sortstring = "&Limit=20&SortBy=DateCreated"
|
||||
else:
|
||||
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
|
||||
#only get basic info for our sync-compares
|
||||
sortstring = "&SortBy=SortName"
|
||||
url = "{server}/mediabrowser/Users/{UserId}/items?%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=MusicVideo&CollapseBoxSetItems=false&format=json&ImageTypeLimit=1" % sortstring
|
||||
|
||||
jsonData = doUtils.downloadUrl(url)
|
||||
if (jsonData == ""):
|
||||
|
@ -69,6 +55,14 @@ class ReadEmbyDB():
|
|||
|
||||
if (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
|
||||
|
||||
|
@ -98,20 +92,14 @@ class ReadEmbyDB():
|
|||
|
||||
return result
|
||||
|
||||
def getTVShows(self, id, fullinfo = False, fullSync = False):
|
||||
def getTvShows(self, id, itemList = []):
|
||||
|
||||
result = None
|
||||
doUtils = DownloadUtils()
|
||||
|
||||
if not fullSync:
|
||||
sortstring = "&Limit=20&SortBy=DateCreated"
|
||||
else:
|
||||
sortstring = "&SortBy=SortName"
|
||||
|
||||
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=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
||||
else:
|
||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
||||
#only get basic info for our sync-compares
|
||||
sortstring = "&SortBy=SortName"
|
||||
url = "{server}/mediabrowser/Users/{UserId}/Items?ParentId=%s%s&Fields=CumulativeRunTimeTicks,Etag&Recursive=true&SortOrder=Descending&IncludeItemTypes=Series&format=json&ImageTypeLimit=1" % (id, sortstring)
|
||||
|
||||
jsonData = doUtils.downloadUrl(url)
|
||||
if (jsonData == ""):
|
||||
|
@ -119,6 +107,14 @@ class ReadEmbyDB():
|
|||
|
||||
if (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
|
||||
|
||||
|
@ -138,15 +134,12 @@ class ReadEmbyDB():
|
|||
|
||||
return result
|
||||
|
||||
def getEpisodes(self, showId, fullinfo = False):
|
||||
def getEpisodes(self, showId, itemList = []):
|
||||
|
||||
result = None
|
||||
doUtils = DownloadUtils()
|
||||
|
||||
if fullinfo:
|
||||
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
|
||||
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
|
||||
|
||||
jsonData = doUtils.downloadUrl(url)
|
||||
if (jsonData == ""):
|
||||
|
@ -154,6 +147,14 @@ class ReadEmbyDB():
|
|||
|
||||
if (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
|
||||
|
||||
|
@ -167,9 +168,9 @@ class ReadEmbyDB():
|
|||
limitString = "Ids=" + ",".join(itemList) + "&"
|
||||
|
||||
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:
|
||||
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)
|
||||
if (jsonData == ""):
|
||||
|
@ -225,33 +226,43 @@ class ReadEmbyDB():
|
|||
doUtils = DownloadUtils()
|
||||
|
||||
viewsUrl = "{server}/mediabrowser/Users/{UserId}/Views?format=json&ImageTypeLimit=1"
|
||||
jsonData = doUtils.downloadUrl(viewsUrl)
|
||||
result = doUtils.downloadUrl(viewsUrl)
|
||||
collections=[]
|
||||
|
||||
if (jsonData != ""):
|
||||
views = views[u'Items']
|
||||
if (result == ""):
|
||||
return []
|
||||
|
||||
result = result[u'Items']
|
||||
|
||||
for view in views:
|
||||
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']
|
||||
jsonData = doUtils.downloadUrl(newViewsUrl)
|
||||
if (jsonData != ""):
|
||||
newViews = newViews[u'Items']
|
||||
for newView in newViews:
|
||||
# There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node.
|
||||
if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries":
|
||||
view=newView
|
||||
if (view[u'ChildCount'] != 0):
|
||||
Name = view[u'Name']
|
||||
|
||||
total = str(view[u'ChildCount'])
|
||||
type = view[u'CollectionType']
|
||||
if type == None:
|
||||
type = "None" # User may not have declared the type
|
||||
if type == type:
|
||||
collections.append( {'title' : Name,
|
||||
'type' : type,
|
||||
'id' : view[u'Id']})
|
||||
for view in result:
|
||||
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']
|
||||
newViews = doUtils.downloadUrl(newViewsUrl)
|
||||
if (result == ""):
|
||||
return []
|
||||
newViews = newViews[u'Items']
|
||||
print str(newViews)
|
||||
for newView in newViews:
|
||||
# There are multiple nodes in here like 'Latest', 'NextUp' - below we grab the full node.
|
||||
if newView[u'CollectionType'] != None:
|
||||
if newView[u'CollectionType'] == "MovieMovies" or newView[u'CollectionType'] == "TvShowSeries":
|
||||
view=newView
|
||||
if (view[u'ChildCount'] != 0):
|
||||
Name = view[u'Name']
|
||||
|
||||
total = str(view[u'ChildCount'])
|
||||
try:
|
||||
itemtype = view[u'CollectionType']
|
||||
except:
|
||||
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
|
||||
|
||||
def getBoxSets(self):
|
||||
|
@ -259,7 +270,7 @@ class ReadEmbyDB():
|
|||
result = None
|
||||
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)
|
||||
if (jsonData == ""):
|
||||
|
@ -275,7 +286,7 @@ class ReadEmbyDB():
|
|||
result = None
|
||||
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)
|
||||
if (jsonData == ""):
|
||||
|
|
|
@ -11,302 +11,49 @@ import os
|
|||
|
||||
import Utils as utils
|
||||
|
||||
|
||||
#sleepval is used to throttle the calls to the xbmc json API
|
||||
sleepVal = 15
|
||||
|
||||
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']
|
||||
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):
|
||||
|
||||
def getKodiMovies(self, connection, cursor):
|
||||
#returns all movies in Kodi db
|
||||
xbmc.sleep(sleepVal)
|
||||
if fullInfo:
|
||||
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"}')
|
||||
else:
|
||||
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
|
||||
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='movie'")
|
||||
allmovies = cursor.fetchall()
|
||||
#this will return a list with tuples of all items returned from the database
|
||||
return allmovies
|
||||
|
||||
def getKodiMoviesIds(self,returnMB3Ids = False):
|
||||
# returns a list of movieIds or MB3 Id's from all movies currently in the Kodi library
|
||||
allKodiMovies = self.getKodiMovies(False)
|
||||
|
||||
if(allKodiMovies == None):
|
||||
return list()
|
||||
|
||||
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 getKodiMusicVideos(self, connection, cursor):
|
||||
#returns all musicvideos in Kodi db
|
||||
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='musicvideo'")
|
||||
allvideos = cursor.fetchall()
|
||||
#this will return a list with tuples of all items returned from the database
|
||||
return allvideos
|
||||
|
||||
def getKodiTvShowsIds(self,returnMB3Ids = False):
|
||||
# returns a list of tvshowIds or MB3 Id's from all tvshows currently in the Kodi library
|
||||
allKodiTvShows = self.getKodiTvShows(False)
|
||||
|
||||
if allKodiTvShows == None:
|
||||
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
|
||||
def getKodiTvShows(self, connection, cursor):
|
||||
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type='tvshow'")
|
||||
allshows = cursor.fetchall()
|
||||
#this will return a list with tuples of all items returned from the database
|
||||
return allshows
|
||||
|
||||
if(jsonobject.has_key('result')):
|
||||
result = jsonobject['result']
|
||||
if(result.has_key('tvshows')):
|
||||
tvshows = result['tvshows']
|
||||
|
||||
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)
|
||||
def getKodiEpisodes(self, connection, cursor, showid=None):
|
||||
|
||||
if showid == None:
|
||||
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=?",("episode",))
|
||||
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)
|
||||
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
|
||||
cursor.execute("SELECT kodi_id, emby_id, checksum FROM emby WHERE media_type=? AND parent_id=?",("episode", showid))
|
||||
|
||||
def getKodiEpisodeByMbItem(self, episodeid, tvshowid):
|
||||
episode = None
|
||||
tvshow = self.getKodiTVShow(tvshowid)
|
||||
allepisodes = cursor.fetchall()
|
||||
#this will return a list with tuples of all items returned from the database
|
||||
return allepisodes
|
||||
|
||||
if tvshow != 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}')
|
||||
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 = {}
|
||||
def getEmbyIdByKodiId(self, id, type, connection=None, cursor=None):
|
||||
if not connection:
|
||||
connection = utils.KodiSQL()
|
||||
cursor = connection.cursor()
|
||||
for kodivideo in musicvideos:
|
||||
cursor.execute("SELECT c23 as MBid FROM musicvideo WHERE idMVideo = ?",(kodivideo["musicvideoid"],))
|
||||
result = cursor.fetchone()
|
||||
if result != None:
|
||||
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
|
||||
cursor.execute("SELECT emby_id FROM emby WHERE media_type=? AND kodi_id=?",(type,id))
|
||||
result = cursor.fetchone()
|
||||
if result:
|
||||
return result[0]
|
||||
else:
|
||||
allKodiMusicVideoIds = list()
|
||||
for kodivideo in allKodiMusicVideos.values():
|
||||
id = str(kodivideo["musicvideoid"])
|
||||
allKodiMusicVideoIds.append(id)
|
||||
|
||||
return allKodiMusicVideoIds
|
||||
return None
|
||||
|
||||
|
|
@ -45,17 +45,17 @@ class UserClient(threading.Thread):
|
|||
def __init__(self, *args):
|
||||
|
||||
self.__dict__ = self._shared_state
|
||||
self.className = self.__class__.__name__
|
||||
|
||||
threading.Thread.__init__(self, *args)
|
||||
|
||||
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):
|
||||
|
||||
username = self.addon.getSetting('username')
|
||||
addon = xbmcaddon.Addon(id=self.addonId)
|
||||
username = addon.getSetting('username')
|
||||
|
||||
if (username == ""):
|
||||
self.logMsg("No username saved.", 2)
|
||||
|
@ -90,7 +90,7 @@ class UserClient(threading.Thread):
|
|||
def getServer(self, prefix=True):
|
||||
|
||||
# For https support
|
||||
addon = self.addon
|
||||
addon = xbmcaddon.Addon(id=self.addonId)
|
||||
HTTPS = addon.getSetting('https')
|
||||
host = addon.getSetting('ipaddress')
|
||||
port = addon.getSetting('port')
|
||||
|
@ -161,6 +161,9 @@ class UserClient(threading.Thread):
|
|||
|
||||
if (result != ""):
|
||||
users = result
|
||||
else:
|
||||
# Server connection failed
|
||||
return False
|
||||
|
||||
return users
|
||||
|
||||
|
@ -226,9 +229,6 @@ class UserClient(threading.Thread):
|
|||
users = self.getPublicUsers()
|
||||
password = ""
|
||||
|
||||
'''if users == "":
|
||||
self.WINDOW.setProperty("Server_status", "Stop")
|
||||
return'''
|
||||
# Find user in list
|
||||
for user in users:
|
||||
name = user[u'Name']
|
||||
|
|
|
@ -53,7 +53,7 @@ def convertEncoding(data):
|
|||
|
||||
def KodiSQL():
|
||||
connection = sqlite3.connect(getKodiDBPath())
|
||||
|
||||
|
||||
return connection
|
||||
|
||||
def getKodiDBPath():
|
||||
|
@ -62,7 +62,7 @@ def getKodiDBPath():
|
|||
dbVersion = "78"
|
||||
if xbmc.getInfoLabel("System.BuildVersion").startswith("15"):
|
||||
#isengard
|
||||
dbVersion = "91"
|
||||
dbVersion = "92"
|
||||
else:
|
||||
#helix
|
||||
dbVersion = "90"
|
||||
|
|
|
@ -20,6 +20,7 @@ from DownloadUtils import DownloadUtils
|
|||
from PlaybackUtils import PlaybackUtils
|
||||
from LibrarySync import LibrarySync
|
||||
from WriteKodiDB import WriteKodiDB
|
||||
from ReadEmbyDB import ReadEmbyDB
|
||||
|
||||
pendingUserDataList = []
|
||||
pendingItemsToRemove = []
|
||||
|
@ -179,39 +180,40 @@ class WebSocketThread(threading.Thread):
|
|||
self.update_items(itemsToUpdate)
|
||||
|
||||
def remove_items(self, itemsRemoved):
|
||||
connection = utils.KodiSQL()
|
||||
cursor = connection.cursor()
|
||||
for item in itemsRemoved:
|
||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteEpisodeFromKodiLibraryByMbId: " + item, 0)
|
||||
WriteKodiDB().deleteEpisodeFromKodiLibraryByMbId(item)
|
||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMovieFromKodiLibrary: " + item, 0)
|
||||
WriteKodiDB().deleteMovieFromKodiLibrary(item)
|
||||
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteMusicVideoFromKodiLibrary: " + item, 0)
|
||||
WriteKodiDB().deleteMusicVideoFromKodiLibrary(item)
|
||||
WriteKodiDB().deleteItemFromKodiLibrary(item, connection, cursor)
|
||||
connection.commit()
|
||||
cursor.close()
|
||||
|
||||
def update_items(self, itemsToUpdate):
|
||||
# doing adds and updates
|
||||
if(len(itemsToUpdate) > 0):
|
||||
self.logMsg("Message : Doing LibraryChanged : Processing Added and Updated : " + str(itemsToUpdate), 0)
|
||||
connection = utils.KodiSQL()
|
||||
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()
|
||||
LibrarySync().IncrementalSync(itemsToUpdate)
|
||||
|
||||
def user_data_update(self, userDataList):
|
||||
|
||||
itemsToUpdate = list()
|
||||
for userData in userDataList:
|
||||
self.logMsg("Message : Doing UserDataChanged : UserData : " + str(userData), 0)
|
||||
itemId = userData.get("ItemId")
|
||||
if(itemId != None):
|
||||
self.logMsg("Message : Doing UserDataChanged : calling updatePlayCount with ID : " + str(itemId), 0)
|
||||
LibrarySync().updatePlayCount(itemId)
|
||||
itemsToUpdate.append(itemId)
|
||||
if(len(itemsToUpdate) > 0):
|
||||
self.logMsg("Message : Doing UserDataChanged : Processing Updated : " + str(itemsToUpdate), 0)
|
||||
LibrarySync().IncrementalSync(itemsToUpdate)
|
||||
|
||||
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
|
||||
|
||||
def on_close(self, ws):
|
||||
self.logMsg("Closed")
|
||||
self.logMsg("Closed", 2)
|
||||
|
||||
def on_open(self, ws):
|
||||
pass
|
||||
|
@ -245,12 +247,19 @@ class WebSocketThread(threading.Thread):
|
|||
self.client.on_open = self.on_open
|
||||
|
||||
while not self.KodiMonitor.abortRequested():
|
||||
self.logMsg("Client Starting")
|
||||
|
||||
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):
|
||||
break
|
||||
|
||||
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="playFromStream" type="bool" label="30002" visible="true" enable="true" default="false" />
|
||||
</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">
|
||||
<!-- <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="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" />
|
||||
<setting id="dbSyncIndication" type="bool" label="30241" default="false" visible="true" enable="true" />
|
||||
</category>
|
||||
<category label="Playback"> <!-- Extra Sync options -->
|
||||
<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="forceTranscodingCodecs" type="text" label="30245" />
|
||||
</category>
|
||||
<category label="Artwork">
|
||||
<setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" />
|
||||
</category>
|
||||
<category label="30022">
|
||||
<setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="1" />
|
||||
<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 WebSocketClient import WebSocketThread
|
||||
from UserClient import UserClient
|
||||
from PlaybackUtils import PlaybackUtils
|
||||
librarySync = LibrarySync()
|
||||
|
||||
|
||||
|
@ -30,7 +31,10 @@ class Service():
|
|||
|
||||
clientInfo = ClientInformation()
|
||||
addonName = clientInfo.getAddonName()
|
||||
className = None
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
|
||||
warn_auth = True
|
||||
server_online = True
|
||||
|
||||
def __init__(self, *args ):
|
||||
self.KodiMonitor = KodiMonitor.Kodi_Monitor()
|
||||
|
@ -40,24 +44,21 @@ class Service():
|
|||
self.logMsg("======== START %s ========" % addonName, 0)
|
||||
self.logMsg("KODI Version: %s" % xbmc.getInfoLabel("System.BuildVersion"), 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):
|
||||
|
||||
self.className = self.__class__.__name__
|
||||
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 ServiceEntryPoint(self):
|
||||
|
||||
WINDOW = self.WINDOW
|
||||
WINDOW.setProperty("Server_online", "")
|
||||
|
||||
ConnectionManager().checkServer()
|
||||
|
||||
lastProgressUpdate = datetime.today()
|
||||
|
||||
startupComplete = False
|
||||
#interval_FullSync = 600
|
||||
#interval_IncrementalSync = 300
|
||||
|
||||
#cur_seconds_fullsync = interval_FullSync
|
||||
#cur_seconds_incrsync = interval_IncrementalSync
|
||||
|
||||
user = UserClient()
|
||||
player = Player()
|
||||
|
@ -70,71 +71,101 @@ class Service():
|
|||
if self.KodiMonitor.waitForAbort(1):
|
||||
# Abort was requested while waiting. We should exit
|
||||
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):
|
||||
player.played_information[currentFile]["currentPosition"] = playTime
|
||||
|
||||
# send update
|
||||
td = datetime.today() - lastProgressUpdate
|
||||
secDiff = td.seconds
|
||||
if(secDiff > 3):
|
||||
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))
|
||||
if WINDOW.getProperty('Server_online') == "true":
|
||||
# Server is online
|
||||
if xbmc.Player().isPlaying():
|
||||
try:
|
||||
playTime = xbmc.Player().getTime()
|
||||
totalTime = xbmc.Player().getTotalTime()
|
||||
currentFile = xbmc.Player().getPlayingFile()
|
||||
|
||||
# Force refresh newly set thumbnails
|
||||
xbmc.executebuiltin("UpdateLibrary(video)")
|
||||
if(libSync and countSync):
|
||||
startupComplete = True
|
||||
else:
|
||||
if self.KodiMonitor.waitForAbort(10):
|
||||
# Abort was requested while waiting. We should exit
|
||||
break
|
||||
WebSocketThread().processPendingActions()
|
||||
|
||||
if(player.played_information.get(currentFile) != None):
|
||||
player.played_information[currentFile]["currentPosition"] = playTime
|
||||
|
||||
# send update
|
||||
td = datetime.today() - lastProgressUpdate
|
||||
secDiff = td.seconds
|
||||
if(secDiff > 3):
|
||||
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:
|
||||
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.
|
||||
WINDOW = xbmcgui.Window(10000)
|
||||
if WINDOW.getProperty("SyncInstallRunDone") == "false":
|
||||
addon = xbmcaddon.Addon('plugin.video.emby')
|
||||
addon.setSetting("SyncInstallRunDone", "false")
|
||||
|
@ -143,8 +174,9 @@ class Service():
|
|||
ws.stopClient()
|
||||
|
||||
if (self.newUserClient != None):
|
||||
user.stopClient()
|
||||
|
||||
user.stopClient()
|
||||
|
||||
self.logMsg("======== STOP %s ========" % self.addonName, 0)
|
||||
|
||||
#start the service
|
||||
Service().ServiceEntryPoint()
|
||||
|
|
Loading…
Reference in a new issue