16 Commits

Author SHA1 Message Date
Rob Weber
b7587c6170 version bump 2021-03-15 13:39:07 -05:00
robweber
79cddb422c part of #186 2021-03-14 21:18:28 -05:00
robweber
8415ec12ba updated changelog.md 2021-03-07 14:30:31 -06:00
robweber
a284451640 part of #186 2021-03-07 14:30:17 -06:00
robweber
dc8d334352 fix addon.xml version 2021-03-06 19:20:54 -06:00
robweber
c17a185639 version bump 2021-03-06 19:20:31 -06:00
robweber
aff124af1f more of #183 2021-03-06 19:11:26 -06:00
robweber
350d81caf4 updated changelog.md 2021-02-21 21:27:04 -06:00
robweber
46d7d22523 part of #183 2021-02-21 21:25:56 -06:00
Rob Weber
11c644cb15 added help strings 2021-01-20 14:35:52 -06:00
Rob Weber
941b593751 updated change log 2021-01-20 14:27:34 -06:00
Rob Weber
e622a0455f fixes #83 2021-01-20 14:25:48 -06:00
Rob Weber
9c1ecc254f path to this folder was incorrect 2021-01-18 13:48:17 -06:00
Rob Weber
44fdf7a20a rmdir function only accepts one arg now 2021-01-18 13:10:50 -06:00
Rob Weber
ec214c074f simplified path expansions for special://temp zip file location 2021-01-18 09:01:19 -06:00
Rob
02d852a7e9 Matrix Settings (#179)
* added settings levels
2021-01-17 14:54:10 -06:00
7 changed files with 485 additions and 82 deletions

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.xbmcbackup"
name="Backup" version="1.6.4" provider-name="robweber">
name="Backup" version="1.6.6" provider-name="robweber">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.8.0" />
@@ -89,11 +89,8 @@
<screenshot>resources/images/screenshot3.jpg</screenshot>
<screenshot>resources/images/screenshot4.jpg</screenshot>
</assets>
<news>Version 1.6.4
- updated deprecated Kodi python methods
- added better system settings/restore functionality (enabled by default)
- fixed Dropbox oauth import
- fixed xbmcgui.Dialog().ok() parameter list
<news>Version 1.6.6
- fixed issue with backup rotations not working properly
</news>
</extension>
</addon>

View File

@@ -4,13 +4,35 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [Version 1.6.6](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.5...robweber:matrix-1.6.6)
### Fixed
- error when typing the remote path, ```listBackups()``` function was not working if final slash not included in typed directory path name.
- added ```force=True``` flag to the ```rmdir()``` function. Fixes issue with directories being removed when not empty
## [Version 1.6.5](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.4...robweber:matrix-1.6.5) - 2021-03-06
### Added
- added Expert setting to change location of zip file temp location as it's being built or extracted
### Changed
- updated ```settings.xml``` to match new [Kodi settings syntax](https://kodi.wiki/view/Add-on_settings_conversion), including visibility levels
### Fixed
- when restoring from a zip file the command to delete the extracted directory was incorrect
- ```Dialog().yesno()``` no longer takes line1 arg, changed to message
## [Version 1.6.4](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.3...robweber:matrix-1.6.4) - 2020-12-23
### Added
- merged duplicate copy code into ```_copyFile``` method
- added method to backup/restore Kodi settings via the GetSettings/SetSettingValue JSON methods in the validation file
- added setting to always restore settings or prompt at the time of backup
- added setting to always restore settings or prompt at the time of backup
### Changed

View File

@@ -173,8 +173,8 @@ msgid "Would you like to continue?"
msgstr "Would you like to continue?"
msgctxt "#30045"
msgid "Error: Remote path doesn't exist"
msgstr "Error: Remote path doesn't exist"
msgid "Error: Remote or zip file path doesn't exist"
msgstr "Error: Remote or zip file path doesn't exist"
msgctxt "#30046"
msgid "Starting"
@@ -592,3 +592,35 @@ msgstr ""
msgctxt "#30150"
msgid "Restore saved Kodi system settings from backup?"
msgstr ""
msgctxt "#30151"
msgid "Enable Verbose Logging"
msgstr ""
msgctxt "#30152"
msgid "Set Zip File Location"
msgstr ""
msgctxt "#30153"
msgid "Full path to where the zip file will be staged during backup or restore - must be local to this device"
msgstr ""
msgctxt "#30154"
msgid "Always prompt if Kodi settings should be restored - no by default"
msgstr ""
msgctxt "#30155"
msgid "Adds additional information to the log file"
msgstr ""
msgctxt "#30156"
msgid "Must save key/secret first, then return to settings to authorize"
msgstr ""
msgctxt "#30157"
msgid "Simple uses pre-defined folder locations, use Advanced Editor to define custom paths"
msgstr ""
msgctxt "#30158"
msgid "Run backup on daily, weekly, monthly, or custom schedule"
msgstr ""

View File

@@ -94,7 +94,7 @@ class AdvancedBackupEditor:
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))
enterHome = self.dialog.yesno(utils.getString(30111), message=utils.getString(30112) + " - " + utils.getString(30114) + "\n" + utils.getString(30113) + " - " + utils.getString(30115), nolabel=utils.getString(30112), yeslabel=utils.getString(30113))
rootFolder = 'special://home'
if(enterHome):
@@ -161,7 +161,7 @@ class AdvancedBackupEditor:
contextOption = self.dialog.contextmenu(cOptions)
if(contextOption == 0):
if(self.dialog.yesno(heading=utils.getString(30123), line1=utils.getString(30128))):
if(self.dialog.yesno(heading=utils.getString(30123), message=utils.getString(30128))):
# remove folder
del backupSet['dirs'][optionSelected - 3]
elif(contextOption == 1 and backupSet['dirs'][optionSelected - 3]['type'] == 'include'):
@@ -217,7 +217,7 @@ class AdvancedBackupEditor:
customPaths.updateSet(aSet['name'], updatedSet)
elif(menuOption == 1):
if(self.dialog.yesno(heading=utils.getString(30127), line1=utils.getString(30128))):
if(self.dialog.yesno(heading=utils.getString(30127), message=utils.getString(30128))):
# delete this path - subtract one because of "add" item
customPaths.deleteSet(exitCondition - 1)

