From 5d9d8a182044b736a2aaf6603574d27b5b598104 Mon Sep 17 00:00:00 2001 From: Rob <1572423+robweber@users.noreply.github.com> Date: Tue, 10 Sep 2019 15:36:52 -0500 Subject: [PATCH 1/4] Guisettings fix (#156) fix guisettings restore issues - thanks Bluerayx --- resources/lib/backup.py | 8 ++-- resources/lib/guisettings.py | 74 +++++++++++++----------------------- 2 files changed, 31 insertions(+), 51 deletions(-) diff --git a/resources/lib/backup.py b/resources/lib/backup.py index 2d7a4ff..210390e 100644 --- a/resources/lib/backup.py +++ b/resources/lib/backup.py @@ -321,10 +321,10 @@ class XbmcBackup: self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point)) self.xbmc_vfs.rmdir(self.remote_vfs.root_path) - if(utils.getSetting("backup_config") == "true"): - #update the guisettings information (or what we can from it) - gui_settings = GuiSettingsManager('special://home/userdata/guisettings.xml') - gui_settings.run() + + #update the guisettings information (or what we can from it) + gui_settings = GuiSettingsManager('special://home/userdata/guisettings.xml') + gui_settings.run() #call update addons to refresh everything xbmc.executebuiltin('UpdateLocalAddons') diff --git a/resources/lib/guisettings.py b/resources/lib/guisettings.py index ab49c66..b4e4c12 100644 --- a/resources/lib/guisettings.py +++ b/resources/lib/guisettings.py @@ -8,8 +8,6 @@ import xbmc,xbmcvfs class GuiSettingsManager: settingsFile = None doc = None - settings_allowed = list() - found_settings = list() def __init__(self,settingsFile): self._readFile(xbmc.translatePath(settingsFile)) @@ -19,32 +17,24 @@ class GuiSettingsManager: json_response = json.loads(xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettings","params":{"level":"advanced"}}')) settings = json_response['result']['settings'] - - for aSetting in settings: - self.settings_allowed.append(aSetting['id']) - - #parse the existing xml file and get all the settings - root_nodes = self.__parseNodes(self.doc.documentElement) + settingsAllowed = [] - for aNode in root_nodes: - secondary_list = self.__parseNodes(self.doc.getElementsByTagName(aNode.name)[0]) + for aSetting in settings: + settingsAllowed.append(aSetting['id']) - for secondNode in secondary_list: - #if the node does not have children and is not default - if(not secondNode.hasChildren and not secondNode.isDefault): - - if(secondNode.json_name() in self.settings_allowed): - self.found_settings.append(secondNode) - + #parse the existing xml file and get all the settings we need to update + updateSettings = self.__parseNodes(self.doc.getElementsByTagName('setting')) + #go through all the found settings and update them - for aSetting in self.found_settings: - utils.log("updating: " + aSetting.json_name() + ", value: " + aSetting.value) + for aSetting in updateSettings: + if(aSetting.name in settingsAllowed): + utils.log("updating: " + aSetting.name + ", value: " + aSetting.value) - #check for boolean and numeric values - if(aSetting.value.isdigit() or (aSetting.value == 'true' or aSetting.value == 'false')): - xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.json_name() + '","value":' + aSetting.value + '}}') - else: - xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.json_name() + '","value":"' + utils.encode(aSetting.value) + '"}}') + #check for boolean and numeric values + if(aSetting.value.isdigit() or (aSetting.value == 'true' or aSetting.value == 'false')): + xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.name + '","value":' + aSetting.value + '}}') + else: + xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.name + '","value":"' + utils.encode(aSetting.value) + '"}}') #make a copy of the guisettings file to make user based restores easier xbmcvfs.copy(self.settingsFile, xbmc.translatePath("special://home/userdata/guisettings.xml.restored")) @@ -52,28 +42,16 @@ class GuiSettingsManager: def __parseNodes(self,nodeList): result = [] - for node in nodeList.childNodes: - if(node.nodeType == self.doc.ELEMENT_NODE): - aSetting = SettingNode(node.nodeName) + for node in nodeList: + #only add if it's not a default setting + if('default' not in node.attributes.keys()): + aSetting = SettingNode(node.getAttribute('id'),node.firstChild.nodeValue) + aSetting.isDefault = False - #detect if there are any element nodes - if(len(node.childNodes) > 0): - for child_node in node.childNodes: - if(child_node.nodeType == self.doc.ELEMENT_NODE): - aSetting.hasChildren = True - - if(not aSetting.hasChildren and len(node.childNodes) > 0): - aSetting.value = node.firstChild.nodeValue - - if('default' not in node.attributes.keys()): - aSetting.isDefault = False - - aSetting.parent = node.parentNode.nodeName - result.append(aSetting) + return result - def _readFile(self,fileLoc): if(xbmcvfs.exists(fileLoc)): @@ -86,14 +64,16 @@ class GuiSettingsManager: class SettingNode: name = '' value = '' - hasChildren = False isDefault = True - parent = '' - def __init__(self,name): + def __init__(self,name,value): self.name = name + self.value= value - def json_name(self): - return self.parent + "." + self.name + def __str__(self): + return "%s : %s" % (self.name,self.value) + + def __repr__(self): + return self.__str__() From 12b25f7ceace38747d7c456be33b1b9c649389e2 Mon Sep 17 00:00:00 2001 From: Rob Weber Date: Tue, 10 Sep 2019 15:38:34 -0500 Subject: [PATCH 2/4] version bump --- addon.xml | 8 +++----- changelog.txt | 4 ++++ 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/addon.xml b/addon.xml index f1e7dbb..0106429 100644 --- a/addon.xml +++ b/addon.xml @@ -1,6 +1,6 @@  + name="Backup" version="1.5.1" provider-name="robweber"> @@ -95,10 +95,8 @@ resources/images/screenshot3.png resources/images/screenshot4.png - Version 1.1.4 -- added file chunk support for dropbox uploads -- fixed settings duplicate ids, thanks aster-anto -- added scheduler delay to assist with time sync (rpi mostly) + Version 1.5.1 +- fix guisettings restores not working - thanks Bluerayx diff --git a/changelog.txt b/changelog.txt index 5fe992a..62a6baf 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,7 @@ +Version 1.5.1 + +fix guisettings restores not working - thanks Bluerayx + Version 1.5.0 Overhaul of file selection and restore procedures. Breaking Change with previous versions PR117 From 1f6324b2d5eaba9c4d18dfa8c67d9af33ef5f52a Mon Sep 17 00:00:00 2001 From: Rob Weber Date: Wed, 11 Sep 2019 08:58:21 -0500 Subject: [PATCH 3/4] use path separators for os --- resources/lib/backup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/resources/lib/backup.py b/resources/lib/backup.py index 210390e..a1408dd 100644 --- a/resources/lib/backup.py +++ b/resources/lib/backup.py @@ -4,12 +4,12 @@ import xbmcvfs import utils as utils import time import json +import os from datetime import datetime from vfs import XBMCFileSystem,DropboxFileSystem,ZipFileSystem,GoogleDriveFilesystem from progressbar import BackupProgressBar from resources.lib.guisettings import GuiSettingsManager from resources.lib.extractor import ZipExtractor -from __builtin__ import file def folderSort(aKey): result = aKey[0] @@ -398,13 +398,15 @@ class XbmcBackup: dest.mkdir(dest.root_path + aFile[len(source.root_path) + 1:]) else: self._updateProgress() + wroteFile = True + destFile = dest.root_path + aFile[len(source.root_path):] if(isinstance(source,DropboxFileSystem) or isinstance(source,GoogleDriveFilesystem)): #if copying from cloud storage we need the file handle, use get_file - wroteFile = source.get_file(aFile,dest.root_path + aFile[len(source.root_path):]) + wroteFile = source.get_file(aFile,destFile) else: #copy using normal method - wroteFile = dest.put(aFile,dest.root_path + aFile[len(source.root_path):]) + wroteFile = dest.put(aFile,destFile) #if result is still true but this file failed if(not wroteFile and result): @@ -555,13 +557,13 @@ class FileManager: if(directory[-1:] == '/' or directory[-1:] == '\\'): directory = directory[:-1] - if(self.vfs.exists(directory + "/")): + if(self.vfs.exists(directory + os.path.sep)): dirs,files = self.vfs.listdir(directory) if(recurse): #create all the subdirs first for aDir in dirs: - dirPath = xbmc.validatePath(xbmc.translatePath(directory + "/" + aDir)) + dirPath = xbmc.validatePath(xbmc.translatePath(directory + os.path.sep + aDir)) file_ext = aDir.split('.')[-1] #check if directory is excluded @@ -581,7 +583,7 @@ class FileManager: #copy all the files for aFile in files: - filePath = xbmc.translatePath(directory + "/" + aFile) + filePath = xbmc.translatePath(directory + os.path.sep + aFile) self.addFile(filePath) def addDir(self,dirMeta): From a4bb3f3febae3cfb5de922ac28a183d0045ac809 Mon Sep 17 00:00:00 2001 From: Rob Weber Date: Wed, 11 Sep 2019 10:01:49 -0500 Subject: [PATCH 4/4] completely changed this class, default no longer matters. Just restore settings that differ from current, ignore default flags closes #154 --- resources/lib/backup.py | 2 +- resources/lib/guisettings.py | 76 +++++++++++++++++------------------- 2 files changed, 36 insertions(+), 42 deletions(-) diff --git a/resources/lib/backup.py b/resources/lib/backup.py index a1408dd..a2d190b 100644 --- a/resources/lib/backup.py +++ b/resources/lib/backup.py @@ -323,7 +323,7 @@ class XbmcBackup: #update the guisettings information (or what we can from it) - gui_settings = GuiSettingsManager('special://home/userdata/guisettings.xml') + gui_settings = GuiSettingsManager() gui_settings.run() #call update addons to refresh everything diff --git a/resources/lib/guisettings.py b/resources/lib/guisettings.py index b4e4c12..09aa8e1 100644 --- a/resources/lib/guisettings.py +++ b/resources/lib/guisettings.py @@ -6,49 +6,59 @@ import xbmc,xbmcvfs class GuiSettingsManager: - settingsFile = None doc = None - def __init__(self,settingsFile): - self._readFile(xbmc.translatePath(settingsFile)) + def __init__(self): + #first make a copy of the file + xbmcvfs.copy(xbmc.translatePath('special://home/userdata/guisettings.xml'), xbmc.translatePath("special://home/userdata/guisettings.xml.restored")) + + #read in the copy + self._readFile(xbmc.translatePath('special://home/userdata/guisettings.xml.restored')) def run(self): #get a list of all the settings we can manipulate via json json_response = json.loads(xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettings","params":{"level":"advanced"}}')) settings = json_response['result']['settings'] - settingsAllowed = [] + currentSettings = {} for aSetting in settings: - settingsAllowed.append(aSetting['id']) + if('value' in aSetting): + currentSettings[aSetting['id']] = aSetting['value'] - #parse the existing xml file and get all the settings we need to update - updateSettings = self.__parseNodes(self.doc.getElementsByTagName('setting')) + #parse the existing xml file and get all the settings we need to restore + restoreSettings = self.__parseNodes(self.doc.getElementsByTagName('setting')) + + #get a list where the restore setting value != the current value + updateSettings = {k: v for k, v in restoreSettings.items() if (k in currentSettings and currentSettings[k] != v)} #go through all the found settings and update them - for aSetting in updateSettings: - if(aSetting.name in settingsAllowed): - utils.log("updating: " + aSetting.name + ", value: " + aSetting.value) + jsonObj = {"jsonrpc":"2.0","id":1,"method":"Settings.SetSettingValue","params":{"setting":"","value":""}} + for anId, aValue in updateSettings.items(): + utils.log("updating: " + anId + ", value: " + str(aValue)) + + jsonObj['params']['setting'] = anId + jsonObj['params']['value'] = aValue - #check for boolean and numeric values - if(aSetting.value.isdigit() or (aSetting.value == 'true' or aSetting.value == 'false')): - xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.name + '","value":' + aSetting.value + '}}') - else: - xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.SetSettingValue","params":{"setting":"' + aSetting.name + '","value":"' + utils.encode(aSetting.value) + '"}}') - - #make a copy of the guisettings file to make user based restores easier - xbmcvfs.copy(self.settingsFile, xbmc.translatePath("special://home/userdata/guisettings.xml.restored")) + xbmc.executeJSONRPC(json.dumps(jsonObj)) def __parseNodes(self,nodeList): - result = [] + result = {} for node in nodeList: - #only add if it's not a default setting - if('default' not in node.attributes.keys()): - aSetting = SettingNode(node.getAttribute('id'),node.firstChild.nodeValue) - aSetting.isDefault = False - - result.append(aSetting) + nodeValue = '' + if(node.firstChild != None): + nodeValue = node.firstChild.nodeValue + + #check for numbers and booleans + if(nodeValue.isdigit()): + nodeValue = int(nodeValue) + elif(nodeValue == 'true'): + nodeValue = True + elif(nodeValue == 'false'): + nodeValue = False + + result[node.getAttribute('id')] = nodeValue return result @@ -57,23 +67,7 @@ class GuiSettingsManager: if(xbmcvfs.exists(fileLoc)): try: self.doc = minidom.parse(fileLoc) - self.settingsFile = fileLoc except ExpatError: utils.log("Can't read " + fileLoc) -class SettingNode: - name = '' - value = '' - isDefault = True - - def __init__(self,name,value): - self.name = name - self.value= value - - def __str__(self): - return "%s : %s" % (self.name,self.value) - - def __repr__(self): - return self.__str__() -