mirror of
				https://github.com/robweber/xbmcbackup.git
				synced 2025-10-31 09:31:02 +01:00 
			
		
		
		
	Merge branch 'master' into leia
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| <?xml version="1.0" encoding="UTF-8" standalone="yes"?> | ||||
| <addon id="script.xbmcbackup" | ||||
|     name="Backup" version="1.5.1~beta1" provider-name="robweber"> | ||||
|     name="Backup" version="1.6.0~beta1" provider-name="robweber"> | ||||
|   <requires> | ||||
|     <import addon="xbmc.python" version="2.26.0"/> | ||||
|     <import addon="script.module.kodi-six" version="0.1.0"/> | ||||
| @@ -92,10 +92,8 @@ | ||||
| 		<screenshot>resources/images/screenshot3.png</screenshot> | ||||
| 		<screenshot>resources/images/screenshot4.png</screenshot> | ||||
|     </assets> | ||||
|     <news>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) | ||||
|     <news>Version 1.5.1 | ||||
| - fix guisettings restores not working - thanks Bluerayx | ||||
|    	</news> | ||||
|   </extension> | ||||
| </addon> | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 125 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 129 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 270 KiB | 
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 150 KiB | 
| @@ -3,6 +3,7 @@ import time | ||||
| import json | ||||
| from kodi_six import xbmc, xbmcgui, xbmcvfs | ||||
| from . import utils as utils | ||||
| import os | ||||
| from datetime import datetime | ||||
| from . vfs import XBMCFileSystem,DropboxFileSystem,ZipFileSystem | ||||
| from . progressbar import BackupProgressBar | ||||
| @@ -316,10 +317,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() | ||||
|             gui_settings.run() | ||||
|  | ||||
|             #call update addons to refresh everything | ||||
|             xbmc.executebuiltin('UpdateLocalAddons') | ||||
| @@ -393,13 +394,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)): | ||||
|                         #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): | ||||
| @@ -550,13 +553,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 | ||||
| @@ -576,7 +579,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): | ||||
|   | ||||
| @@ -6,94 +6,68 @@ from xml.parsers.expat import ExpatError | ||||
|  | ||||
|  | ||||
| class GuiSettingsManager: | ||||
|     settingsFile = None | ||||
|     doc = None | ||||
|     settings_allowed = list() | ||||
|     found_settings = list() | ||||
|      | ||||
|     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'] | ||||
|             | ||||
|         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) | ||||
|         currentSettings = {} | ||||
|          | ||||
|         for aNode in root_nodes: | ||||
|             secondary_list = self.__parseNodes(self.doc.getElementsByTagName(aNode.name)[0]) | ||||
|         for aSetting in settings: | ||||
|             if('value' in aSetting): | ||||
|                 currentSettings[aSetting['id']] = aSetting['value'] | ||||
|              | ||||
|             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 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 self.found_settings: | ||||
|             utils.log("updating: " + aSetting.json_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.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")) | ||||
|             xbmc.executeJSONRPC(json.dumps(jsonObj)) | ||||
|              | ||||
|     def __parseNodes(self,nodeList): | ||||
|         result = [] | ||||
|         result = {} | ||||
|  | ||||
|         for node in nodeList.childNodes: | ||||
|             if(node.nodeType == self.doc.ELEMENT_NODE): | ||||
|                 aSetting = SettingNode(node.nodeName) | ||||
|  | ||||
|                 #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) | ||||
|         for node in nodeList: | ||||
|             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 | ||||
|      | ||||
|      | ||||
|     def _readFile(self,fileLoc): | ||||
|          | ||||
|         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 = '' | ||||
|     hasChildren = False | ||||
|     isDefault = True | ||||
|     parent = '' | ||||
|      | ||||
|     def __init__(self,name): | ||||
|         self.name = name | ||||
|          | ||||
|     def json_name(self): | ||||
|         return self.parent + "." + self.name | ||||
|                  | ||||
|          | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Rob Weber
					Rob Weber