Merge branch 'clean-up'

This commit is contained in:
xnappo 2015-07-15 18:32:56 -05:00
commit 0e32e254e3
8 changed files with 321 additions and 214 deletions

View file

@ -97,9 +97,9 @@
<string id="30111">Include Stream Info</string> <string id="30111">Include Stream Info</string>
<string id="30112">Include People</string> <string id="30112">Include People</string>
<string id="30113">Include Overview</string> <string id="30113">Include Overview</string>
<string id="30114">On Resume Jump Back Seconds</string> <string id="30114">Offer delete after playback</string>
<string id="30115"> - Offer delete when stopped above %</string> <string id="30115"> - For Episodes</string>
<string id="30116">Add Item and Played Counts</string> <string id="30116"> - For Movies</string>
<string id="30117">Background Art Refresh Rate (seconds)</string> <string id="30117">Background Art Refresh Rate (seconds)</string>
<string id="30118">Add Resume Percent</string> <string id="30118">Add Resume Percent</string>
<string id="30119">Add Episode Number</string> <string id="30119">Add Episode Number</string>
@ -110,7 +110,7 @@
<string id="30124">Downloading Jason Data</string> <string id="30124">Downloading Jason Data</string>
<string id="30125">Done</string> <string id="30125">Done</string>
<string id="30126">Processing Item : </string> <string id="30126">Processing Item : </string>
<string id="30127">Offer delete for watched episodes</string> <string id="30127">YOUCANUSETHIS</string>
<string id="30128">Play Error</string> <string id="30128">Play Error</string>
<string id="30129">This item is not playable</string> <string id="30129">This item is not playable</string>
<string id="30130">Local path detected</string> <string id="30130">Local path detected</string>
@ -258,4 +258,6 @@
</strings> </strings>

View file

@ -11,7 +11,6 @@ import json
import Utils as utils import Utils as utils
from WriteKodiVideoDB import WriteKodiVideoDB from WriteKodiVideoDB import WriteKodiVideoDB
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 from PlaybackUtils import PlaybackUtils
@ -119,11 +118,7 @@ class Kodi_Monitor(xbmc.Monitor):
if method == "System.OnWake": if method == "System.OnWake":
xbmc.sleep(10000) #Allow network to wake up xbmc.sleep(10000) #Allow network to wake up
if WINDOW.getProperty("SyncDatabaseRunning") != "true": WINDOW.setProperty("OnWakeSync", "true")
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",0)
libSync = LibrarySync().FullLibrarySync()
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),0)
if method == "VideoLibrary.OnRemove": if method == "VideoLibrary.OnRemove":
xbmc.log('Intercepted remove from sender: ' + sender + ' method: ' + method + ' data: ' + data) xbmc.log('Intercepted remove from sender: ' + sender + ' method: ' + method + ' data: ' + data)
@ -139,7 +134,7 @@ class Kodi_Monitor(xbmc.Monitor):
cursor.close cursor.close
if jsondata: if jsondata:
if jsondata.get("type") == "episode": if jsondata.get("type") == "episode" or "movie":
url='{server}/mediabrowser/Items?Ids=' + id + '&format=json' url='{server}/mediabrowser/Items?Ids=' + id + '&format=json'
#This is a check to see if the item exists on the server, if it doesn't it may have already been deleted by another client #This is a check to see if the item exists on the server, if it doesn't it may have already been deleted by another client
result = DownloadUtils().downloadUrl(url) result = DownloadUtils().downloadUrl(url)

View file