View File

@@ -27,6 +27,8 @@ class XbmcBackup:
Backup = 0
Restore = 1
ZIP_TEMP_PATH = None
# list of dirs for the "simple" file selection
simple_directory_list = ['addons', 'addon_data', 'database', 'game_saves', 'playlists', 'profiles', 'thumbnails', 'config']
@@ -48,26 +50,26 @@ class XbmcBackup:
def __init__(self):
self.xbmc_vfs = XBMCFileSystem(xbmcvfs.translatePath('special://home'))
self.ZIP_TEMP_PATH = xbmcvfs.translatePath(utils.getSetting('zip_temp_path'))
self.configureRemote()
utils.log(utils.getString(30046))
def configureRemote(self):
if(utils.getSetting('remote_selection') == '1'):
self.remote_base_path = utils.getSetting('remote_path_2')
self.remote_vfs = XBMCFileSystem(utils.getSetting('remote_path_2'))
utils.setSetting("remote_path", "")
elif(utils.getSetting('remote_selection') == '0'):
self.remote_base_path = utils.getSetting('remote_path')
self.remote_vfs = XBMCFileSystem(utils.getSetting("remote_path"))
elif(utils.getSetting('remote_selection') == '2'):
self.remote_base_path = "/"
self.remote_vfs = DropboxFileSystem("/")
self.remote_base_path = self.remote_vfs.root_path
def remoteConfigured(self):
result = True
if(self.remote_base_path == ""):
if(self.remote_base_path == "" or not xbmcvfs.exists(self.ZIP_TEMP_PATH)):
result = False
return result
@@ -155,7 +157,7 @@ class XbmcBackup:
if(not writeCheck):
# 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)
shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30089), "%s\n%s" % (utils.getString(30090), utils.getString(30044)), autoclose=25000)
if(not shouldContinue):
return
@@ -181,13 +183,13 @@ class XbmcBackup:
fileManager = FileManager(self.xbmc_vfs)
# send the zip file to the real remote vfs
zip_name = self.remote_vfs.root_path[:-1] + ".zip"
zip_name = os.path.join(self.ZIP_TEMP_PATH, self.remote_vfs.root_path[:-1] + ".zip")
self.remote_vfs.cleanup()
self.xbmc_vfs.rename(xbmcvfs.translatePath("special://temp/xbmc_backup_temp.zip"), xbmcvfs.translatePath("special://temp/" + zip_name))
fileManager.addFile(xbmcvfs.translatePath("special://temp/" + zip_name))
self.xbmc_vfs.rename(os.path.join(self.ZIP_TEMP_PATH, "xbmc_backup_temp.zip"), zip_name)
fileManager.addFile(zip_name)
# set root to data dir home and reset remote
self.xbmc_vfs.set_root(xbmcvfs.translatePath("special://temp/"))
self.xbmc_vfs.set_root(self.ZIP_TEMP_PATH)
self.remote_vfs = self.saved_remote_vfs
# update the amount to transfer
@@ -200,7 +202,7 @@ class XbmcBackup:
shouldContinue = xbmcgui.Dialog().ok(utils.getString(30089), '%s\n%s' % (utils.getString(30090), utils.getString(30091)))
# delete the temp zip file
self.xbmc_vfs.rmfile(xbmcvfs.translatePath("special://temp/" + zip_name))
self.xbmc_vfs.rmfile(zip_name)
# remove old backups
self._rotateBackups()
@@ -220,9 +222,9 @@ class XbmcBackup:
utils.log("copying zip file: " + self.restore_point)
# set root to data dir home
self.xbmc_vfs.set_root(xbmcvfs.translatePath("special://temp/"))
if(not self.xbmc_vfs.exists(xbmcvfs.translatePath("special://temp/" + self.restore_point))):
self.xbmc_vfs.set_root(self.ZIP_TEMP_PATH)
restore_path = os.path.join(self.ZIP_TEMP_PATH, self.restore_point)
if(not self.xbmc_vfs.exists(restore_path)):
# copy just this file from the remote vfs
self.transferSize = self.remote_vfs.fileSize(self.remote_base_path + self.restore_point)
zipFile = []
@@ -235,13 +237,13 @@ class XbmcBackup:
utils.log("zip file exists already")
# extract the zip file
zip_vfs = ZipFileSystem(xbmcvfs.translatePath("special://temp/" + self.restore_point), 'r')
zip_vfs = ZipFileSystem(restore_path, 'r')
extractor = ZipExtractor()
if(not extractor.extract(zip_vfs, xbmcvfs.translatePath("special://temp/"), self.progressBar)):
if(not extractor.extract(zip_vfs, self.ZIP_TEMP_PATH, self.progressBar)):
# we had a problem extracting the archive, delete everything
zip_vfs.cleanup()
self.xbmc_vfs.rmfile(xbmcvfs.translatePath("special://temp/" + self.restore_point))
self.xbmc_vfs.rmfile(restore_path)
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30101))
return
@@ -250,7 +252,7 @@ class XbmcBackup:
self.progressBar.updateProgress(0, utils.getString(30049) + "......")
# set the new remote vfs and fix xbmc path
self.remote_vfs = XBMCFileSystem(xbmcvfs.translatePath("special://temp/" + self.restore_point.split(".")[0] + "/"))
self.remote_vfs = XBMCFileSystem(os.path.join(self.ZIP_TEMP_PATH, self.restore_point.split(".")[0]))
self.xbmc_vfs.set_root(xbmcvfs.translatePath("special://home/"))
# for restores remote path must exist
@@ -270,7 +272,7 @@ class XbmcBackup:
# 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
restartXbmc = xbmcgui.Dialog().yesno(utils.getString(30038), utils.getString(30039), utils.getString(30040), utils.getString(30041))
restartXbmc = xbmcgui.Dialog().yesno(utils.getString(30038), "%s\n%s" % (utils.getString(30039), utils.getString(30040)), utils.getString(30041))
if(restartXbmc):
# add only this file to the file list
@@ -335,8 +337,10 @@ class XbmcBackup:
if(self.restore_point.split('.')[-1] == 'zip'):
# delete the zip file and the extracted directory
self.xbmc_vfs.rmfile(xbmcvfs.translatePath("special://temp/" + self.restore_point))
self.xbmc_vfs.rmdir(self.remote_vfs.root_path)
self.xbmc_vfs.rmfile(os.path.join(self.ZIP_TEMP_PATH, self.restore_point))
xbmc.sleep(1000)
self.xbmc_vfs.rmdir(self.remote_vfs.clean_path(os.path.join(self.ZIP_TEMP_PATH, self.restore_point.split(".")[0])))
xbmc.sleep(1000)
# call update addons to refresh everything
xbmc.executebuiltin('UpdateLocalAddons')
@@ -351,15 +355,16 @@ class XbmcBackup:
if(mode == self.Backup and self.remote_vfs.root_path != ''):
if(utils.getSettingBool("compress_backups")):
# delete old temp file
if(self.xbmc_vfs.exists(xbmcvfs.translatePath('special://temp/xbmc_backup_temp.zip'))):
if(not self.xbmc_vfs.rmfile(xbmcvfs.translatePath('special://temp/xbmc_backup_temp.zip'))):
zip_path = os.path.join(self.ZIP_TEMP_PATH, 'xbmc_backup_temp.zip')
if(self.xbmc_vfs.exists(zip_path)):
if(not self.xbmc_vfs.rmfile(zip_path)):
# we had some kind of error deleting the old file
xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s' % (utils.getString(30096), utils.getString(30097)))
return False
# save the remote file system and use the zip vfs
self.saved_remote_vfs = self.remote_vfs
self.remote_vfs = ZipFileSystem(xbmcvfs.translatePath("special://temp/xbmc_backup_temp.zip"), "w")
self.remote_vfs = ZipFileSystem(zip_path, "w")
self.remote_vfs.set_root(self.remote_vfs.root_path + time.strftime("%Y%m%d%H%M") + "/")
progressBarTitle = progressBarTitle + utils.getString(30023) + ": " + utils.getString(30016)
@@ -374,6 +379,7 @@ class XbmcBackup:
utils.log(utils.getString(30047) + ": " + self.xbmc_vfs.root_path)
utils.log(utils.getString(30048) + ": " + self.remote_vfs.root_path)
utils.log(utils.getString(30152) + ": " + utils.getSetting('zip_temp_path'))
# setup the progress bar
self.progressBar = BackupProgressBar(progressOverride)
@@ -535,7 +541,7 @@ class XbmcBackup:
result = json.loads(jsonString)
if(xbmc.getInfoLabel('System.BuildVersion') != result['xbmc_version']):
shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30085), utils.getString(30086), utils.getString(30044))
shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30085), "%s\n%s" % (utils.getString(30086), utils.getString(30044)))
if(not shouldContinue):
result = None

