import json import xbmc import xbmcgui import xbmcvfs from . import utils as utils class BackupSetManager: jsonFile = xbmc.translatePath(utils.data_dir() + "custom_paths.json") paths = None def __init__(self): self.paths = {} # try and read in the custom file self._readFile() def addSet(self, aSet): self.paths[aSet['name']] = {'root': aSet['root'], 'dirs': [{"type": "include", "path": aSet['root'], 'recurse': True}]} # save the file self._writeFile() def updateSet(self, name, aSet): self.paths[name] = aSet # save the file self._writeFile() def deleteSet(self, index): # match the index to a key keys = self.getSets() # delete this set del self.paths[keys[index]] # save the file self._writeFile() def getSets(self): # list all current sets by name keys = list(self.paths.keys()) keys.sort() return keys def getSet(self, index): keys = self.getSets() # return the set at this index return {'name': keys[index], 'set': self.paths[keys[index]]} def validateSetName(self, name): return (name not in self.getSets()) def _writeFile(self): # create the custom file aFile = xbmcvfs.File(self.jsonFile, 'w') aFile.write(json.dumps(self.paths)) aFile.close() def _readFile(self): if(xbmcvfs.exists(self.jsonFile)): # read in the custom file aFile = xbmcvfs.File(self.jsonFile) # load custom dirs self.paths = json.loads(aFile.read()) aFile.close() else: # write a blank file self._writeFile() class AdvancedBackupEditor: dialog = None def __init__(self): self.dialog = xbmcgui.Dialog() def _cleanPath(self, root, path): return path[len(root) - 1:] def _validatePath(self, root, path): return path.startswith(root) def createSet(self): backupSet = None name = self.dialog.input(utils.getString(30110), defaultt='Backup Set') if(name is not None): # give a choice to start in home or enter a root path enterHome = self.dialog.yesno(utils.getString(30111), line1=utils.getString(30112) + " - " + utils.getString(30114), line2=utils.getString(30113) + " - " + utils.getString(30115), nolabel=utils.getString(30112), yeslabel=utils.getString(30113)) rootFolder = 'special://home' if(enterHome): rootFolder = self.dialog.input(utils.getString(30116), defaultt=rootFolder) # direcotry has to end in slash if(rootFolder[:-1] != '/'): rootFolder = rootFolder + '/' # check that this path even exists if(not xbmcvfs.exists(xbmc.translatePath(rootFolder))): self.dialog.ok(utils.getString(30117), utils.getString(30118), rootFolder) return None else: # select path to start set rootFolder = self.dialog.browse(type=0, heading=utils.getString(30119), shares='files', defaultt=rootFolder) backupSet = {'name': name, 'root': rootFolder} return backupSet def editSet(self, name, backupSet): optionSelected = '' rootPath = backupSet['root'] utils.log(rootPath) while(optionSelected != -1): options = [xbmcgui.ListItem(utils.getString(30120), "Exclude a specific folder from this backup set"), xbmcgui.ListItem(utils.getString(30135), "Include a specific folder to this backup set"), xbmcgui.ListItem(rootPath, utils.getString(30121))] for aDir in backupSet['dirs']: if(aDir['type'] == 'exclude'): options.append(xbmcgui.ListItem(self._cleanPath(rootPath, aDir['path']), "%s: %s" % ("Type", utils.getString(30129)))) elif(aDir['type'] == 'include'): options.append(xbmcgui.ListItem(self._cleanPath(rootPath, aDir['path']), "%s: %s | %s: %s" % ("Type", utils.getString(30134), "Include Sub Folders", str(aDir['recurse'])))) optionSelected = self.dialog.select(utils.getString(30122) + ' ' + name, options, useDetails=True) if(optionSelected == 0 or optionSelected == 1): # add a folder, will equal root if cancel is hit addFolder = self.dialog.browse(type=0, heading=utils.getString(30120), shares='files', defaultt=backupSet['root']) if(addFolder.startswith(rootPath)): if(not any(addFolder == aDir['path'] for aDir in backupSet['dirs'])): # cannot add root as an exclusion if(optionSelected == 0 and addFolder != backupSet['root']): backupSet['dirs'].append({"path": addFolder, "type": "exclude"}) elif(optionSelected == 1): # can add root as inclusion backupSet['dirs'].append({"path": addFolder, "type": "include", "recurse": True}) else: # this path is already part of another include/exclude rule self.dialog.ok(utils.getString(30117), utils.getString(30137), addFolder) else: # folder must be under root folder self.dialog.ok(utils.getString(30117), utils.getString(30136), rootPath) elif(optionSelected == 2): self.dialog.ok(utils.getString(30121), utils.getString(30130), backupSet['root']) elif(optionSelected > 2): cOptions = ['Delete'] if(backupSet['dirs'][optionSelected - 3]['type'] == 'include'): cOptions.append('Toggle Sub Folders') contextOption = self.dialog.contextmenu(cOptions) if(contextOption == 0): if(self.dialog.yesno(heading=utils.getString(30123), line1=utils.getString(30128))): # remove folder del backupSet['dirs'][optionSelected - 3] elif(contextOption == 1 and backupSet['dirs'][optionSelected - 3]['type'] == 'include'): # toggle if this folder should be recursive backupSet['dirs'][optionSelected - 3]['recurse'] = not backupSet['dirs'][optionSelected - 3]['recurse'] return backupSet def showMainScreen(self): exitCondition = "" customPaths = BackupSetManager() # show this every time self.dialog.ok(utils.getString(30036), utils.getString(30037)) while(exitCondition != -1): # load the custom paths options = [xbmcgui.ListItem(utils.getString(30126), '', utils.addon_dir() + '/resources/images/plus-icon.png')] for index in range(0, len(customPaths.getSets())): aSet = customPaths.getSet(index) options.append(xbmcgui.ListItem(aSet['name'], utils.getString(30121) + ': ' + aSet['set']['root'], utils.addon_dir() + '/resources/images/folder-icon.png')) # show the gui exitCondition = self.dialog.select(utils.getString(30125), options, useDetails=True) if(exitCondition >= 0): if(exitCondition == 0): newSet = self.createSet() # check that the name is unique if(customPaths.validateSetName(newSet['name'])): customPaths.addSet(newSet) else: self.dialog.ok(utils.getString(30117), utils.getString(30138), newSet['name']) else: # bring up a context menu menuOption = self.dialog.contextmenu([utils.getString(30122), utils.getString(30123)]) if(menuOption == 0): # get the set aSet = customPaths.getSet(exitCondition - 1) # edit the set updatedSet = self.editSet(aSet['name'], aSet['set']) # save it customPaths.updateSet(aSet['name'], updatedSet) elif(menuOption == 1): if(self.dialog.yesno(heading=utils.getString(30127), line1=utils.getString(30128))): # delete this path - subtract one because of "add" item customPaths.deleteSet(exitCondition - 1) def copySimpleConfig(self): # disclaimer in case the user hit this on accident shouldContinue = self.dialog.yesno(utils.getString(30139), utils.getString(30140), utils.getString(30141)) if(shouldContinue): source = xbmc.translatePath(utils.addon_dir() + "/resources/data/default_files.json") dest = xbmc.translatePath(utils.data_dir() + "/custom_paths.json") xbmcvfs.copy(source, dest)