@ -16,8 +16,10 @@ from itertools import chain
import urllib2 import urllib2
import os import os
import KodiMonitor
from API import API from API import API
import Utils as utils import Utils as utils
from ClientInformation import ClientInformation
from DownloadUtils import DownloadUtils from DownloadUtils import DownloadUtils
from ReadEmbyDB import ReadEmbyDB from ReadEmbyDB import ReadEmbyDB
from ReadKodiDB import ReadKodiDB from ReadKodiDB import ReadKodiDB
@ -32,7 +34,28 @@ tvLibrary = os.path.join(dataPath,'tvshows')
WINDOW = xbmcgui.Window( 10000 ) WINDOW = xbmcgui.Window( 10000 )
class LibrarySync(): class LibrarySync(threading.Thread):
_shared_state = {}
KodiMonitor = KodiMonitor.Kodi_Monitor()
clientInfo = ClientInformation()
addonName = clientInfo.getAddonName()
doIncrementalSync = False
updateItems = []
removeItems = []
def __init__(self, *args):
self.__dict__ = self._shared_state
threading.Thread.__init__(self, *args)
def logMsg(self, msg, lvl=1):
className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
def FullLibrarySync(self,manualRun=False): def FullLibrarySync(self,manualRun=False):
@ -632,6 +655,103 @@ class LibrarySync():
# tell any widgets to refresh because the content has changed # tell any widgets to refresh because the content has changed
WINDOW.setProperty("widgetreload", datetime.now().strftime('%Y-%m-%d %H:%M:%S')) WINDOW.setProperty("widgetreload", datetime.now().strftime('%Y-%m-%d %H:%M:%S'))
def removefromDB(self, itemList, deleteEmbyItem = False):
# Delete from Kodi before Emby
# To be able to get mediaType
doUtils = DownloadUtils()
video = []
music = []
itemIds = ','.join(itemList)
url = "{server}/mediabrowser/Users/{UserId}/Items?Ids=%s&format=json" % itemIds
result = doUtils.downloadUrl(url)
if result is "":
# Websocket feedback
self.logMsg("Item %s is removed." % itemIds)
return
for item in result[u'Items']:
# Sort by type for database deletion
itemId = item["Id"]
mediaType = item["MediaType"]
if "Video" in mediaType:
video.append(itemId)
elif "Audio" in mediaType:
music.append(itemId)
if len(video) > 0:
#Process video library
connection = utils.KodiSQL("video")
cursor = connection.cursor()
for item in video:
type = ReadKodiDB().getTypeByEmbyId(item, connection, cursor)
self.logMsg("Type: %s" % type)
self.logMsg("Message: Doing LibraryChanged: Items Removed: Calling deleteItemFromKodiLibrary: %s" % item, 0)
if "episode" in type:
# Get the TV Show Id for reference later
showId = ReadKodiDB().getShowIdByEmbyId(item, connection, cursor)
self.logMsg("ShowId: %s" % showId, 0)
WriteKodiVideoDB().deleteItemFromKodiLibrary(item, connection, cursor)
# Verification
if "episode" in type:
showTotalCount = ReadKodiDB().getShowTotalCount(showId, connection, cursor)
self.logMsg("ShowTotalCount: %s" % showTotalCount, 0)
# If there are no episodes left
if showTotalCount == 0 or showTotalCount == None:
# Delete show
embyId = ReadKodiDB().getEmbyIdByKodiId(showId, "tvshow", connection, cursor)
self.logMsg("Message: Doing LibraryChanged: Deleting show: %s" % embyId, 0)
WriteKodiVideoDB().deleteItemFromKodiLibrary(embyId, connection, cursor)
connection.commit()
cursor.close()
if len(music) > 0:
#Process music library
addon = xbmcaddon.Addon(id='plugin.video.emby')
if addon.getSetting("enableMusicSync") is "true":
connection = utils.KodiSQL("music")
cursor = connection.cursor()
for item in music:
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteItemFromKodiLibrary (musiclibrary): " + item, 0)
WriteKodiMusicDB().deleteItemFromKodiLibrary(item, connection, cursor)
connection.commit()
cursor.close()
if deleteEmbyItem:
for item in itemList:
url = "{server}/mediabrowser/Items/%s" % item
self.logMsg('Deleting via URL: %s' % url)
doUtils.downloadUrl(url, type="DELETE")
xbmc.executebuiltin("Container.Refresh")
def remove_items(self, itemsRemoved):
self.removeItems.extend(itemsRemoved)
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)
self.updateItems.extend(itemsToUpdate)
self.doIncrementalSync = True
def user_data_update(self, userDataList):
# do full playcount update for now
for userData in userDataList:
itemId = userData.get("ItemId")
if(itemId != None):
self.updateItems.append(itemId)
if(len(self.updateItems) > 0):
self.logMsg("Message : Doing UserDataChanged : Processing Updated : " + str(self.updateItems), 0)
self.doIncrementalSync = True
def ShouldStop(self): def ShouldStop(self):
if(xbmc.abortRequested): if(xbmc.abortRequested):
@ -642,6 +762,46 @@ class LibrarySync():
return False return False
def run(self):
self.logMsg("--- Starting Library Sync Thread ---", 0)
WINDOW = xbmcgui.Window(10000)
startupComplete = False
while not self.KodiMonitor.abortRequested():
# Library sync
if not startupComplete:
# Run full sync
self.logMsg("Doing_Db_Sync: syncDatabase (Started)", 1)
libSync = self.FullLibrarySync()
self.logMsg("Doing_Db_Sync: syncDatabase (Finished) %s" % libSync, 1)
if libSync:
startupComplete = True
if WINDOW.getProperty("OnWakeSync") == "true":
WINDOW.clearProperty("OnWakeSync")
if WINDOW.getProperty("SyncDatabaseRunning") != "true":
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Started)",0)
libSync = self.FullLibrarySync()
utils.logMsg("Doing_Db_Sync Post Resume: syncDatabase (Finished) " + str(libSync),0)
if self.doIncrementalSync:
# Add or update item to Kodi library
listItems = self.updateItems
self.updateItems = []
self.doIncrementalSync = False
self.IncrementalSync(listItems)
if len(self.removeItems) > 0:
# Remove item from Kodi library
listItems = self.removeItems
self.removeItems = []
self.removefromDB(listItems)
if self.KodiMonitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break
self.logMsg("--- Library Sync Thread stopped ---", 0)

