Merge branch 'master' into krypton

This commit is contained in:
Rob Weber 2019-09-11 10:05:16 -05:00
commit b21c11de26
4 changed files with 58 additions and 80 deletions

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.xbmcbackup" <addon id="script.xbmcbackup"
name="Backup" version="1.5.0" provider-name="robweber"> name="Backup" version="1.5.1" provider-name="robweber">
<requires> <requires>
<!-- jarvis --> <!-- jarvis -->
<import addon="xbmc.python" version="2.25.0"/> <import addon="xbmc.python" version="2.25.0"/>
@ -95,10 +95,8 @@
<screenshot>resources/images/screenshot3.png</screenshot> <screenshot>resources/images/screenshot3.png</screenshot>
<screenshot>resources/images/screenshot4.png</screenshot> <screenshot>resources/images/screenshot4.png</screenshot>
</assets> </assets>
<news>Version 1.1.4 <news>Version 1.5.1
- added file chunk support for dropbox uploads - fix guisettings restores not working - thanks Bluerayx
- fixed settings duplicate ids, thanks aster-anto
- added scheduler delay to assist with time sync (rpi mostly)
</news> </news>
</extension> </extension>
</addon> </addon>

View File

@ -1,3 +1,7 @@
Version 1.5.1
fix guisettings restores not working - thanks Bluerayx
Version 1.5.0 Version 1.5.0
Overhaul of file selection and restore procedures. Breaking Change with previous versions PR117 Overhaul of file selection and restore procedures. Breaking Change with previous versions PR117

View File

@ -4,12 +4,12 @@ import xbmcvfs
import utils as utils import utils as utils
import time import time
import json import json
import os
from datetime import datetime from datetime import datetime
from vfs import XBMCFileSystem,DropboxFileSystem,ZipFileSystem,GoogleDriveFilesystem from vfs import XBMCFileSystem,DropboxFileSystem,ZipFileSystem,GoogleDriveFilesystem
from progressbar import BackupProgressBar from progressbar import BackupProgressBar
from resources.lib.guisettings import GuiSettingsManager from resources.lib.guisettings import GuiSettingsManager
from resources.lib.extractor import ZipExtractor from resources.lib.extractor import ZipExtractor
from __builtin__ import file
def folderSort(aKey): def folderSort(aKey):
result = aKey[0] result = aKey[0]
@ -321,10 +321,10 @@ class XbmcBackup:
self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point)) self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point))
self.xbmc_vfs.rmdir(self.remote_vfs.root_path) 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) #update the guisettings information (or what we can from it)
gui_settings = GuiSettingsManager('special://home/userdata/guisettings.xml') gui_settings = GuiSettingsManager()
gui_settings.run() gui_settings.run()
#call update addons to refresh everything #call update addons to refresh everything
xbmc.executebuiltin('UpdateLocalAddons') xbmc.executebuiltin('UpdateLocalAddons')
@ -398,13 +398,15 @@ class XbmcBackup:
dest.mkdir(dest.root_path + aFile[len(source.root_path) + 1:]) dest.mkdir(dest.root_path + aFile[len(source.root_path) + 1:])
else: else:
self._updateProgress() self._updateProgress()
wroteFile = True wroteFile = True
destFile = dest.root_path + aFile[len(source.root_path):]
if(isinstance(source,DropboxFileSystem) or isinstance(source,GoogleDriveFilesystem)): if(isinstance(source,DropboxFileSystem) or isinstance(source,GoogleDriveFilesystem)):
#if copying from cloud storage we need the file handle, use get_file #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: else:
#copy using normal method #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 result is still true but this file failed
if(not wroteFile and result): if(not wroteFile and result):
@ -555,13 +557,13 @@ class FileManager:
if(directory[-1:] == '/' or directory[-1:] == '\\'): if(directory[-1:] == '/' or directory[-1:] == '\\'):
directory = directory[:-1] directory = directory[:-1]
if(self.vfs.exists(directory + "/")): if(self.vfs.exists(directory + os.path.sep)):
dirs,files = self.vfs.listdir(directory) dirs,files = self.vfs.listdir(directory)
if(recurse): if(recurse):
#create all the subdirs first #create all the subdirs first
for aDir in dirs: 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] file_ext = aDir.split('.')[-1]
#check if directory is excluded #check if directory is excluded
@ -581,7 +583,7 @@ class FileManager:
#copy all the files #copy all the files
for aFile in files: for aFile in files:
filePath = xbmc.translatePath(directory + "/" + aFile) filePath = xbmc.translatePath(directory + os.path.sep + aFile)
self.addFile(filePath) self.addFile(filePath)
def addDir(self,dirMeta): def addDir(self,dirMeta):

