diff --git a/default.py b/default.py index e4e9988..adef440 100644 --- a/default.py +++ b/default.py @@ -37,6 +37,6 @@ Functions.mainEntryPoint() xbmc.log ("===== MBCon FINISHED =====") #clear done and exit. -sys.modules.clear() +#sys.modules.clear() diff --git a/resources/language/English/strings.xml b/resources/language/English/strings.xml index d2ec31c..7fad067 100644 --- a/resources/language/English/strings.xml +++ b/resources/language/English/strings.xml @@ -45,10 +45,6 @@ Add Resume Percent Add Episode Number Show Load Progress - Loading Content - Retrieving Data - Parsing Jason Data - Downloading Jason Data Done Processing Item : Offer delete for watched episodes diff --git a/resources/lib/DataManager.py b/resources/lib/DataManager.py new file mode 100644 index 0000000..2094adf --- /dev/null +++ b/resources/lib/DataManager.py @@ -0,0 +1,143 @@ +import hashlib +import os +import threading +import json as json + +import xbmcplugin +import xbmcgui +import xbmcaddon +import xbmc + +from DownloadUtils import DownloadUtils + +class DataManager(): + + def getCacheValidatorFromData(self, result): + result = result.get("Items") + if(result == None): + result = [] + + itemCount = 0 + unwatchedItemCount = 0 + dataHashString = ""; + + for item in result: + userData = item.get("UserData") + if(userData != None): + if(item.get("IsFolder") == False): + itemCount = itemCount + 1 + itemPercent = 0.0 + if userData.get("Played") == False: + unwatchedItemCount = unwatchedItemCount + 1 + itemPossition = userData.get("PlaybackPositionTicks") + itemRuntime = item.get("RunTimeTicks") + if(itemRuntime != None and itemPossition != None): + itemPercent = float(itemPossition) / float(itemRuntime) + else: + itemPercent == 100.0 + + dataHashString = dataHashString + str(itemCount) + "_" + item.get("Name", "name") + "_" + "{0:09.6f}".format(itemPercent) + "-" + str(unwatchedItemCount) + "|" + else: + itemCount = itemCount + item.get("RecursiveItemCount") + unwatchedItemCount = unwatchedItemCount + userData.get("UnplayedItemCount") + PlayedPercentage = userData.get("PlayedPercentage") + if PlayedPercentage == None: + PlayedPercentage = 0 + dataHashString = dataHashString + str(itemCount) + "_" + item.get("Name", "name") + "_" + "{0:09.6f}".format(PlayedPercentage) + "-" + str(unwatchedItemCount) + "|" + + # hash the data + dataHashString = dataHashString.encode("UTF-8") + m = hashlib.md5() + m.update(dataHashString) + validatorString = m.hexdigest() + + #xbmc.log("Cache_Data_Manager: getCacheValidatorFromData : RawData : " + dataHashString) + xbmc.log("Cache_Data_Manager: getCacheValidatorFromData : hashData : " + validatorString) + + return validatorString + + def loadJasonData(self, jsonData): + return json.loads(jsonData) + + def GetContent(self, url): + + # first get the url hash + m = hashlib.md5() + m.update(url) + urlHash = m.hexdigest() + + # build cache data path + __addon__ = xbmcaddon.Addon(id='plugin.video.mbcon') + __addondir__ = xbmc.translatePath( __addon__.getAddonInfo('profile')) + if not os.path.exists(os.path.join(__addondir__, "cache")): + os.makedirs(os.path.join(__addondir__, "cache")) + cacheDataPath = os.path.join(__addondir__, "cache", urlHash) + + xbmc.log("Cache_Data_Manager:" + cacheDataPath) + + # are we forcing a reload + WINDOW = xbmcgui.Window( 10000 ) + force_data_reload = WINDOW.getProperty("force_data_reload") + WINDOW.setProperty("force_data_reload", "false") + + if(os.path.exists(cacheDataPath)) and force_data_reload != "true": + # load data from cache if it is available and trigger a background + # verification process to test cache validity + xbmc.log("Cache_Data_Manager: Loading Cached File") + cachedfie = open(cacheDataPath, 'r') + jsonData = cachedfie.read() + cachedfie.close() + result = self.loadJasonData(jsonData) + + # start a worker thread to process the cache validity + actionThread = CacheManagerThread() + actionThread.setCacheData(result, url, cacheDataPath) + actionThread.start() + + xbmc.log("Cache_Data_Manager: Returning Cached Result") + return result + else: + # no cache data so load the url and save it + jsonData = DownloadUtils().downloadUrl(url, suppress=False, popup=1) + xbmc.log("Cache_Data_Manager: Loading URL and saving to cache") + cachedfie = open(cacheDataPath, 'w') + cachedfie.write(jsonData) + cachedfie.close() + result = self.loadJasonData(jsonData) + xbmc.log("Cache_Data_Manager: Returning Loaded Result") + return result + + +class CacheManagerThread(threading.Thread): + + cacheDataResult = None + dataUrl = None + cacheDataPath = None + + def setCacheData(self, cacheData, url, path): + self.cacheDataResult = cacheData + self.dataUrl = url + self.cacheDataPath = path + + def run(self): + + dataManager = DataManager() + xbmc.log("Cache_Data_Manager: CacheManagerThread Started") + + cacheValidatorString = dataManager.getCacheValidatorFromData(self.cacheDataResult) + xbmc.log("Cache_Data_Manager: Cache Validator String (" + cacheValidatorString + ")") + + jsonData = DownloadUtils().downloadUrl(self.dataUrl, suppress=False, popup=1) + loadedResult = dataManager.loadJasonData(jsonData) + loadedValidatorString = dataManager.getCacheValidatorFromData(loadedResult) + xbmc.log("Cache_Data_Manager: loaded Validator String (" + loadedValidatorString + ")") + + # if they dont match then save the data and trigger a content reload + if(cacheValidatorString != loadedValidatorString): + xbmc.log("Cache_Data_Manager: CacheManagerThread Saving new cache data and reloading container") + cachedfie = open(self.cacheDataPath, 'w') + cachedfie.write(jsonData) + cachedfie.close() + xbmc.executebuiltin("Container.Refresh") + + xbmc.log("Cache_Data_Manager: CacheManagerThread Exited") diff --git a/resources/lib/Functions.py b/resources/lib/Functions.py index 4b63607..479f139 100644 --- a/resources/lib/Functions.py +++ b/resources/lib/Functions.py @@ -56,6 +56,7 @@ from ClientInformation import ClientInformation from PersonInfo import PersonInfo from SearchDialog import SearchDialog from DisplayItems import DisplayItems +from DataManager import DataManager _MODE_GETCONTENT=0 _MODE_MOVIES=0 @@ -154,9 +155,6 @@ downloadUtils = DownloadUtils() def mainEntryPoint(): - - - ProfileCode = __settings__.getSetting('profile') == "true" if(ProfileCode): @@ -263,7 +261,7 @@ def mainEntryPoint(): showViewList(param_url, pluginhandle) WINDOW = xbmcgui.Window( 10000 ) - WINDOW.clearProperty("MB3.Background.Item.FanArt") + #WINDOW.clearProperty("MB3.Background.Item.FanArt") if(ProfileCode): pr.disable() @@ -898,125 +896,12 @@ def get_params( paramstring ): param[splitparams[0]]=splitparams[1]+"="+splitparams[2] printDebug("MBCon -> Detected parameters: " + str(param), level=2) return param - -def getCacheValidator(server, url): - parsedserver,parsedport = server.split(':') - userid = downloadUtils.getUserId() - idAndOptions = url.split("ParentId=") - id = idAndOptions[1].split("&") - jsonData = downloadUtils.downloadUrl("http://"+server+"/mediabrowser/Users/" + userid + "/Items/" + id[0] + "?format=json", suppress=False, popup=1 ) - result = json.loads(jsonData) - userData = result.get("UserData") - printDebug ("RecursiveItemCount: " + str(result.get("RecursiveItemCount"))) - printDebug ("UnplayedItemCount: " + str(userData.get("UnplayedItemCount"))) - printDebug ("PlayedPercentage: " + str(userData.get("PlayedPercentage"))) - - playedPercentage = 0.0 - if(userData.get("PlayedPercentage") != None): - playedPercentage = userData.get("PlayedPercentage") - - playedTime = "{0:09.6f}".format(playedPercentage) - playedTime = playedTime.replace(".", "-") - validatorString = "" - - validatorString = str(result.get("RecursiveItemCount")) + "_" + str(userData.get("UnplayedItemCount")) + "_" + playedTime - ''' - if result.get("RecursiveItemCount") != None: - if int(result.get("RecursiveItemCount")) <= 25: - validatorString = 'nocache' - else: - validatorString = str(result.get("RecursiveItemCount")) + "_" + str(userData.get("UnplayedItemCount")) + "_" + playedTime - printDebug("getCacheValidator : " + validatorString) - ''' - return validatorString - -def getAllMoviesCacheValidator(server, url): - parsedserver,parsedport = server.split(':') - userid = downloadUtils.getUserId() - jsonData = downloadUtils.downloadUrl("http://"+server+"/mediabrowser/Users/" + userid + "/Views?format=json", suppress=False, popup=1 ) - alldata = json.loads(jsonData) - validatorString = "" - playedTime = "" - playedPercentage = 0.0 - - userData = {} - result=alldata.get("Items") - for item in result: - if item.get("Name")=="Movies": - userData = item.get("UserData") - printDebug ("RecursiveItemCount: " + str(item.get("RecursiveItemCount"))) - printDebug ("RecursiveUnplayedCount: " + str(userData.get("UnplayedItemCount"))) - printDebug ("RecursiveUnplayedCount: " + str(userData.get("PlayedPercentage"))) - - if(userData.get("PlayedPercentage") != None): - playedPercentage = userData.get("PlayedPercentage") - - playedTime = "{0:09.6f}".format(playedPercentage) - playedTime = playedTime.replace(".","-") - - if item.get("RecursiveItemCount") != None: - if int(item.get("RecursiveItemCount")) <= 25: - validatorString = 'nocache' - else: - validatorString = "allmovies_" + str(item.get("RecursiveItemCount")) + "_" + str(userData.get("UnplayedItemCount")) + "_" + playedTime - printDebug ("getAllMoviesCacheValidator : " + validatorString) - return validatorString - -def getCacheValidatorFromData(result): - result = result.get("Items") - if(result == None): - result = [] - - itemCount = 0 - unwatchedItemCount = 0 - totalPlayedPercentage = 0 - for item in result: - userData = item.get("UserData") - if(userData != None): - if(item.get("IsFolder") == False): - itemCount = itemCount + 1 - if userData.get("Played") == False: - unwatchedItemCount = unwatchedItemCount + 1 - itemPossition = userData.get("PlaybackPositionTicks") - itemRuntime = item.get("RunTimeTicks") - if(itemRuntime != None and itemPossition != None): - itemPercent = float(itemPossition) / float(itemRuntime) - totalPlayedPercentage = totalPlayedPercentage + itemPercent - else: - totalPlayedPercentage = totalPlayedPercentage + 100 - else: - itemCount = itemCount + item.get("RecursiveItemCount") - unwatchedItemCount = unwatchedItemCount + userData.get("UnplayedItemCount") - PlayedPercentage=userData.get("PlayedPercentage") - if PlayedPercentage==None: - PlayedPercentage=0 - totalPlayedPercentage = totalPlayedPercentage + (item.get("RecursiveItemCount") * PlayedPercentage) - - if(itemCount == 0): - totalPlayedPercentage = 0.0 - else: - totalPlayedPercentage = totalPlayedPercentage / float(itemCount) - - playedTime = "{0:09.6f}".format(totalPlayedPercentage) - playedTime = playedTime.replace(".","-") - validatorString = "_" + str(itemCount) + "_" + str(unwatchedItemCount) + "_" + playedTime - printDebug ("getCacheValidatorFromData : " + validatorString) - return validatorString - + def getContent(url, pluginhandle): global viewType printDebug("== ENTER: getContent ==") - server=getServerFromURL(url) - lastbit=url.split('/')[-1] - printDebug("URL suffix: " + str(lastbit)) - printDebug("server: " + str(server)) printDebug("URL: " + str(url)) - validator = 'nocache' #Don't cache special queries (recently added etc) - if "Parent" in url: - validator = "_" + getCacheValidator(server, url) - elif "&SortOrder=Ascending&IncludeItemTypes=Movie" in url: - validator = "_" + getAllMoviesCacheValidator(server, url) # sort by if("SortBy=" in url == -1): @@ -1041,89 +926,23 @@ def getContent(url, pluginhandle): if(indexVal != None and indexVal != ""): GenreFilter = int(indexVal) url = re.sub("Genres.*?&", "Genres=" + genreFilters[GenreFilter] + "&", url) - - # ADD VALIDATOR TO FILENAME TO DETERMINE IF CACHE IS FRESH - m = hashlib.md5() - m.update(url) - urlHash = m.hexdigest() - - jsonData = "" - cacheDataPath = __addondir__ + urlHash + validator - - xbmcplugin.addSortMethod(pluginhandle, xbmcplugin.SORT_METHOD_NONE) - result = None - - WINDOW = xbmcgui.Window( 10000 ) - force_data_reload = WINDOW.getProperty("force_data_reload") - WINDOW.setProperty("force_data_reload", "false") - + + # show a progress indicator if needed progress = None if(__settings__.getSetting('showLoadProgress') == "true"): progress = xbmcgui.DialogProgress() - progress.create(__language__(30121)) - progress.update(0, __language__(30122)) + progress.create("Loading Content") + progress.update(0, "Retrieving Data") - # if a cached file exists use it - # if one does not exist then load data from the url - if(os.path.exists(cacheDataPath)) and validator != 'nocache' and force_data_reload != "true": - cachedfie = open(cacheDataPath, 'r') - jsonData = cachedfie.read() - cachedfie.close() - printDebug("Data Read From Cache : " + cacheDataPath) - if(progress != None): - progress.update(0, __language__(30123)) - try: - result = loadJasonData(jsonData) - except: - printDebug("Json load failed from cache data") - result = [] - dataLen = len(result) - printDebug("Json Load Result : " + str(dataLen)) - if(dataLen == 0): - result = None + # use the data manager to get the data + result = DataManager().GetContent(url) - # if there was no cache data or the cache data was not valid then try to load it again - if(result == None): - r = glob.glob(__addondir__ + urlHash + "*") - for i in r: - os.remove(i) - printDebug("No Cache Data, download data now") - if(progress != None): - progress.update(0, __language__(30124)) - jsonData = downloadUtils.downloadUrl(url, suppress=False, popup=1 ) - if(progress != None): - progress.update(0, __language__(30123)) - try: - result = loadJasonData(jsonData) - except: - xbmc.log("Json load failed from downloaded data") - result = [] - dataLen = len(result) - printDebug("Json Load Result : " + str(dataLen)) - if(dataLen > 0 and validator != 'nocache'): - cacheValidationString = getCacheValidatorFromData(result) - printDebug("getCacheValidator : " + validator) - printDebug("getCacheValidatorFromData : " + cacheValidationString) - if(validator == cacheValidationString): - printDebug("Validator String Match, Saving Cache Data") - cacheDataPath = __addondir__ + urlHash + cacheValidationString - printDebug("Saving data to cache : " + cacheDataPath) - cachedfie = open(cacheDataPath, 'w') - cachedfie.write(jsonData) - cachedfie.close() - elif("allmovies" in validator): - printDebug("All Movies Cache") - cacheDataPath = __addondir__ + urlHash + validator - printDebug("Saving data to cache : " + cacheDataPath) - cachedfie = open(cacheDataPath, 'w') - cachedfie.write(jsonData) - cachedfie.close() - if jsonData == "": + if result == None or len(result) == 0: if(progress != None): progress.close() return - printDebug("JSON DATA: " + str(result), level=2) + #printDebug("JSON DATA: " + str(result), level=2) dirItems = processDirectory(url, result, progress, pluginhandle) xbmcplugin.addDirectoryItems(pluginhandle, dirItems)