View file

@ -379,7 +379,9 @@ class PlaybackUtils():
WINDOW.setProperty(playurl + "positionurl", positionurl) WINDOW.setProperty(playurl + "positionurl", positionurl)
WINDOW.setProperty(playurl + "deleteurl", "") WINDOW.setProperty(playurl + "deleteurl", "")
if item.get("Type") == "Episode" and addon.getSetting("offerDelete")=="true": if item.get("Type") == "Episode" and addon.getSetting("offerDeleteTV")=="true":
WINDOW.setProperty(playurl + "deleteurl", deleteurl)
if item.get("Type") == "Movie" and addon.getSetting("offerDeleteMovies")=="true":
WINDOW.setProperty(playurl + "deleteurl", deleteurl) WINDOW.setProperty(playurl + "deleteurl", deleteurl)
WINDOW.setProperty(playurl + "runtimeticks", str(item.get("RunTimeTicks"))) WINDOW.setProperty(playurl + "runtimeticks", str(item.get("RunTimeTicks")))

View file

@ -103,17 +103,18 @@ class Player( xbmc.Player ):
self.stopPlayback(data) self.stopPlayback(data)
if percentComplete > .80 and data.get("Type") == "Episode" and addonSettings.getSetting("offerDelete")=="true": offerDelete=False
if data.get("Type") == "Episode" and addonSettings.getSetting("offerDeleteTV")=="true":
offerDelete = True
elif data.get("Type") == "Movie" and addonSettings.getSetting("offerDeleteMovies")=="true":
offerDelete = True
if percentComplete > .80 and offerDelete == True:
return_value = xbmcgui.Dialog().yesno("Offer Delete", "Delete\n" + data.get("currentfile").split("/")[-1] + "\non Emby Server? ") return_value = xbmcgui.Dialog().yesno("Offer Delete", "Delete\n" + data.get("currentfile").split("/")[-1] + "\non Emby Server? ")
if return_value: if return_value:
url='{server}/mediabrowser/Items/' + item_id # Delete Kodi entry before Emby
xbmc.log('Deleting via URL: ' + url) listItem = [item_id]
self.doUtils.downloadUrl(url, type="DELETE") LibrarySync().removefromDB(listItem, True)
xbmc.sleep (15000)
xbmc.executebuiltin( "Container.Refresh" )
#if(refresh_id != None):
#report updates playcount and resume status to Kodi and MB3
#librarySync.updatePlayCount(item_id)
# Stop transcoding # Stop transcoding
if self.WINDOW.getProperty("transcoding%s" % item_id) == "true": if self.WINDOW.getProperty("transcoding%s" % item_id) == "true":