View File

@ -6,94 +6,68 @@ import xbmc,xbmcvfs
class GuiSettingsManager: class GuiSettingsManager:
settingsFile = None
doc = None doc = None
settings_allowed = list()
found_settings = list()
def __init__(self,settingsFile): def __init__(self):
self._readFile(xbmc.translatePath(settingsFile)) #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): def run(self):
#get a list of all the settings we can manipulate via json #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"}}')) json_response = json.loads(xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettings","params":{"level":"advanced"}}'))
settings = json_response['result']['settings'] settings = json_response['result']['settings']
currentSettings = {}
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)
for aNode in root_nodes: for aSetting in settings:
secondary_list = self.__parseNodes(self.doc.getElementsByTagName(aNode.name)[0]) if('value' in aSetting):
currentSettings[aSetting['id']] = aSetting['value']
for secondNode in secondary_list: #parse the existing xml file and get all the settings we need to restore
#if the node does not have children and is not default restoreSettings = self.__parseNodes(self.doc.getElementsByTagName('setting'))
if(not secondNode.hasChildren and not secondNode.isDefault):
#get a list where the restore setting value != the current value
if(secondNode.json_name() in self.settings_allowed): updateSettings = {k: v for k, v in restoreSettings.items() if (k in currentSettings and currentSettings[k] != v)}
self.found_settings.append(secondNode)
#go through all the found settings and update them #go through all the found settings and update them
for aSetting in self.found_settings: jsonObj = {"jsonrpc":"2.0","id":1,"method":"Settings.SetSettingValue","params":{"setting":"","value":""}}
utils.log("updating: " + aSetting.json_name() + ", value: " + aSetting.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 xbmc.executeJSONRPC(json.dumps(jsonObj))
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) + '"}}')
#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"))
def __parseNodes(self,nodeList): def __parseNodes(self,nodeList):
result = [] result = {}
for node in nodeList.childNodes: for node in nodeList:
if(node.nodeType == self.doc.ELEMENT_NODE): nodeValue = ''
aSetting = SettingNode(node.nodeName) if(node.firstChild != None):
nodeValue = node.firstChild.nodeValue
#detect if there are any element nodes
if(len(node.childNodes) > 0): #check for numbers and booleans
for child_node in node.childNodes: if(nodeValue.isdigit()):
if(child_node.nodeType == self.doc.ELEMENT_NODE): nodeValue = int(nodeValue)
aSetting.hasChildren = True elif(nodeValue == 'true'):
nodeValue = True
if(not aSetting.hasChildren and len(node.childNodes) > 0): elif(nodeValue == 'false'):
aSetting.value = node.firstChild.nodeValue nodeValue = False
if('default' not in node.attributes.keys()): result[node.getAttribute('id')] = nodeValue
aSetting.isDefault = False
aSetting.parent = node.parentNode.nodeName
result.append(aSetting)
return result return result
def _readFile(self,fileLoc): def _readFile(self,fileLoc):
if(xbmcvfs.exists(fileLoc)): if(xbmcvfs.exists(fileLoc)):
try: try:
self.doc = minidom.parse(fileLoc) self.doc = minidom.parse(fileLoc)
self.settingsFile = fileLoc
except ExpatError: except ExpatError:
utils.log("Can't read " + fileLoc) utils.log("Can't read " + fileLoc)
class SettingNode:
name = ''
value = ''
hasChildren = False
isDefault = True
parent = ''
def __init__(self,name):
self.name = name
def json_name(self):
return self.parent + "." + self.name