View File

@@ -73,7 +73,7 @@ class XBMCFileSystem(Vfs):
return xbmcvfs.copy(xbmcvfs.translatePath(source), xbmcvfs.translatePath(dest))
def rmdir(self, directory):
return xbmcvfs.rmdir(directory, True)
return xbmcvfs.rmdir(directory, force=True) # use force=True to make sure it works recursively
def rmfile(self, aFile):
return xbmcvfs.delete(aFile)

View File

@@ -1,46 +1,392 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<settings>
<category id="general" label="30011" level="expert">
<setting id="compress_backups" type="bool" label="30087" default="false" />
<setting id="backup_rotation" type="number" label="30026" default="0" />
<setting id="always_prompt_restore_settings" type="bool" label="30148" default="false" />
<setting id="progress_mode" type="enum" label="30022" lvalues="30082|30083|30084" default="0" />
<setting type="sep" />
<setting id="verbose_logging" type="bool" label="Enable Verbose Logging" default="false" />
<setting id="upgrade_notes" type="number" label="upgrade_notes" visible="false" default="1" />
</category>
<category id="backup_path" label="30048">
<setting id="remote_selection" type="enum" lvalues="30018|30019|30027" default="0" label="30025"/>
<setting id="remote_path_2" type="text" label="30024" default="" visible="eq(-1,1)" />
<setting id="remote_path" type="folder" label="30020" visible="eq(-2,0)" />
<setting id="dropbox_key" type="text" label="30028" visible="eq(-3,2)" default="" />
<setting id="dropbox_secret" type="text" label="30029" visible="eq(-4,2)" default="" />
<setting id="google_drive_id" type="text" label="Client ID" visible="eq(-5,3)" default="" />
<setting id="google_drive_secret" type="text" label="Client Secret" visible="eq(-6,3)" default="" />
<setting id="auth_dropbox_button" type="action" label="30104" action="RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=authorize_cloud,provider=dropbox)" visible="eq(-7,2)"/>
<setting id="auth_google_button" type="action" label="30104" action="RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=authorize_cloud,provider=google_drive)" visible="eq(-8,3)"/>
<setting id="remove_auth_button" type="action" label="30093" action="RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=remove_auth)" visible="gt(-9,1)"/>
</category>
<category id="selection" label="30012">
<setting id="backup_selection_type" type="enum" lvalues="30014|30015" default="0" label="30023" />
<setting id="backup_addon_data" type="bool" label="30031" default="false" visible="eq(-1,0)"/>
<setting id="backup_config" type="bool" label="30035" default="true" visible="eq(-2,0)"/>
<setting id="backup_database" type="bool" label="30032" default="true" visible="eq(-3,0)"/>
<setting id="backup_game_saves" type="bool" label="30133" default="false" visible="eq(-4,0)" />
<setting id="backup_playlists" type="bool" label="30033" default="true" visible="eq(-5,0)"/>
<setting id="backup_profiles" type="bool" label="30080" default="false" visible="eq(-6,0)"/>
<setting id="backup_thumbnails" type="bool" label="30034" default="true" visible="eq(-7,0)"/>
<setting id="backup_addons" type="bool" label="30030" default="true" visible="eq(-8,0)" />
<setting id="advanced_button" type="action" label="30125" visible="eq(-9,1)" action="RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=advanced_editor)" />
<setting id="advanced_defaults" type="action" label="30139" visible="eq(-10,1)" action="RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=advanced_copy_config)" />
</category>
<category id="scheduling" label="30013">
<setting id="enable_scheduler" type="bool" label="30060" default="false" />
<setting id="schedule_interval" type="enum" label="30061" lvalues="30079|30072|30073|30074|30075" default="1" enable="eq(-1,true)"/>
<setting id="schedule_time" type="labelenum" label="30062" values="00:00|01:00|02:00|03:00|04:00|05:00|06:00|07:00|08:00|09:00|10:00|11:00|12:00|13:00|14:00|15:00|16:00|17:00|18:00|19:00|20:00|21:00|22:00|23:00" default="00:00" visible="!eq(-1,4)" enable="eq(-2,true)"/>
<setting id="day_of_week" type="enum" label="30063" lvalues="30065|30066|30067|30068|30069|30070|30071" default="0" visible="eq(-2,2)" enable="eq(-3,true)"/>
<setting id="cron_schedule" type="text" label="30064" default="0 0 * * *" visible="eq(-3,4)" enable="eq(-4,true)"/>
<setting id="schedule_miss" type="bool" label="30109" default="false" enable="eq(-5,true)" />
<setting id="cron_shutdown" type="bool" label="30076" default="false" enable="eq(-6,true)" />
</category>
<?xml version="1.0"?>
<settings version="1">
<section id="service.xbmcbackup">
<category id="general" label="30011" help="">
<group id="1" label="">
<!-- compress backups -->
<setting id="compress_backups" type="boolean" label="30087" help="">
<level>0</level>
<default>false</default>
<control type="toggle" />
</setting>
<!-- zip folder staging path -->
<setting id="zip_temp_path" type="string" label="30152" help="30153">
<level>3</level>
<default>special://temp</default>
<constraints>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="compress_backups">true</dependency>
</dependencies>
<control type="edit" format="string">
<heading>30152</heading>
</control>
</setting>
<!-- backup rotation -->
<setting id="backup_rotation" type="integer" label="30026" help="">
<level>0</level>
<default>0</default>
<control type="edit" format="integer">
<heading>30026</heading>
</control>
</setting>
<!-- prompt to restore settings -->
<setting id="always_prompt_restore_settings" type="boolean" label="30148" help="30154">
<level>2</level>
<default>false</default>
<control type="toggle" />
</setting>
<!-- progress mode -->
<setting id="progress_mode" type="integer" label="30022" help="">
<level>1</level>
<default>0</default>
<constraints>
<options>
<option label="30082">0</option>
<option label="30083">1</option>
<option label="30084">2</option>
</options>
</constraints>
<control type="spinner" format="string" />
</setting>
</group>
<group id="2" label="">
<!-- verbose logging -->
<setting id="verbose_logging" type="boolean" label="30151" help="30155">
<level>3</level>
<default>false</default>
<control type="toggle" />
</setting>
<!-- upgrade notes not visible to users -->
<setting id="upgrade_notes" type="integer" label="upgrade_notes" help="">
<level>4</level>
<default>1</default>
<visible>false</visible>
<control type="edit" format="integer">
<heading>upgrade_notes</heading>
</control>
</setting>
</group>
</category>
<category id="backup_path" label="30048" help="">
<group id="1" label="">
<!-- backup repo type -->
<setting id="remote_selection" type="integer" label="30025" help="">
<level>0</level>
<default>0</default>
<constraints>
<options>
<option label="30018">0</option>
<option label="30019">1</option>
<option label="30027">2</option>
</options>
</constraints>
<control type="spinner" format="string" />
</setting>
<!-- folder select path -->
<setting id="remote_path" type="path" label="30020" help="">
<level>0</level>
<default/>
<constraints>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="remote_selection">0</dependency>
</dependencies>
<control type="button" format="path">
<heading>30020</heading>
</control>
</setting>
<!-- type remote path -->
<setting id="remote_path_2" type="string" label="30024" help="">
<level>0</level>
<default></default>
<constraints>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="remote_selection">1</dependency>
</dependencies>
<control type="edit" format="string">
<heading>30024</heading>
</control>
</setting>
<!-- dropbox key and secret -->
<setting id="dropbox_key" type="string" label="30028" help="30156">
<level>0</level>
<default></default>
<constraints>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="remote_selection">2</dependency>
</dependencies>
<control type="edit" format="string">
<heading>30028</heading>
</control>
</setting>
<setting id="dropbox_secret" type="string" label="30029" help="30156">
<level>0</level>
<default></default>
<constraints>
<allowempty>true</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="remote_selection">2</dependency>
</dependencies>
<control type="edit" format="string">
<heading>30029</heading>
</control>
</setting>
<!-- authorize dropbox -->
<setting id="auth_dropbox_button" type="action" label="30104" help="">
<level>0</level>
<default />
<dependencies>
<dependency type="visible" setting="remote_selection">2</dependency>
</dependencies>
<control type="button" format="action">
<data>RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=authorize_cloud,provider=dropbox)</data>
</control>
</setting>
</group>
<group id="2" label="">
<!-- remove auth button -->
<setting id="remove_auth_button" type="action" label="30093" help="">
<level>2</level>
<default />
<dependencies>
<dependency type="visible" setting="remote_selection">2</dependency>
</dependencies>
<control type="button" format="action">
<data>RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=remove_auth)</data>
</control>
</setting>
</group>
</category>
<category id="selection" label="30012">
<group id="1" label="">
<!-- selection type (simple/advanced) -->
<setting id="backup_selection_type" type="integer" label="30023" help="30157">
<level>2</level>
<default>0</default>
<constraints>
<options>
<option label="30014">0</option>
<option label="30015">1</option>
</options>
</constraints>
<control type="spinner" format="string" />
</setting>
<!-- simple selection settings -->
<setting id="backup_addon_data" type="boolean" label="30031" help="">
<level>0</level>
<default>false</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_config" type="boolean" label="30035" help="">
<level>0</level>
<default>true</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_database" type="boolean" label="30032" help="">
<level>0</level>
<default>true</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_game_saves" type="boolean" label="30133" help="">
<level>0</level>
<default>false</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_playlists" type="boolean" label="30033" help="">
<level>0</level>
<default>true</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_profiles" type="boolean" label="30080" help="">
<level>0</level>
<default>false</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_thumbnails" type="boolean" label="30034" help="">
<level>0</level>
<default>true</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<setting id="backup_addons" type="boolean" label="30030" help="">
<level>0</level>
<default>true</default>
<dependencies>
<dependency type="visible" setting="backup_selection_type">0</dependency>
</dependencies>
<control type="toggle" />
</setting>
<!-- advanced editor options -->
<setting id="advanced_button" type="action" label="30125" help="">
<level>2</level>
<default />
<dependencies>
<dependency type="visible" setting="backup_selection_type">1</dependency>
</dependencies>
<control type="button" format="action">
<data>RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=advanced_editor)</data>
</control>
</setting>
<setting id="advanced_defaults" type="action" label="30139" help="">
<level>2</level>
<default />
<dependencies>
<dependency type="visible" setting="backup_selection_type">1</dependency>
</dependencies>
<control type="button" format="action">
<data>RunScript(special://home/addons/script.xbmcbackup/launcher.py,action=advanced_copy_config)</data>
</control>
</setting>
</group>
</category>
<category id="scheduling" label="30013">
<group id="1" label="">
<!-- enable scheduler -->
<setting id="enable_scheduler" type="boolean" label="30060" help="30158">
<level>0</level>
<default>false</default>
<control type="toggle" />
</setting>
<!-- schedule interval -->
<setting id="schedule_interval" type="integer" label="30061" help="">
<level>0</level>
<default>1</default>
<constraints>
<options>
<option label="30079">0</option>
<option label="30072">1</option>
<option label="30073">2</option>
<option label="30074">3</option>
<option label="30075">4</option>
</options>
</constraints>
<dependencies>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="spinner" format="string"/>
</setting>
<!-- hour of the day -->
<setting id="schedule_time" type="string" label="30062" help="">
<level>0</level>
<default>00:00</default>
<constraints>
<options sort="ascending">
<option>00:00</option>
<option>01:00</option>
<option>02:00</option>
<option>03:00</option>
<option>04:00</option>
<option>05:00</option>
<option>06:00</option>
<option>07:00</option>
<option>08:00</option>
<option>09:00</option>
<option>10:00</option>
<option>11:00</option>
<option>12:00</option>
<option>13:00</option>
<option>14:00</option>
<option>15:00</option>
<option>16:00</option>
<option>17:00</option>
<option>18:00</option>
<option>19:00</option>
<option>20:00</option>
<option>21:00</option>
<option>22:00</option>
<option>23:00</option>
</options>
<allowempty>false</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="schedule_interval" operator="!is">4</dependency>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="spinner" format="string"/>
</setting>
<!-- day of the week -->
<setting id="day_of_week" type="integer" label="30063" help="">
<level>0</level>
<default>0</default>
<constraints>
<options>
<option label="30065">0</option>
<option label="30066">1</option>
<option label="30067">2</option>
<option label="30068">3</option>
<option label="30069">4</option>
<option label="30070">5</option>
<option label="30071">6</option>
</options>
</constraints>
<dependencies>
<dependency type="visible" setting="schedule_interval">2</dependency>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="spinner" format="string"/>
</setting>
<!-- cron schedule -->
<setting id="cron_schedule" type="string" label="30064" help="">
<level>0</level>
<default>0 0 * * *</default>
<constraints>
<allowempty>false</allowempty>
</constraints>
<dependencies>
<dependency type="visible" setting="schedule_interval">4</dependency>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="edit" format="string">
<heading>30064</heading>
</control>
</setting>
<!-- run if schedule missed -->
<setting id="schedule_miss" type="boolean" label="30109" help="">
<level>1</level>
<default>false</default>
<dependencies>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="toggle" />
</setting>
<!-- shutdown on complete -->
<setting id="cron_shutdown" type="boolean" label="30076" help="">
<level>1</level>
<default>false</default>
<dependencies>
<dependency type="enable" setting="enable_scheduler">true</dependency>
</dependencies>
<control type="toggle" />
</setting>
</group>
</category>
</section>
</settings>