View file

@ -156,7 +156,7 @@ class WebSocketThread(threading.Thread):
userDataList = data.get("UserDataList") userDataList = data.get("UserDataList")
self.logMsg("Message : Doing UserDataChanged : UserDataList : " + str(userDataList), 0) self.logMsg("Message : Doing UserDataChanged : UserDataList : " + str(userDataList), 0)
if(userDataList != None): if(userDataList != None):
self.user_data_update(userDataList) LibrarySync().user_data_update(userDataList)
elif(messageType != None and messageType == "LibraryChanged"): elif(messageType != None and messageType == "LibraryChanged"):
foldersAddedTo = data.get("FoldersAddedTo") foldersAddedTo = data.get("FoldersAddedTo")
@ -171,8 +171,8 @@ class WebSocketThread(threading.Thread):
self.logMsg("Message : WebSocket LibraryChanged : Items Updated : " + str(itemsUpdated), 0) self.logMsg("Message : WebSocket LibraryChanged : Items Updated : " + str(itemsUpdated), 0)
self.logMsg("Message : WebSocket LibraryChanged : Items Removed : " + str(itemsRemoved), 0) self.logMsg("Message : WebSocket LibraryChanged : Items Removed : " + str(itemsRemoved), 0)
self.remove_items(itemsRemoved) LibrarySync().remove_items(itemsRemoved)
self.update_items(itemsToUpdate) LibrarySync().update_items(itemsToUpdate)
elif messageType == "GeneralCommand": elif messageType == "GeneralCommand":
@ -249,56 +249,6 @@ class WebSocketThread(threading.Thread):
else: else:
self.logMsg("Unknown command.", 1) self.logMsg("Unknown command.", 1)
def remove_items(self, itemsRemoved):
#Process video library
connection = utils.KodiSQL("video")
cursor = connection.cursor()
for item in itemsRemoved:
type=ReadKodiDB().getTypeByEmbyId(item, connection, cursor)
self.logMsg("Type: " + str(type))
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteItemFromKodiLibrary: " + item, 0)
if type == "episode":
showId=ReadKodiDB().getShowIdByEmbyId(item, connection, cursor) # Get the TV Show ID
self.logMsg("ShowID: " + str(showId),0)
WriteKodiVideoDB().deleteItemFromKodiLibrary(item, connection, cursor)
if type == "episode":
showTotalCount = ReadKodiDB().getShowTotalCount(showId, connection, cursor) # Check if there are no episodes left
self.logMsg("ShowTotalCount: " + str(showTotalCount),0)
if showTotalCount == 0 or showTotalCount == None: # Delete show if no episodes are left
embyId=ReadKodiDB().getEmbyIdByKodiId(showId, "tvshow", connection, cursor)
self.logMsg("Message : Doing LibraryChanged : Deleting show:" + embyId, 0)
WriteKodiVideoDB().deleteItemFromKodiLibrary(embyId, connection, cursor)
connection.commit()
cursor.close()
#Process music library
addon = xbmcaddon.Addon(id='plugin.video.emby')
if addon.getSetting("enableMusicSync") == "true":
connection = utils.KodiSQL("music")
cursor = connection.cursor()
for item in itemsRemoved:
self.logMsg("Message : Doing LibraryChanged : Items Removed : Calling deleteItemFromKodiLibrary (musiclibrary): " + item, 0)
WriteKodiMusicDB().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)
LibrarySync().IncrementalSync(itemsToUpdate)
def user_data_update(self, userDataList):
itemsToUpdate = list()
for userData in userDataList:
itemId = userData.get("ItemId")
if(itemId != None):
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): def on_error(self, ws, error):
if "10061" in str(error): if "10061" in str(error):
# Server is offline # Server is offline

View file

