diff --git a/default.py b/default.py index 54c9d61..1ecd1d7 100644 --- a/default.py +++ b/default.py @@ -10,7 +10,7 @@ def get_params(): args = i if('=' in args): if(args.startswith('?')): - args = args[1:] #legacy in case of url params + args = args[1:] # legacy in case of url params splitString = args.split('=') param[splitString[0]] = splitString[1] except: @@ -18,7 +18,7 @@ def get_params(): return param -#the program mode +# the program mode mode = -1 params = get_params() @@ -29,33 +29,33 @@ if("mode" in params): elif(params['mode'] == 'restore'): mode = 1 -#if mode wasn't passed in as arg, get from user +# if mode wasn't passed in as arg, get from user if(mode == -1): - #by default, Backup,Restore,Open Settings + # by default, Backup,Restore,Open Settings options = [utils.getString(30016),utils.getString(30017),utils.getString(30099)] - #find out if we're using the advanced editor + # find out if we're using the advanced editor if(int(utils.getSetting('backup_selection_type')) == 1): options.append(utils.getString(30125)) - #figure out if this is a backup or a restore from the user + # figure out if this is a backup or a restore from the user mode = xbmcgui.Dialog().select(utils.getString(30010) + " - " + utils.getString(30023),options) -#check if program should be run +# check if program should be run if(mode != -1): - #run the profile backup + # run the profile backup backup = XbmcBackup() if(mode == 2): - #open the settings dialog + # open the settings dialog utils.openSettings() elif(mode == 3 and int(utils.getSetting('backup_selection_type')) == 1): - #open the advanced editor + # open the advanced editor xbmc.executebuiltin('RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=advanced_editor)') elif(backup.remoteConfigured()): if(mode == backup.Restore): - #get list of valid restore points + # get list of valid restore points restorePoints = backup.listBackups() pointNames = [] folderNames = [] @@ -67,16 +67,16 @@ if(mode != -1): selectedRestore = -1 if("archive" in params): - #check that the user give archive exists + # check that the user give archive exists if(params['archive'] in folderNames): - #set the index + # set the index selectedRestore = folderNames.index(params['archive']) utils.log(str(selectedRestore) + " : " + params['archive']) else: utils.showNotification(utils.getString(30045)) utils.log(params['archive'] + ' is not a valid restore point') else: - #allow user to select the backup to restore from + # allow user to select the backup to restore from selectedRestore = xbmcgui.Dialog().select(utils.getString(30010) + " - " + utils.getString(30021),pointNames) if(selectedRestore != -1): @@ -89,6 +89,6 @@ if(mode != -1): else: backup.backup() else: - #can't go any further + # can't go any further xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045)) utils.openSettings() diff --git a/launcher.py b/launcher.py index 54f09a4..9450c2d 100644 --- a/launcher.py +++ b/launcher.py @@ -5,10 +5,10 @@ from resources.lib.authorizers import DropboxAuthorizer from resources.lib.advanced_editor import AdvancedBackupEditor -#launcher for various helpful functions found in the settings.xml area +# launcher for various helpful functions found in the settings.xml area def authorize_cloud(cloudProvider): - #drobpox + # drobpox if(cloudProvider == 'dropbox'): authorizer = DropboxAuthorizer() @@ -18,13 +18,13 @@ def authorize_cloud(cloudProvider): xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30107) + ' ' + utils.getString(30027)) def remove_auth(): - #triggered from settings.xml - asks if user wants to delete OAuth token information + # triggered from settings.xml - asks if user wants to delete OAuth token information shouldDelete = xbmcgui.Dialog().yesno(utils.getString(30093),utils.getString(30094),utils.getString(30095),autoclose=7000) if(shouldDelete): - #delete any of the known token file types - xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "tokens.txt")) #dropbox - xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "google_drive.dat")) #google drive + # delete any of the known token file types + xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "tokens.txt")) # dropbox + xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "google_drive.dat")) # google drive def get_params(): param = {} @@ -33,7 +33,7 @@ def get_params(): args = i if('=' in args): if(args.startswith('?')): - args = args[1:] #legacy in case of url params + args = args[1:] # legacy in case of url params splitString = args.split('=') param[splitString[0]] = splitString[1] except: diff --git a/resources/lib/advanced_editor.py b/resources/lib/advanced_editor.py index 1aa1fda..f14d790 100644 --- a/resources/lib/advanced_editor.py +++ b/resources/lib/advanced_editor.py @@ -9,33 +9,33 @@ class BackupSetManager: def __init__(self): self.paths = {} - #try and read in the custom file + # 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 + # save the file self._writeFile() def updateSet(self,name,aSet): self.paths[name] = aSet - #save the file + # save the file self._writeFile() def deleteSet(self,index): - #match the index to a key + # match the index to a key keys = self.getSets() - #delete this set + # delete this set del self.paths[keys[index]] #save the file self._writeFile() def getSets(self): - #list all current sets by name + # list all current sets by name keys = list(self.paths.keys()) keys.sort() @@ -44,14 +44,14 @@ class BackupSetManager: def getSet(self,index): keys = self.getSets(); - #return the set at this index + # 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 + # create the custom file aFile = xbmcvfs.File(self.jsonFile,'w') aFile.write(json.dumps(self.paths)) aFile.close() @@ -60,14 +60,14 @@ class BackupSetManager: if(xbmcvfs.exists(self.jsonFile)): - #read in the custom file + # read in the custom file aFile = xbmcvfs.File(self.jsonFile) - #load custom dirs + # load custom dirs self.paths = json.loads(aFile.read()) aFile.close() else: - #write a blank file + # write a blank file self._writeFile() class AdvancedBackupEditor: @@ -89,23 +89,23 @@ class AdvancedBackupEditor: if(name != None): - #give a choice to start in home or enter a root path + # 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 + # direcotry has to end in slash if(rootFolder[:-1] != '/'): rootFolder = rootFolder + '/' - #check that this path even exists + # 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 + # select path to start set rootFolder = self.dialog.browse(type=0,heading=utils.getString(30119),shares='files',defaultt=rootFolder) backupSet = {'name':name,'root':rootFolder} @@ -128,23 +128,23 @@ class AdvancedBackupEditor: 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 + # 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 + # 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 + # 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 + # 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 + # 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']) @@ -158,10 +158,10 @@ class AdvancedBackupEditor: if(contextOption == 0): if(self.dialog.yesno(heading=utils.getString(30123),line1=utils.getString(30128))): - #remove folder + # remove folder del backupSet['dirs'][optionSelected - 3] elif(contextOption == 1 and backupSet['dirs'][optionSelected - 3]['type'] == 'include'): - #toggle if this folder should be recursive + # toggle if this folder should be recursive backupSet['dirs'][optionSelected - 3]['recurse'] = not backupSet['dirs'][optionSelected - 3]['recurse'] return backupSet @@ -171,50 +171,50 @@ class AdvancedBackupEditor: exitCondition = "" customPaths = BackupSetManager() - #show this every time + # show this every time self.dialog.ok(utils.getString(30036),utils.getString(30037)) while(exitCondition != -1): - #load the custom paths + # 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 + # 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 + # 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 + # bring up a context menu menuOption = self.dialog.contextmenu([utils.getString(30122),utils.getString(30123)]) if(menuOption == 0): - #get the set + # get the set aSet = customPaths.getSet(exitCondition -1) - #edit the set + # edit the set updatedSet = self.editSet(aSet['name'],aSet['set']) - #save it + # 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 + # 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 + # disclaimer in case the user hit this on accident shouldContinue = self.dialog.yesno(utils.getString(30139),utils.getString(30140),utils.getString(30141)) if(shouldContinue): diff --git a/resources/lib/authorizers.py b/resources/lib/authorizers.py index b548007..588c5bf 100644 --- a/resources/lib/authorizers.py +++ b/resources/lib/authorizers.py @@ -2,7 +2,7 @@ import xbmc, xbmcgui, xbmcvfs import resources.lib.tinyurl as tinyurl import resources.lib.utils as utils -#don't die on import error yet, these might not even get used +# don't die on import error yet, these might not even get used try: from . import dropbox except ImportError: @@ -20,7 +20,7 @@ class DropboxAuthorizer: result = True if(self.APP_KEY == '' and self.APP_SECRET == ''): - #we can't go any farther, need these for sure + # we can't go any farther, need these for sure xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30027) + ' ' + utils.getString(30058),utils.getString(30059)) result = False @@ -39,19 +39,19 @@ class DropboxAuthorizer: return False if(self.isAuthorized()): - #delete the token to start over + # delete the token to start over self._deleteToken() - #copied flow from http://dropbox-sdk-python.readthedocs.io/en/latest/moduledoc.html#dropbox.oauth.DropboxOAuth2FlowNoRedirect + # copied flow from http://dropbox-sdk-python.readthedocs.io/en/latest/moduledoc.html#dropbox.oauth.DropboxOAuth2FlowNoRedirect flow = dropbox.oauth.DropboxOAuth2FlowNoRedirect(self.APP_KEY,self.APP_SECRET) url = flow.start() - #print url in log + # print url in log utils.log("Authorize URL: " + url) xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30056),utils.getString(30057),tinyurl.shorten(url)) - #get the auth code + # get the auth code code = xbmcgui.Dialog().input(utils.getString(30027) + ' ' + utils.getString(30103)) #if user authorized this will work @@ -65,7 +65,7 @@ class DropboxAuthorizer: return result; - #return the DropboxClient, or None if can't be created + # return the DropboxClient, or None if can't be created def getClient(self): result = None @@ -85,13 +85,13 @@ class DropboxAuthorizer: return result def _setToken(self,token): - #write the token files + # write the token files token_file = open(xbmc.translatePath(utils.data_dir() + "tokens.txt"),'w') token_file.write(token) token_file.close() def _getToken(self): - #get token, if it exists + # get token, if it exists if(xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + "tokens.txt"))): token_file = open(xbmc.translatePath(utils.data_dir() + "tokens.txt")) token = token_file.read() diff --git a/resources/lib/backup.py b/resources/lib/backup.py index 3e6a89c..e2770dd 100644 --- a/resources/lib/backup.py +++ b/resources/lib/backup.py @@ -19,14 +19,14 @@ def folderSort(aKey): class XbmcBackup: - #constants for initiating a back or restore + # constants for initiating a back or restore Backup = 0 Restore = 1 - #list of dirs for the "simple" file selection + # list of dirs for the "simple" file selection simple_directory_list = ['addons','addon_data','database','game_saves','playlists','profiles','thumbnails','config'] - #file systems + # file systems xbmc_vfs = None remote_vfs = None saved_remote_vfs = None @@ -34,13 +34,13 @@ class XbmcBackup: restoreFile = None remote_base_path = None - #for the progress bar + # for the progress bar progressBar = None filesLeft = 0 filesTotal = 1 restore_point = None - skip_advanced = False #if we should check for the existance of advancedsettings in the restore + skip_advanced = False # if we should check for the existance of advancedsettings in the restore def __init__(self): self.xbmc_vfs = XBMCFileSystem(xbmc.translatePath('special://home')) @@ -68,17 +68,17 @@ class XbmcBackup: return result - #reverse - should reverse the resulting, default is true - newest to oldest - def listBackups(self,reverse=True): + # reverse - should reverse the resulting, default is true - newest to oldest + def listBackups(self, reverse=True): result = [] - #get all the folders in the current root path + # get all the folders in the current root path dirs,files = self.remote_vfs.listdir(self.remote_base_path) for aDir in dirs: if(self.remote_vfs.exists(self.remote_base_path + aDir + "/xbmcbackup.val")): - #format the name according to regional settings + # format the name according to regional settings folderName = self._dateFormat(aDir) result.append((aDir,folderName)) @@ -89,33 +89,33 @@ class XbmcBackup: if(file_ext == 'zip' and len(folderName) == 12 and folderName.isdigit()): - #format the name according to regional settings + # format the name according to regional settings folderName = self._dateFormat(folderName) - result.append((aFile ,folderName)) + result.append((aFile, folderName)) result.sort(key=folderSort,reverse=reverse) return result - def selectRestore(self,restore_point): + def selectRestore(self, restore_point): self.restore_point = restore_point def skipAdvanced(self): self.skip_advanced = True - def backup(self,progressOverride=False): - shouldContinue = self._setupVFS(self.Backup,progressOverride) + def backup(self, progressOverride=False): + shouldContinue = self._setupVFS(self.Backup, progressOverride) if(shouldContinue): utils.log(utils.getString(30023) + " - " + utils.getString(30016)) - #check if remote path exists + # check if remote path exists if(self.remote_vfs.exists(self.remote_vfs.root_path)): - #may be data in here already + # may be data in here already utils.log(utils.getString(30050)) else: - #make the remote directory + # make the remote directory self.remote_vfs.mkdir(self.remote_vfs.root_path) utils.log(utils.getString(30051)) @@ -123,35 +123,35 @@ class XbmcBackup: allFiles = [] if(int(utils.getSetting('backup_selection_type')) == 0): - #read in a list of the directories to backup + # read in a list of the directories to backup selectedDirs = self._readBackupConfig(utils.addon_dir() + "/resources/data/default_files.json") - #simple mode - get file listings for all enabled directories + # simple mode - get file listings for all enabled directories for aDir in self.simple_directory_list: - #if this dir enabled + # if this dir enabled if(utils.getSetting('backup_' + aDir) == 'true'): - #get a file listing and append it to the allfiles array + # get a file listing and append it to the allfiles array allFiles.append(self._addBackupDir(aDir,selectedDirs[aDir]['root'],selectedDirs[aDir]['dirs'])) else: - #advanced mode - load custom paths + # advanced mode - load custom paths selectedDirs = self._readBackupConfig(utils.data_dir() + "/custom_paths.json") - #get the set names + # get the set names keys = list(selectedDirs.keys()) - #go through the custom sets + # go through the custom sets for aKey in keys: - #get the set + # get the set aSet = selectedDirs[aKey] - #get file listing and append + # get file listing and append allFiles.append(self._addBackupDir(aKey,aSet['root'],aSet['dirs'])) - #create a validation file for backup rotation + # create a validation file for backup rotation writeCheck = self._createValidationFile(allFiles) if(not writeCheck): - #we may not be able to write to this destination for some reason + # we may not be able to write to this destination for some reason shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30089),utils.getString(30090), utils.getString(30044),autoclose=25000) if(not shouldContinue): @@ -159,7 +159,7 @@ class XbmcBackup: orig_base_path = self.remote_vfs.root_path - #backup all the files + # backup all the files self.filesLeft = self.filesTotal for fileGroup in allFiles: self.xbmc_vfs.set_root(xbmc.translatePath(fileGroup['source'])) @@ -170,20 +170,20 @@ class XbmcBackup: utils.showNotification(utils.getString(30092)) utils.log(utils.getString(30092)) - #reset remote and xbmc vfs + # reset remote and xbmc vfs self.xbmc_vfs.set_root("special://home/") self.remote_vfs.set_root(orig_base_path) if(utils.getSetting("compress_backups") == 'true'): fileManager = FileManager(self.xbmc_vfs) - #send the zip file to the real remote vfs + # send the zip file to the real remote vfs zip_name = self.remote_vfs.root_path[:-1] + ".zip" self.remote_vfs.cleanup() self.xbmc_vfs.rename(xbmc.translatePath("special://temp/xbmc_backup_temp.zip"), xbmc.translatePath("special://temp/" + zip_name)) fileManager.addFile(xbmc.translatePath("special://temp/" + zip_name)) - #set root to data dir home + # set root to data dir home self.xbmc_vfs.set_root(xbmc.translatePath("special://temp/")) self.remote_vfs = self.saved_remote_vfs @@ -191,16 +191,16 @@ class XbmcBackup: fileCopied = self._copyFiles(fileManager.getFiles(),self.xbmc_vfs, self.remote_vfs) if(not fileCopied): - #zip archive copy filed, inform the user + # zip archive copy filed, inform the user shouldContinue = xbmcgui.Dialog().ok(utils.getString(30089),utils.getString(30090), utils.getString(30091)) - #delete the temp zip file + # delete the temp zip file self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + zip_name)) - #remove old backups + # remove old backups self._rotateBackups() - #close any files + # close any files self._closeVFS() def restore(self,progressOverride=False,selectedSets=None): @@ -209,16 +209,16 @@ class XbmcBackup: if(shouldContinue): utils.log(utils.getString(30023) + " - " + utils.getString(30017)) - #catch for if the restore point is actually a zip file + # catch for if the restore point is actually a zip file if(self.restore_point.split('.')[-1] == 'zip'): self.progressBar.updateProgress(2, utils.getString(30088)) utils.log("copying zip file: " + self.restore_point) - #set root to data dir home + # set root to data dir home self.xbmc_vfs.set_root(xbmc.translatePath("special://temp/")) if(not self.xbmc_vfs.exists(xbmc.translatePath("special://temp/" + self.restore_point))): - #copy just this file from the remote vfs + # copy just this file from the remote vfs zipFile = [] zipFile.append(self.remote_base_path + self.restore_point) @@ -226,12 +226,12 @@ class XbmcBackup: else: utils.log("zip file exists already") - #extract the zip file + # extract the zip file zip_vfs = ZipFileSystem(xbmc.translatePath("special://temp/"+ self.restore_point),'r') extractor = ZipExtractor() if(not extractor.extract(zip_vfs, xbmc.translatePath("special://temp/"), self.progressBar)): - #we had a problem extracting the archive, delete everything + # we had a problem extracting the archive, delete everything zip_vfs.cleanup() self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point)) @@ -241,60 +241,60 @@ class XbmcBackup: zip_vfs.cleanup() self.progressBar.updateProgress(0,utils.getString(30049) + "......") - #set the new remote vfs and fix xbmc path + # set the new remote vfs and fix xbmc path self.remote_vfs = XBMCFileSystem(xbmc.translatePath("special://temp/" + self.restore_point.split(".")[0] + "/")) self.xbmc_vfs.set_root(xbmc.translatePath("special://home/")) - #for restores remote path must exist + # for restores remote path must exist if(not self.remote_vfs.exists(self.remote_vfs.root_path)): xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045),self.remote_vfs.root_path) return valFile = self._checkValidationFile(self.remote_vfs.root_path) if(valFile == None): - #don't continue + # don't continue return utils.log(utils.getString(30051)) allFiles = [] fileManager = FileManager(self.remote_vfs) - #check for the existance of an advancedsettings file + # check for the existance of an advancedsettings file if(self.remote_vfs.exists(self.remote_vfs.root_path + "config/advancedsettings.xml") and not self.skip_advanced): - #let the user know there is an advanced settings file present + # let the user know there is an advanced settings file present restartXbmc = xbmcgui.Dialog().yesno(utils.getString(30038),utils.getString(30039),utils.getString(30040), utils.getString(30041)) if(restartXbmc): - #add only this file to the file list + # add only this file to the file list fileManager.addFile(self.remote_vfs.root_path + "config/advancedsettings.xml") self._copyFiles(fileManager.getFiles(),self.remote_vfs,self.xbmc_vfs) - #let the service know to resume this backup on startup + # let the service know to resume this backup on startup self._createResumeBackupFile() - #do not continue running + # do not continue running xbmcgui.Dialog().ok(utils.getString(30077),utils.getString(30078)) return - #use a multiselect dialog to select sets to restore + # use a multiselect dialog to select sets to restore restoreSets = [n['name'] for n in valFile['directories']] - #if passed in list, skip selection + # if passed in list, skip selection if(selectedSets == None): selectedSets = xbmcgui.Dialog().multiselect(utils.getString(30131),restoreSets) else: - selectedSets = [restoreSets.index(n) for n in selectedSets if n in restoreSets] #if set name not found just skip it + selectedSets = [restoreSets.index(n) for n in selectedSets if n in restoreSets] # if set name not found just skip it if(selectedSets != None): - #go through each of the directories in the backup and write them to the correct location + # go through each of the directories in the backup and write them to the correct location for index in selectedSets: - #add this directory + # add this directory aDir = valFile['directories'][index] self.xbmc_vfs.set_root(xbmc.translatePath(aDir['path'])) if(self.remote_vfs.exists(self.remote_vfs.root_path + aDir['name'] + '/')): - #walk the directory + # walk the directory fileManager.walkTree(self.remote_vfs.root_path + aDir['name'] + '/') self.filesTotal = self.filesTotal + fileManager.size() allFiles.append({"source":self.remote_vfs.root_path + aDir['name'],"dest":self.xbmc_vfs.root_path,"files":fileManager.getFiles()}) @@ -302,7 +302,7 @@ class XbmcBackup: utils.log("error path not found: " + self.remote_vfs.root_path + aDir['name']) xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045),self.remote_vfs.root_path + aDir['name']) - #restore all the files + # restore all the files self.filesLeft = self.filesTotal for fileGroup in allFiles: self.remote_vfs.set_root(fileGroup['source']) @@ -312,35 +312,35 @@ class XbmcBackup: self.progressBar.updateProgress(99,"Clean up operations .....") if(self.restore_point.split('.')[-1] == 'zip'): - #delete the zip file and the extracted directory + # delete the zip file and the extracted directory self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point)) self.xbmc_vfs.rmdir(self.remote_vfs.root_path) - #update the guisettings information (or what we can from it) + # update the guisettings information (or what we can from it) gui_settings = GuiSettingsManager() gui_settings.run() - #call update addons to refresh everything + # call update addons to refresh everything xbmc.executebuiltin('UpdateLocalAddons') def _setupVFS(self,mode=-1,progressOverride=False): - #set windows setting to true + # set windows setting to true window = xbmcgui.Window(10000) window.setProperty(utils.__addon_id__ + ".running","true") - #append backup folder name + # append backup folder name progressBarTitle = utils.getString(30010) + " - " if(mode == self.Backup and self.remote_vfs.root_path != ''): if(utils.getSetting("compress_backups") == 'true'): - #delete old temp file + # delete old temp file if(self.xbmc_vfs.exists(xbmc.translatePath('special://temp/xbmc_backup_temp.zip'))): if(not self.xbmc_vfs.rmfile(xbmc.translatePath('special://temp/xbmc_backup_temp.zip'))): - #we had some kind of error deleting the old file + # we had some kind of error deleting the old file xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30096),utils.getString(30097)) return False - #save the remote file system and use the zip vfs + # save the remote file system and use the zip vfs self.saved_remote_vfs = self.remote_vfs self.remote_vfs = ZipFileSystem(xbmc.translatePath("special://temp/xbmc_backup_temp.zip"),"w") @@ -351,7 +351,7 @@ class XbmcBackup: self.remote_vfs.set_root(self.remote_vfs.root_path + self.restore_point + "/") progressBarTitle = progressBarTitle + utils.getString(30023) + ": " + utils.getString(30017) else: - #kill the program here + # kill the program here self.remote_vfs = None return False @@ -359,11 +359,11 @@ class XbmcBackup: utils.log(utils.getString(30048) + ": " + self.remote_vfs.root_path) - #setup the progress bar + # setup the progress bar self.progressBar = BackupProgressBar(progressOverride) self.progressBar.create(progressBarTitle,utils.getString(30049) + "......") - #if we made it this far we're good + # if we made it this far we're good return True def _closeVFS(self): @@ -371,7 +371,7 @@ class XbmcBackup: self.remote_vfs.cleanup() self.progressBar.close() - #reset the window setting + # reset the window setting window = xbmcgui.Window(10000) window.setProperty(utils.__addon_id__ + ".running","") @@ -381,7 +381,7 @@ class XbmcBackup: utils.log("Source: " + source.root_path) utils.log("Desintation: " + dest.root_path) - #make sure the dest folder exists - can cause write errors if the full path doesn't exist + # make sure the dest folder exists - can cause write errors if the full path doesn't exist if(not dest.exists(dest.root_path)): dest.mkdir(dest.root_path) @@ -397,13 +397,13 @@ class XbmcBackup: 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 + # if copying from cloud storage we need the file handle, use get_file wroteFile = source.get_file(aFile,destFile) else: - #copy using normal method + # copy using normal method 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): result = False @@ -418,18 +418,18 @@ class XbmcBackup: for aDir in dirList: fileManager.addDir(aDir) - #walk all the root trees + # walk all the root trees fileManager.walk() - #update total files + # update total files self.filesTotal = self.filesTotal + fileManager.size() return {"name":folder_name,"source":root_path,"dest":self.remote_vfs.root_path,"files":fileManager.getFiles()} def _dateFormat(self,dirName): - #create date_time object from foldername YYYYMMDDHHmm + # create date_time object from foldername YYYYMMDDHHmm date_time = datetime(int(dirName[0:4]),int(dirName[4:6]),int(dirName[6:8]),int(dirName[8:10]),int(dirName[10:12])) - #format the string based on region settings + # format the string based on region settings result = utils.getRegionalTimestamp(date_time, ['dateshort','time']) return result @@ -442,21 +442,21 @@ class XbmcBackup: total_backups = int(utils.getSetting('backup_rotation')) if(total_backups > 0): - #get a list of valid backup folders + # get a list of valid backup folders dirs = self.listBackups(reverse=False) if(len(dirs) > total_backups): - #remove backups to equal total wanted + # remove backups to equal total wanted remove_num = 0 self.filesTotal = self.filesTotal + remove_num + 1 - #update the progress bar if it is available + # update the progress bar if it is available while(remove_num < (len(dirs) - total_backups) and not self.progressBar.checkCancel()): self._updateProgress(utils.getString(30054) + " " + dirs[remove_num][1]) utils.log("Removing backup " + dirs[remove_num][0]) if(dirs[remove_num][0].split('.')[-1] == 'zip'): - #this is a file, remove it that way + # this is a file, remove it that way self.remote_vfs.rmfile(self.remote_base_path + dirs[remove_num][0]) else: self.remote_vfs.rmdir(self.remote_base_path + dirs[remove_num][0] + "/") @@ -478,11 +478,11 @@ class XbmcBackup: success = self.remote_vfs.put(xbmc.translatePath(utils.data_dir() + "xbmcbackup.val"),self.remote_vfs.root_path + "xbmcbackup.val") - #remove the validation file + # remove the validation file xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "xbmcbackup.val")) if(success): - #android requires a .nomedia file to not index the directory as media + # android requires a .nomedia file to not index the directory as media if(not xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + ".nomedia"))): nmFile = xbmcvfs.File(xbmc.translatePath(utils.data_dir() + ".nomedia"),'w') nmFile.close() @@ -494,7 +494,7 @@ class XbmcBackup: def _checkValidationFile(self,path): result = None - #copy the file and open it + # copy the file and open it if(isinstance(self.remote_vfs,DropboxFileSystem)): self.remote_vfs.get_file(path + "xbmcbackup.val", xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val")) else: @@ -504,7 +504,7 @@ class XbmcBackup: jsonString = vFile.read() vFile.close() - #delete after checking + # delete after checking xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val")) try: @@ -517,7 +517,7 @@ class XbmcBackup: result = None except ValueError: - #may fail on older archives + # may fail on older archives result = None return result @@ -560,17 +560,17 @@ class FileManager: dirs,files = self.vfs.listdir(directory) if(recurse): - #create all the subdirs first + # create all the subdirs first for aDir in dirs: dirPath = xbmc.validatePath(xbmc.translatePath(directory + self.pathSep + aDir)) file_ext = aDir.split('.')[-1] - #check if directory is excluded + # check if directory is excluded if(not any(dirPath.startswith(exDir) for exDir in self.exclude_dir)): self.addFile("-" + dirPath) - #catch for "non directory" type files + # catch for "non directory" type files shouldWalk = True for s in file_ext: @@ -580,7 +580,7 @@ class FileManager: if(shouldWalk): self.walkTree(dirPath) - #copy all the files + # copy all the files for aFile in files: filePath = xbmc.translatePath(directory + self.pathSep + aFile) self.addFile(filePath) @@ -592,17 +592,17 @@ class FileManager: self.excludeFile(xbmc.translatePath(dirMeta['path'])) def addFile(self,filename): - #write the full remote path name of this file + # write the full remote path name of this file utils.log("Add File: " + filename) self.fileArray.append(filename) def excludeFile(self,filename): - #remove trailing slash + # remove trailing slash if(filename[-1] == '/' or filename[-1] == '\\'): filename = filename[:-1] - #write the full remote path name of this file + # write the full remote path name of this file utils.log("Exclude File: " + filename) self.exclude_dir.append(filename) diff --git a/resources/lib/extractor.py b/resources/lib/extractor.py index e85a6cf..115c391 100644 --- a/resources/lib/extractor.py +++ b/resources/lib/extractor.py @@ -1,31 +1,30 @@ from . import utils as utils class ZipExtractor: - - def extract(self,zipFile,outLoc,progressBar): + + def extract(self, zipFile, outLoc, progressBar): utils.log("extracting zip archive") - - result = True #result is true unless we fail - - #update the progress bar + + result = True # result is true unless we fail + + # update the progress bar progressBar.updateProgress(0,utils.getString(30100)) - - #list the files + + # list the files fileCount = float(len(zipFile.listFiles())) currentFile = 0 - + try: for aFile in zipFile.listFiles(): - #update the progress bar + # update the progress bar currentFile += 1 - progressBar.updateProgress(int((currentFile/fileCount) * 100),utils.getString(30100)) - - #extract the file - zipFile.extract(aFile,outLoc) - - except Exception as e: + progressBar.updateProgress(int((currentFile / fileCount) * 100), utils.getString(30100)) + + # extract the file + zipFile.extract(aFile, outLoc) + + except Exception: utils.log("Error extracting file") result = False - + return result - diff --git a/resources/lib/guisettings.py b/resources/lib/guisettings.py index d51ac6e..aa1b570 100644 --- a/resources/lib/guisettings.py +++ b/resources/lib/guisettings.py @@ -9,14 +9,14 @@ class GuiSettingsManager: doc = None def __init__(self): - #first make a copy of the file + # 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 + # 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 + # 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'] @@ -26,13 +26,13 @@ class GuiSettingsManager: if('value' in aSetting): currentSettings[aSetting['id']] = aSetting['value'] - #parse the existing xml file and get all the settings we need to restore + # 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 + # get a list where the restore setting value != the current value updateSettings = {k: v for k, v in list(restoreSettings.items()) if (k in currentSettings and currentSettings[k] != v)} - #go through all the found settings and update them + # go through all the found settings and update them jsonObj = {"jsonrpc":"2.0","id":1,"method":"Settings.SetSettingValue","params":{"setting":"","value":""}} for anId, aValue in list(updateSettings.items()): utils.log("updating: " + anId + ", value: " + str(aValue)) @@ -50,7 +50,7 @@ class GuiSettingsManager: if(node.firstChild != None): nodeValue = node.firstChild.nodeValue - #check for numbers and booleans + # check for numbers and booleans if(nodeValue.isdigit()): nodeValue = int(nodeValue) elif(nodeValue == 'true'): diff --git a/resources/lib/progressbar.py b/resources/lib/progressbar.py index e68cb04..78a43a7 100644 --- a/resources/lib/progressbar.py +++ b/resources/lib/progressbar.py @@ -13,9 +13,9 @@ class BackupProgressBar: def __init__(self,progressOverride): self.override = progressOverride - #check if we should use the progress bar + # check if we should use the progress bar if(int(utils.getSetting('progress_mode')) != 2): - #check if background or normal + # check if background or normal if(int(utils.getSetting('progress_mode')) == 0 and not self.override): self.mode = self.DIALOG self.progressBar = xbmcgui.DialogProgress() @@ -29,10 +29,10 @@ class BackupProgressBar: def updateProgress(self,percent,message=None): - #update the progress bar + # update the progress bar if(self.mode != self.NONE): if(message != None): - #need different calls for dialog and background bars + # need different calls for dialog and background bars if(self.mode == self.DIALOG): self.progressBar.update(percent,message) else: diff --git a/resources/lib/tinyurl.py b/resources/lib/tinyurl.py index af5ca82..ac892b8 100644 --- a/resources/lib/tinyurl.py +++ b/resources/lib/tinyurl.py @@ -1,11 +1,11 @@ from future.moves.urllib.request import urlopen -#this is duplicated in snipppets of code from all over the web, credit to no one -#in particular - to all those that have gone before me! +# this is duplicated in snipppets of code from all over the web, credit to no one +# in particular - to all those that have gone before me! def shorten(aUrl): tinyurl = 'http://tinyurl.com/api-create.php?url=' req = urlopen(tinyurl + aUrl) data = req.read() - #should be a tiny url + # should be a tiny url return str(data) diff --git a/resources/lib/vfs.py b/resources/lib/vfs.py index 47b6c7a..d93d5b7 100644 --- a/resources/lib/vfs.py +++ b/resources/lib/vfs.py @@ -18,14 +18,14 @@ class Vfs: old_root = self.root_path self.root_path = rootString - #fix slashes + # fix slashes self.root_path = self.root_path.replace("\\","/") - #check if trailing slash is included + # check if trailing slash is included if(self.root_path[-1:] != "/"): self.root_path = self.root_path + "/" - #return the old root + # return the old root return old_root def listdir(self,directory): @@ -86,7 +86,7 @@ class ZipFileSystem(Vfs): return [[],[]] def mkdir(self,directory): - #self.zip.write(directory[len(self.root_path):]) + # self.zip.write(directory[len(self.root_path):]) return False def put(self,source,dest): @@ -107,14 +107,14 @@ class ZipFileSystem(Vfs): self.zip.close() def extract(self,aFile,path): - #extract zip file to path + # extract zip file to path self.zip.extract(aFile,path) def listFiles(self): return self.zip.infolist() class DropboxFileSystem(Vfs): - MAX_CHUNK = 50 * 1000 * 1000 #dropbox uses 150, reduced to 50 for small mem systems + MAX_CHUNK = 50 * 1000 * 1000 # dropbox uses 150, reduced to 50 for small mem systems client = None APP_KEY = '' APP_SECRET = '' @@ -127,7 +127,7 @@ class DropboxFileSystem(Vfs): if(authorizer.isAuthorized()): self.client = authorizer.getClient() else: - #tell the user to go back and run the authorizer + # tell the user to go back and run the authorizer xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30105)) sys.exit() @@ -153,7 +153,7 @@ class DropboxFileSystem(Vfs): def mkdir(self,directory): directory = self._fix_slashes(directory) if(self.client != None): - #sort of odd but always return true, folder create is implicit with file upload + # sort of odd but always return true, folder create is implicit with file upload return True else: return False @@ -161,13 +161,13 @@ class DropboxFileSystem(Vfs): def rmdir(self,directory): directory = self._fix_slashes(directory) if(self.client != None and self.exists(directory)): - #dropbox is stupid and will refuse to do this sometimes, need to delete recursively + # dropbox is stupid and will refuse to do this sometimes, need to delete recursively dirs,files = self.listdir(directory) for aDir in dirs: self.rmdir(aDir) - #finally remove the root directory + # finally remove the root directory self.client.files_delete(directory) return True @@ -187,13 +187,13 @@ class DropboxFileSystem(Vfs): aFile = self._fix_slashes(aFile) if(self.client != None): - #can't list root metadata + # can't list root metadata if(aFile == ''): return True try: meta_data = self.client.files_get_metadata(aFile) - #if we make it here the file does exist + # if we make it here the file does exist return True except: return False @@ -204,46 +204,46 @@ class DropboxFileSystem(Vfs): dest = self._fix_slashes(dest) if(self.client != None): - #open the file and get its size + # open the file and get its size f = open(source,'rb') f_size = os.path.getsize(source) try: if(f_size < self.MAX_CHUNK): - #use the regular upload + # use the regular upload response = self.client.files_upload(f.read(),dest,mode=WriteMode('overwrite')) else: - #start the upload session + # start the upload session upload_session = self.client.files_upload_session_start(f.read(self.MAX_CHUNK)) upload_cursor = UploadSessionCursor(upload_session.session_id,f.tell()) while(f.tell() < f_size): - #check if we should finish the upload + # check if we should finish the upload if((f_size - f.tell()) <= self.MAX_CHUNK): - #upload and close + # upload and close self.client.files_upload_session_finish(f.read(self.MAX_CHUNK),upload_cursor,CommitInfo(dest,mode=WriteMode('overwrite'))) else: - #upload a part and store the offset + # upload a part and store the offset self.client.files_upload_session_append_v2(f.read(self.MAX_CHUNK),upload_cursor) upload_cursor.offset = f.tell() - #if no errors we're good! + # if no errors we're good! return True except Exception as anError: utils.log(str(anError)) - #if we have an exception retry + # if we have an exception retry if(retry): return self.put(source,dest,False) else: - #tried once already, just quit + # tried once already, just quit return False else: return False def get_file(self,source,dest): if(self.client != None): - #write the file locally + # write the file locally f = self.client.files_download_to_file(dest,source) return True else: @@ -252,11 +252,11 @@ class DropboxFileSystem(Vfs): def _fix_slashes(self,filename): result = filename.replace('\\','/') - #root needs to be a blank string + # root needs to be a blank string if(result == '/'): result = "" - #if dir ends in slash, remove it + # if dir ends in slash, remove it if(result[-1:] == "/"): result = result[:-1] diff --git a/scheduler.py b/scheduler.py index cd8a182..329f282 100644 --- a/scheduler.py +++ b/scheduler.py @@ -5,7 +5,7 @@ import resources.lib.utils as utils from resources.lib.croniter import croniter from resources.lib.backup import XbmcBackup -UPGRADE_INT = 2 #to keep track of any upgrade notifications +UPGRADE_INT = 2 # to keep track of any upgrade notifications class BackupScheduler: monitor = None @@ -21,7 +21,7 @@ class BackupScheduler: if(self.enabled == "true"): - #sleep for 2 minutes so Kodi can start and time can update correctly + # sleep for 2 minutes so Kodi can start and time can update correctly xbmc.Monitor().waitForAbort(120) nr = 0 @@ -29,14 +29,14 @@ class BackupScheduler: fh = xbmcvfs.File(self.next_run_path) try: - #check if we saved a run time from the last run + # check if we saved a run time from the last run nr = float(fh.read()) except ValueError: nr = 0 fh.close() - #if we missed and the user wants to play catch-up + # if we missed and the user wants to play catch-up if(0 < nr <= time.time() and utils.getSetting('schedule_miss') == 'true'): utils.log("scheduled backup was missed, doing it now...") progress_mode = int(utils.getSetting('progress_mode')) @@ -49,49 +49,49 @@ class BackupScheduler: self.setup() def setup(self): - #scheduler was turned on, find next run time + # scheduler was turned on, find next run time utils.log("scheduler enabled, finding next run time") self.findNextRun(time.time()) def start(self): - #display upgrade messages if they exist + # display upgrade messages if they exist if(int(utils.getSetting('upgrade_notes')) < UPGRADE_INT): xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30132)) utils.setSetting('upgrade_notes',str(UPGRADE_INT)) - #check if a backup should be resumed + # check if a backup should be resumed resumeRestore = self._resumeCheck() if(resumeRestore): restore = XbmcBackup() restore.selectRestore(self.restore_point) - #skip the advanced settings check + # skip the advanced settings check restore.skipAdvanced() restore.restore() while(not self.monitor.abortRequested()): if(self.enabled == "true"): - #scheduler is still on + # scheduler is still on now = time.time() if(self.next_run <= now): progress_mode = int(utils.getSetting('progress_mode')) self.doScheduledBackup(progress_mode) - #check if we should shut the computer down + # check if we should shut the computer down if(utils.getSetting("cron_shutdown") == 'true'): - #wait 10 seconds to make sure all backup processes and files are completed + # wait 10 seconds to make sure all backup processes and files are completed time.sleep(10) xbmc.executebuiltin('ShutDown()') else: - #find the next run time like normal + # find the next run time like normal self.findNextRun(now) xbmc.sleep(500) - #delete monitor to free up memory + # delete monitor to free up memory del self.monitor def doScheduledBackup(self,progress_mode): @@ -107,9 +107,9 @@ class BackupScheduler: else: backup.backup(False) - #check if this is a "one-off" + # check if this is a "one-off" if(int(utils.getSetting("schedule_interval")) == 0): - #disable the scheduler after this run + # disable the scheduler after this run self.enabled = "false" utils.setSetting('enable_scheduler','false') else: @@ -118,7 +118,7 @@ class BackupScheduler: def findNextRun(self,now): progress_mode = int(utils.getSetting('progress_mode')) - #find the cron expression and get the next run time + # find the cron expression and get the next run time cron_exp = self.parseSchedule() cron_ob = croniter(cron_exp,datetime.fromtimestamp(now)) @@ -128,12 +128,12 @@ class BackupScheduler: self.next_run = new_run_time utils.log("scheduler will run again on " + utils.getRegionalTimestamp(datetime.fromtimestamp(self.next_run),['dateshort','time'])) - #write the next time to a file + # write the next time to a file fh = xbmcvfs.File(self.next_run_path, 'w') fh.write(str(self.next_run)) fh.close() - #only show when not in silent mode + # only show when not in silent mode if(progress_mode != 2): utils.showNotification(utils.getString(30081) + " " + utils.getRegionalTimestamp(datetime.fromtimestamp(self.next_run),['dateshort','time'])) @@ -141,15 +141,15 @@ class BackupScheduler: current_enabled = utils.getSetting("enable_scheduler") if(current_enabled == "true" and self.enabled == "false"): - #scheduler was just turned on + # scheduler was just turned on self.enabled = current_enabled self.setup() elif (current_enabled == "false" and self.enabled == "true"): - #schedule was turn off + # schedule was turn off self.enabled = current_enabled if(self.enabled == "true"): - #always recheck the next run time after an update + # always recheck the next run time after an update self.findNextRun(time.time()) def parseSchedule(self): @@ -159,14 +159,14 @@ class BackupScheduler: hour_of_day = utils.getSetting("schedule_time") hour_of_day = int(hour_of_day[0:2]) if(schedule_type == 0 or schedule_type == 1): - #every day + # every day cron_exp = "0 " + str(hour_of_day) + " * * *" elif(schedule_type == 2): - #once a week + # once a week day_of_week = utils.getSetting("day_of_week") cron_exp = "0 " + str(hour_of_day) + " * * " + day_of_week elif(schedule_type == 3): - #first day of month + # first day of month cron_exp = "0 " + str(hour_of_day) + " 1 * *" return cron_exp