@ -25,7 +25,9 @@
<setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" /> <setting id="smbusername" type="text" label="30007" default="" visible="true" enable="true" />
<setting id="smbpassword" type="text" label="30008" default="" option="hidden" visible="true" enable="true" /> <setting id="smbpassword" type="text" label="30008" default="" option="hidden" visible="true" enable="true" />
<setting type="sep" /> <setting type="sep" />
<setting id="offerDelete" type="bool" label="30127" visible="true" enable="true" default="false" /> <setting id="offerDelete" type="bool" label="30114" visible="true" enable="true" default="false" />
<setting id="offerDeleteTV" type="bool" label=" 30115" visible="eq(-1,true)" enable="true" default="false" />
<setting id="offerDeleteMovies" type="bool" label="30116" visible="eq(-2,true)" enable="true" default="false" />
<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" />
<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" visible="eq(-1,true)" 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" visible="eq(-1,true)" default="17" />
<setting id="forceTranscodingCodecs" type="text" label="30245" visible="false" /> <setting id="forceTranscodingCodecs" type="text" label="30245" visible="false" />
@ -35,7 +37,7 @@
<setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" /> <setting id="disableCoverArt" type="bool" label="30157" default="false" visible="true" enable="true" />
<setting id="coverArtratio" type="bool" label="Force CoverArt Ratio" visible="eq(-1,false)" default="false" enable="true" /> <setting id="coverArtratio" type="bool" label="Force CoverArt Ratio" visible="eq(-1,false)" default="false" enable="true" />
<setting id="ignoreSpecialsNextEpisodes" type="bool" label="Ignore specials in next episodes" visible="true" enable="true" default="false" /> <setting id="ignoreSpecialsNextEpisodes" type="bool" label="Ignore specials in next episodes" visible="true" enable="true" default="false" />
<setting id="showSpecialInfoDialog" type="bool" label="Show special Emby infodialog on play" default="false" visible="false" /> <setting id="showSpecialInfoDialog" type="bool" label="Show special Emby info dialog on play" default="false" visible="false" />
</category> </category>
<category label="30022"> <category label="30022">
<setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="0" /> <setting id="logLevel" type="enum" label="30004" values="None|Info|Debug" default="0" />

View file

@ -1,166 +1,186 @@
# -- coding: utf-8 --
import os
import sys
import time
from datetime import datetime
import xbmcaddon import xbmcaddon
import xbmc import xbmc
import xbmcgui import xbmcgui
import os
import threading
import json
from datetime import datetime
import time
cwd = xbmcaddon.Addon(id='plugin.video.emby').getAddonInfo('path') addon_ = xbmcaddon.Addon(id='plugin.video.emby')
BASE_RESOURCE_PATH = xbmc.translatePath( os.path.join( cwd, 'resources', 'lib' ) ) addon_path = addon_.getAddonInfo('path').decode('utf-8')
sys.path.append(BASE_RESOURCE_PATH) base_resource_path = xbmc.translatePath(os.path.join(addon_path, 'resources', 'lib')).decode('utf-8')
sys.path.append(base_resource_path)
import KodiMonitor import KodiMonitor
import Utils as utils import Utils as utils
from LibrarySync import LibrarySync
from Player import Player
from DownloadUtils import DownloadUtils
from ConnectionManager import ConnectionManager
from ClientInformation import ClientInformation from ClientInformation import ClientInformation
from WebSocketClient import WebSocketThread from ConnectionManager import ConnectionManager
from UserClient import UserClient from UserClient import UserClient
from PlaybackUtils import PlaybackUtils from Player import Player
librarySync = LibrarySync() from WebSocketClient import WebSocketThread
from LibrarySync import LibrarySync
class Service(): class Service():
KodiMonitor = KodiMonitor.Kodi_Monitor()
clientInfo = ClientInformation()
addonName = clientInfo.getAddonName()
logLevel = UserClient().getLogLevel()
WINDOW = xbmcgui.Window(10000)
newWebSocketThread = None newWebSocketThread = None
newUserClient = None newUserClient = None
newLibraryThread = None
clientInfo = ClientInformation()
KodiMonitor = KodiMonitor.Kodi_Monitor()
addonName = clientInfo.getAddonName()
WINDOW = xbmcgui.Window(10000)
logLevel = UserClient().getLogLevel()
warn_auth = True warn_auth = True
welcome_msg = True welcome_msg = True
server_online = True server_online = True
def __init__(self, *args ): def __init__(self, *args):
addonName = self.addonName addonName = self.addonName
WINDOW = self.WINDOW WINDOW = self.WINDOW
WINDOW.setProperty('getLogLevel', str(self.logLevel)) WINDOW.setProperty('getLogLevel', str(self.logLevel))
# Initial logging
self.logMsg("Starting Monitor", 0) self.logMsg("Starting Monitor", 0)
self.logMsg("======== START %s ========" % addonName, 0) 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) self.logMsg("Platform: %s" % (self.clientInfo.getPlatform()), 0)
self.logMsg("Log Level: %s" % self.logLevel, 0) self.logMsg("KODI Version: %s" % xbmc.getInfoLabel('System.BuildVersion'), 0)
self.logMsg("%s Version: %s" % (addonName, self.clientInfo.getVersion()), 0)
self.logMsg("Log Level: %s" % self.logLevel, 1)
# Reset window props for profile switch
WINDOW.clearProperty('Server_online')
WINDOW.clearProperty('Server_status')
WINDOW.clearProperty('startup')
WINDOW.clearProperty('OnWakeSync')
embyProperty = WINDOW.getProperty('Emby.nodes.total')
propNames = [
"index","path","title","content",
"inprogress.content","inprogress.title",
"inprogress.content","inprogress.path",
"nextepisodes.title","nextepisodes.content",
"nextepisodes.path","unwatched.title",
"unwatched.content","unwatched.path",
"recent.title","recent.content","recent.path",
"recentepisodes.title","recentepisodes.content",
"recentepisodes.path","inprogressepisodes.title",
"inprogressepisodes.content","inprogressepisodes.path"
]
#reset all window props on startup for user profile switches
self.WINDOW.clearProperty("startup")
embyProperty = WINDOW.getProperty("Emby.nodes.total")
propNames = ["index","path","title","content","inprogress.content","inprogress.title","inprogress.content","inprogress.path","nextepisodes.title","nextepisodes.content","nextepisodes.path","unwatched.title","unwatched.content","unwatched.path","recent.title","recent.content","recent.path","recentepisodes.title","recentepisodes.content","recentepisodes.path","inprogressepisodes.title","inprogressepisodes.content","inprogressepisodes.path"]
if embyProperty: if embyProperty:
totalNodes = int(embyProperty) totalNodes = int(embyProperty)
for i in range(totalNodes): for i in range(totalNodes):
for prop in propNames: for prop in propNames:
WINDOW.clearProperty("Emby.nodes.%s.%s" %(str(i),prop)) WINDOW.clearProperty('Emby.nodes.%s.%s' % (str(i), prop))
def logMsg(self, msg, lvl=1): def logMsg(self, msg, lvl=1):
className = self.__class__.__name__ className = self.__class__.__name__
utils.logMsg("%s %s" % (self.addonName, className), str(msg), int(lvl)) utils.logMsg("%s %s" % (self.addonName, className), msg, int(lvl))
def ServiceEntryPoint(self): def ServiceEntryPoint(self):
WINDOW = self.WINDOW WINDOW = self.WINDOW
addon = xbmcaddon.Addon(id=self.clientInfo.getAddonId()) addon = xbmcaddon.Addon()
WINDOW.setProperty("Server_online", "")
self.WINDOW.setProperty("Server_status", "")
WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
# Server auto-detect
ConnectionManager().checkServer() ConnectionManager().checkServer()
lastProgressUpdate = datetime.today()
startupComplete = False
# Initialize important threads
user = UserClient() user = UserClient()
player = Player() player = Player()
ws = WebSocketThread() ws = WebSocketThread()
library = LibrarySync()
lastFile = None # Sync and progress report
lastProgressUpdate = datetime.today()
while not self.KodiMonitor.abortRequested(): while not self.KodiMonitor.abortRequested():
#WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
if self.KodiMonitor.waitForAbort(1): # Before proceeding, need to make sure:
# Abort was requested while waiting. We should exit # 1. Server is online
break # 2. User is set
# 3. User has access to the server
if WINDOW.getProperty('Server_online') == "true": if WINDOW.getProperty('Server_online') == "true":
# Server is online
if (user.currUser != None) and (user.HasAccess == True):
self.warn_auth = True
if addon.getSetting('supressConnectMsg') == "false":
if self.welcome_msg:
# Reset authentication warnings
self.welcome_msg = False
xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser, time=2000, sound=False)
# Correctly launch the websocket, if user manually launches the add-on # Emby server is online
if (self.newWebSocketThread == None): # Verify if user is set and has access to the server
self.newWebSocketThread = "Started" if (user.currUser != None) and user.HasAccess:
ws.start()
# If an item is playing
if xbmc.Player().isPlaying(): if xbmc.Player().isPlaying():
#WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
try: try:
# Update and report progress
playTime = xbmc.Player().getTime() playTime = xbmc.Player().getTime()
totalTime = xbmc.Player().getTotalTime() totalTime = xbmc.Player().getTotalTime()
currentFile = xbmc.Player().getPlayingFile() currentFile = xbmc.Player().getPlayingFile()
if(player.played_information.get(currentFile) != None): # Update positionticks
if player.played_information.get(currentFile) != None:
player.played_information[currentFile]["currentPosition"] = playTime player.played_information[currentFile]["currentPosition"] = playTime
# send update
td = datetime.today() - lastProgressUpdate td = datetime.today() - lastProgressUpdate
secDiff = td.seconds secDiff = td.seconds
if(secDiff > 3):
# Report progress to Emby server
if (secDiff > 3):
try: try:
player.reportPlayback() player.reportPlayback()
except Exception, msg: except Exception as msg:
self.logMsg("Exception reporting progress: %s" % msg) self.logMsg("Exception reporting progress: %s" % msg)
pass
lastProgressUpdate = datetime.today() lastProgressUpdate = datetime.today()
elif WINDOW.getProperty('commandUpdate') == "true": elif WINDOW.getProperty('commandUpdate') == "true":
# Received a remote control command that
# requires updating immediately
try: try:
WINDOW.clearProperty('commandUpdate') WINDOW.clearProperty('commandUpdate')
player.reportPlayback() player.reportPlayback()
except: pass except: pass
lastProgressUpdate = datetime.today() lastProgressUpdate = datetime.today()
except Exception, e: except Exception as e:
self.logMsg("Exception in Playback Monitor Service: %s" % e) self.logMsg("Exception in Playback Monitor Service: %s" % e)
pass pass
else:
# Start up events
self.warn_auth = True
if addon.getSetting('supressConnectMsg') == "false":
if self.welcome_msg:
# Reset authentication warnings
self.welcome_msg = False
xbmcgui.Dialog().notification("Emby server", "Welcome %s!" % user.currUser.decode('utf-8').encode('utf-8'), time=2000, sound=False)
# Start the Websocket Client
if (self.newWebSocketThread == None):
self.newWebSocketThread = "Started"
ws.start()
# Start the Library Sync Thread
if (self.newLibraryThread == None):
self.newLibraryThread = "Started"
library.start()
else:
#full sync
if (startupComplete == False):
self.logMsg("Doing_Db_Sync: syncDatabase (Started)")
libSync = librarySync.FullLibrarySync()
self.logMsg("Doing_Db_Sync: syncDatabase (Finished) " + str(libSync))
#WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
if (libSync):
startupComplete = True
else:
if self.KodiMonitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break
else: else:
if self.warn_auth: if (user.currUser == None) and self.warn_auth:
self.logMsg("Not authenticated yet.", 1) # Alert user is not authenticated and suppress future warning
self.warn_auth = False self.warn_auth = False
self.logMsg("Not authenticated yet.", 1)
# User access is restricted.
# Keep verifying until access is granted
# unless server goes offline or Kodi is shut down.
while user.HasAccess == False: while user.HasAccess == False:
# Verify access with an API call
#WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
user.hasAccess() user.hasAccess()
if WINDOW.getProperty('Server_online') != "true": if WINDOW.getProperty('Server_online') != "true":
@ -171,37 +191,41 @@ class Service():
# Abort was requested while waiting. We should exit # Abort was requested while waiting. We should exit
break break
else: else:
# Wait until server becomes online or shut down is requested # Wait until Emby server is online
# or Kodi is shut down.
while not self.KodiMonitor.abortRequested(): while not self.KodiMonitor.abortRequested():
#WINDOW.setProperty("Emby_Service_Timestamp", str(int(time.time())))
if user.getServer() == "": if user.getServer() == "":
# No server info set in add-on settings
pass pass
elif user.getPublicUsers() == False: elif user.getPublicUsers() == False:
# Server is not online, suppress future warning # Server is offline.
# Alert the user and suppress future warning
if self.server_online: if self.server_online:
WINDOW.setProperty("Server_online", "false")
self.logMsg("Server is offline.", 1) self.logMsg("Server is offline.", 1)
WINDOW.setProperty('Server_online', "false")
xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName, sound=False) xbmcgui.Dialog().notification("Error connecting", "%s Server is unreachable." % self.addonName, sound=False)
self.server_online = False self.server_online = False
else: else:
# Server is online # Server is online
if not self.server_online: if not self.server_online:
# Server was not online when Kodi started. # Server was offline when Kodi started.
# Wait for server to be fully established. # Wait for server to be fully established.
if self.KodiMonitor.waitForAbort(5): if self.KodiMonitor.waitForAbort(5):
# Abort was requested while waiting. # Abort was requested while waiting.
break break
# Alert the user that server is online.
xbmcgui.Dialog().notification("Connection successful", "%s Server is online." % self.addonName, time=2000, sound=False) xbmcgui.Dialog().notification("Connection successful", "%s Server is online." % self.addonName, time=2000, sound=False)
self.server_online = True self.server_online = True
self.logMsg("Server is online and ready.", 1) self.logMsg("Server is online and ready.", 1)
WINDOW.setProperty("Server_online", "true") WINDOW.setProperty('Server_online', "true")
# Server is online, proceed. # Start the User client
if (self.newUserClient == None): if self.newUserClient == None:
self.newUserClient = "Started" self.newUserClient = "Started"
user.start() user.start()
break break
@ -210,12 +234,13 @@ class Service():
# Abort was requested while waiting. # Abort was requested while waiting.
break break
#self.checkService() if self.KodiMonitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
break
# If user reset library database. # If user reset library database.
if WINDOW.getProperty("SyncInstallRunDone") == "false": if WINDOW.getProperty('SyncInstallRunDone') == "false":
addon = xbmcaddon.Addon('plugin.video.emby') addon.setSetting('SyncInstallRunDone', "false")
addon.setSetting("SyncInstallRunDone", "false")
if (self.newWebSocketThread != None): if (self.newWebSocketThread != None):
ws.stopClient() ws.stopClient()
@ -225,35 +250,5 @@ class Service():
self.logMsg("======== STOP %s ========" % self.addonName, 0) self.logMsg("======== STOP %s ========" % self.addonName, 0)
# To be reviewed when moving the sync process to it's own thread
'''def checkService(self):
WINDOW = self.WINDOW
timeStamp = WINDOW.getProperty("Emby_Service_Timestamp")
loops = 0
while(timeStamp == ""):
timeStamp = WINDOW.getProperty("Emby_Service_Timestamp")
loops = loops + 1
if(loops == 5):
self.logMsg("Emby Service Not Running, no time stamp, exiting.", 0)
addon = xbmcaddon.Addon(id='plugin.video.emby')
language = addon.getLocalizedString
xbmcgui.Dialog().ok(language(30135), language(30136), language(30137))
sys.exit()
if self.KodiMonitor.waitForAbort(1):
# Abort was requested while waiting. We should exit
return
self.logMsg("Emby Service Timestamp: " + timeStamp, 2)
self.logMsg("Emby Current Timestamp: " + str(int(time.time())), 2)
if((int(timeStamp) + 30) < int(time.time())):
self.logMsg("Emby Service Not Running, time stamp to old, exiting.", 0)
addon = xbmcaddon.Addon(id='plugin.video.emby')
language = addon.getLocalizedString
xbmcgui.Dialog().ok(language(30135), language(30136), language(30137))
sys.exit()'''
#start the service #start the service
Service().ServiceEntryPoint() Service().ServiceEntryPoint()