Merge pull request #28 from robweber/testing

Merge custom directory code
This commit is contained in:
robweber 2013-03-04 08:29:05 -08:00
commit 4da499ebaa
6 changed files with 253 additions and 155 deletions

View File

@ -11,6 +11,8 @@ In the addon settings you can define a remote path for the destination of your x
On the Backup Selection page you can select which items from your user profile folder will be sent to the backup location. By default all are turned on except the Addon Data directory. On the Backup Selection page you can select which items from your user profile folder will be sent to the backup location. By default all are turned on except the Addon Data directory.
You can also define non-XBMC directories on your device. See "Custom Directories" for more information on how these are handled.
Scheduling: Scheduling:
You can also schedule backups to be completed on a set interval via the scheduling area. When it is time for the backup to run it will be executed in the background. You can also schedule backups to be completed on a set interval via the scheduling area. When it is time for the backup to run it will be executed in the background.
@ -21,6 +23,10 @@ Running the Program:
Running the program will allow you to select Backup or Restore as a running mode. Selecting Backup will push files to your remote store using the addon settings you defined. Selecting Restore will give you a list of restore points currently in your remote destination. Selecting one will pull the files matching your selection criteria from the restore point to your local XBMC folders. Running the program will allow you to select Backup or Restore as a running mode. Selecting Backup will push files to your remote store using the addon settings you defined. Selecting Restore will give you a list of restore points currently in your remote destination. Selecting one will pull the files matching your selection criteria from the restore point to your local XBMC folders.
Custom Directories:
You can define custom directories that are not a part of your XBMC folder structure for backup. These create a custom_1_hash folder in your backup destination. The hash for these folders is very important. During a restore if the hash of the file path in Custom 1 does not match the hash in the restore folder it will not move the files. This is to prevent files from being restored to the wrong location in the event you change file paths in the addon settings. A dialog box will let you know if file paths do not match up.
Using Dropbox: Using Dropbox:

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.xbmcbackup" <addon id="script.xbmcbackup"
name="XBMC Backup" version="0.3.4" provider-name="robweber"> name="XBMC Backup" version="0.3.5" provider-name="robweber">
<requires> <requires>
<import addon="xbmc.python" version="2.1.0"/> <import addon="xbmc.python" version="2.1.0"/>
</requires> </requires>

View File

@ -1,3 +1,7 @@
Version 0.3.5
test of custom directories - only 1 at the moment
Version 0.3.4 Version 0.3.4
added ability to take parameters via RunScript() or JSONRPC.Addons.ExecuteAddon() added ability to take parameters via RunScript() or JSONRPC.Addons.ExecuteAddon()

View File

@ -6,92 +6,13 @@ import os.path
import time import time
from vfs import XBMCFileSystem,DropboxFileSystem from vfs import XBMCFileSystem,DropboxFileSystem
class FileManager:
fileArray = None
verbose_log = False
not_dir = ['.zip','.xsp','.rar']
vfs = None
def __init__(self,vfs):
self.vfs = vfs
def createFileList(self):
self.fileArray = []
self.verbose_log = utils.getSetting("verbose_log") == 'true'
#figure out which syncing options to run
if(utils.getSetting('backup_addons') == 'true'):
self.addFile("-addons")
self.walkTree(self.vfs.root_path + "addons/")
self.addFile("-userdata")
if(utils.getSetting('backup_addon_data') == 'true'):
self.addFile("-userdata/addon_data")
self.walkTree(self.vfs.root_path + "userdata/addon_data/")
if(utils.getSetting('backup_database') == 'true'):
self.addFile("-userdata/Database")
self.walkTree(self.vfs.root_path + "userdata/Database")
if(utils.getSetting("backup_playlists") == 'true'):
self.addFile("-userdata/playlists")
self.walkTree(self.vfs.root_path + "userdata/playlists")
if(utils.getSetting("backup_thumbnails") == "true"):
self.addFile("-userdata/Thumbnails")
self.walkTree(self.vfs.root_path + "userdata/Thumbnails")
if(utils.getSetting("backup_config") == "true"):
self.addFile("-userdata/keymaps")
self.walkTree(self.vfs.root_path + "userdata/keymaps")
self.addFile("-userdata/peripheral_data")
self.walkTree(self.vfs.root_path + "userdata/peripheral_data")
#this part is an oddity
dirs,configFiles = self.vfs.listdir(self.vfs.root_path + "userdata/")
for aFile in configFiles:
if(aFile.endswith(".xml")):
self.addFile("userdata/" + aFile)
def walkTree(self,directory):
dirs,files = self.vfs.listdir(directory)
#create all the subdirs first
for aDir in dirs:
dirPath = xbmc.translatePath(directory + "/" + aDir)
file_ext = aDir.split('.')[-1]
self.addFile("-" + dirPath[len(self.vfs.root_path):])
#catch for "non directory" type files
if (not any(file_ext in s for s in self.not_dir)):
self.walkTree(dirPath)
#copy all the files
for aFile in files:
filePath = xbmc.translatePath(directory + "/" + aFile)
self.addFile(filePath[len(self.vfs.root_path):])
def addFile(self,filename):
try:
filename = filename.decode('UTF-8')
except UnicodeDecodeError:
filename = filename.decode('ISO-8859-2')
#write the full remote path name of this file
utils.log("Add File: " + filename,xbmc.LOGDEBUG)
self.fileArray.append(filename)
def getFileList(self):
return self.fileArray
class XbmcBackup: class XbmcBackup:
#constants for initiating a back or restore #constants for initiating a back or restore
Backup = 0 Backup = 0
Restore = 1 Restore = 1
#remote file system #remote file system
local_vfs = None xbmc_vfs = None
remote_vfs = None remote_vfs = None
restoreFile = None restoreFile = None
@ -104,24 +25,19 @@ class XbmcBackup:
restore_point = None restore_point = None
def __init__(self): def __init__(self):
self.local_vfs = XBMCFileSystem() self.xbmc_vfs = XBMCFileSystem(xbmc.translatePath('special://home'))
self.local_vfs.set_root(xbmc.translatePath("special://home"))
self.configureVFS()
self.configureRemote()
utils.log(utils.getString(30046)) utils.log(utils.getString(30046))
def configureVFS(self): def configureRemote(self):
if(utils.getSetting('remote_selection') == '1'): if(utils.getSetting('remote_selection') == '1'):
self.remote_vfs = XBMCFileSystem() self.remote_vfs = XBMCFileSystem(utils.getSetting('remote_path_2'))
self.remote_vfs.set_root(utils.getSetting('remote_path_2'))
utils.setSetting("remote_path","") utils.setSetting("remote_path","")
elif(utils.getSetting('remote_selection') == '0'): elif(utils.getSetting('remote_selection') == '0'):
self.remote_vfs = XBMCFileSystem() self.remote_vfs = XBMCFileSystem(utils.getSetting("remote_path"))
self.remote_vfs.set_root(utils.getSetting("remote_path"))
elif(utils.getSetting('remote_selection') == '2'): elif(utils.getSetting('remote_selection') == '2'):
self.remote_vfs = DropboxFileSystem() self.remote_vfs = DropboxFileSystem("/")
self.remote_vfs.set_root('/')
def listBackups(self): def listBackups(self):
result = list() result = list()
@ -138,7 +54,6 @@ class XbmcBackup:
self.restore_point = restore_point self.restore_point = restore_point
def run(self,mode=-1,runSilent=False): def run(self,mode=-1,runSilent=False):
#append backup folder name #append backup folder name
remote_base_path = "" remote_base_path = ""
progressBarTitle = utils.getString(30010) + " - " progressBarTitle = utils.getString(30010) + " - "
@ -154,7 +69,7 @@ class XbmcBackup:
self.remote_vfs = None self.remote_vfs = None
return return
utils.log(utils.getString(30047) + ": " + self.local_vfs.root_path) utils.log(utils.getString(30047) + ": " + self.xbmc_vfs.root_path)
utils.log(utils.getString(30048) + ": " + self.remote_vfs.root_path) utils.log(utils.getString(30048) + ": " + self.remote_vfs.root_path)
#check if we should use the progress bar #check if we should use the progress bar
@ -162,17 +77,78 @@ class XbmcBackup:
self.progressBar = xbmcgui.DialogProgress() self.progressBar = xbmcgui.DialogProgress()
self.progressBar.create(progressBarTitle,utils.getString(30049) + "......") self.progressBar.create(progressBarTitle,utils.getString(30049) + "......")
#run the correct mode
if(mode == self.Backup): if(mode == self.Backup):
utils.log(utils.getString(30023) + " - " + utils.getString(30016)) utils.log(utils.getString(30023) + " - " + utils.getString(30016))
self.fileManager = FileManager(self.local_vfs) #check if remote path exists
#for backups check if remote path exists
if(self.remote_vfs.exists(self.remote_vfs.root_path)): if(self.remote_vfs.exists(self.remote_vfs.root_path)):
#this will fail - need a disclaimer here #may be data in here already
utils.log(utils.getString(30050)) utils.log(utils.getString(30050))
else:
#make the remote directory
self.remote_vfs.mkdir(self.remote_vfs.root_path)
self.syncFiles() utils.log(utils.getString(30051))
allFiles = []
fileManager = FileManager(self.xbmc_vfs)
#go through each of the user selected items and write them to the backup store
if(utils.getSetting('backup_addons') == 'true'):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "addons")
fileManager.walkTree(xbmc.translatePath('special://home/addons'))
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata")
if(utils.getSetting('backup_addon_data') == 'true'):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/addon_data")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/addon_data'))
if(utils.getSetting('backup_database') == 'true'):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/Database")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/Database'))
if(utils.getSetting("backup_playlists") == 'true'):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/playlists")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/playlists'))
if(utils.getSetting("backup_thumbnails") == "true"):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/Thumbnails")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/Thumbnails'))
if(utils.getSetting("backup_config") == "true"):
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/keymaps")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/keymaps'))
self.remote_vfs.mkdir(self.remote_vfs.root_path + "userdata/peripheral_data")
fileManager.walkTree(xbmc.translatePath('special://home/userdata/peripheral_data'))
#this part is an oddity
dirs,configFiles = self.xbmc_vfs.listdir(xbmc.translatePath('special://home/userdata/'))
for aFile in configFiles:
if(aFile.endswith(".xml")):
fileManager.addFile(xbmc.translatePath('special://home/userdata/') + aFile)
#add to array
self.filesTotal = fileManager.size()
allFiles.append({"source":self.xbmc_vfs.root_path,"dest":self.remote_vfs.root_path,"files":fileManager.getFiles()})
#check if there are custom directories
if(utils.getSetting('backup_custom_dir') != ''):
#create a special remote path with hash
self.xbmc_vfs.set_root(utils.getSetting('backup_custom_dir'))
self.remote_vfs.mkdir(self.remote_vfs.root_path + "custom_1_" + self._createCRC(self.xbmc_vfs.root_path))
self.remote_vfs.set_root(self.remote_vfs.root_path + "custom_1_" + self._createCRC(self.xbmc_vfs.root_path))
fileManager.walkTree(self.xbmc_vfs.root_path)
self.filesTotal = self.filesTotal + fileManager.size()
allFiles.append({"source":self.xbmc_vfs.root_path,"dest":self.remote_vfs.root_path,"files":fileManager.getFiles()})
#backup all the files
self.filesLeft = self.filesTotal
for fileGroup in allFiles:
self.xbmc_vfs.set_root(fileGroup['source'])
self.remote_vfs.set_root(fileGroup['dest'])
self.backupFiles(fileGroup['files'],self.xbmc_vfs,self.remote_vfs)
#remove old backups #remove old backups
total_backups = int(utils.getSetting('backup_rotation')) total_backups = int(utils.getSetting('backup_rotation'))
@ -186,82 +162,178 @@ class XbmcBackup:
self.filesTotal = self.filesTotal + remove_num + 1 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 >= 0 and not self.checkCancel()): while(remove_num >= 0 and not self._checkCancel()):
self.updateProgress(utils.getString(30054) + " " + dirs[remove_num]) self._updateProgress(utils.getString(30054) + " " + dirs[remove_num])
utils.log("Removing backup " + dirs[remove_num]) utils.log("Removing backup " + dirs[remove_num])
self.remote_vfs.rmdir(remote_base_path + dirs[remove_num] + "/") self.remote_vfs.rmdir(remote_base_path + dirs[remove_num] + "/")
remove_num = remove_num - 1 remove_num = remove_num - 1
elif (mode == self.Restore):
else:
utils.log(utils.getString(30023) + " - " + utils.getString(30017)) utils.log(utils.getString(30023) + " - " + utils.getString(30017))
self.fileManager = FileManager(self.remote_vfs)
#for restores remote path must exist #for restores remote path must exist
if(self.remote_vfs.exists(self.remote_vfs.root_path)): if(not self.remote_vfs.exists(self.remote_vfs.root_path)):
self.restoreFiles()
else:
xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045),self.remote_vfs.root_path) xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045),self.remote_vfs.root_path)
return
if(utils.getSetting('run_silent') == 'false' and not runSilent):
self.progressBar.close()
def syncFiles(self):
#make the remote directory
self.remote_vfs.mkdir(self.remote_vfs.root_path)
utils.log(utils.getString(30051)) utils.log(utils.getString(30051))
self.fileManager.createFileList() allFiles = []
fileManager = FileManager(self.remote_vfs)
allFiles = self.fileManager.getFileList() #go through each of the user selected items and write them to the backup store
if(utils.getSetting('backup_addons') == 'true'):
self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/addons'))
fileManager.walkTree(self.remote_vfs.root_path + "addons")
#write list from local to remote self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata'))
self.writeFiles(allFiles,self.local_vfs,self.remote_vfs)
def restoreFiles(self): if(utils.getSetting('backup_addon_data') == 'true'):
self.fileManager.createFileList() self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/addon_data'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/addon_data")
utils.log(utils.getString(30051)) if(utils.getSetting('backup_database') == 'true'):
allFiles = self.fileManager.getFileList() self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/Database'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/Database")
#write list from remote to local if(utils.getSetting("backup_playlists") == 'true'):
self.writeFiles(allFiles,self.remote_vfs,self.local_vfs) self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/playlists'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/playlists")
if(utils.getSetting("backup_thumbnails") == "true"):
self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/Thumbnails'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/Thumbnails")
if(utils.getSetting("backup_config") == "true"):
self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/keymaps'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/keymaps")
self.xbmc_vfs.mkdir(xbmc.translatePath('special://home/userdata/peripheral_data'))
fileManager.walkTree(self.remote_vfs.root_path + "userdata/peripheral_data")
#this part is an oddity
dirs,configFiles = self.remote_vfs.listdir(self.remote_vfs.root_path + "userdata/")
for aFile in configFiles:
if(aFile.endswith(".xml")):
fileManager.addFile(self.remote_vfs.root_path + "userdata/" + aFile)
#add to array
self.filesTotal = fileManager.size()
allFiles.append({"source":self.remote_vfs.root_path,"dest":self.xbmc_vfs.root_path,"files":fileManager.getFiles()})
#check if there are custom directories
if(utils.getSetting('backup_custom_dir') != ''):
self.xbmc_vfs.set_root(utils.getSetting('backup_custom_dir'))
if(self.remote_vfs.exists(self.remote_vfs.root_path + "custom_1_" + self._createCRC(self.xbmc_vfs.root_path))):
#index files to restore
self.remote_vfs.set_root(self.remote_vfs.root_path + "custom_1_" + self._createCRC(self.xbmc_vfs.root_path))
fileManager.walkTree(self.remote_vfs.root_path)
self.filesTotal = self.filesTotal + fileManager.size()
allFiles.append({"source":self.remote_vfs.root_path,"dest":self.xbmc_vfs.root_path,"files":fileManager.getFiles()})
else:
xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30045),self.remote_vfs.root_path + "custom_1_" + self._createCRC(utils.getSetting('backup_custom_dir')))
#restore all the files
self.filesLeft = self.filesTotal
for fileGroup in allFiles:
self.remote_vfs.set_root(fileGroup['source'])
self.xbmc_vfs.set_root(fileGroup['dest'])
self.backupFiles(fileGroup['files'],self.remote_vfs,self.xbmc_vfs)
#call update addons to refresh everything #call update addons to refresh everything
xbmc.executebuiltin('UpdateLocalAddons') xbmc.executebuiltin('UpdateLocalAddons')
def writeFiles(self,fileList,source,dest): if(utils.getSetting('run_silent') == 'false' and not runSilent):
utils.log("Writing files to: " + dest.root_path) self.progressBar.close()
self.filesTotal = len(fileList)
self.filesLeft = self.filesTotal
#write each file from source to destination def backupFiles(self,fileList,source,dest):
utils.log("Writing files to: " + dest.root_path)
utils.log("Source: " + source.root_path)
for aFile in fileList: for aFile in fileList:
if(not self.checkCancel()): if(not self._checkCancel()):
utils.log('Writing file: ' + source.root_path + aFile,xbmc.LOGDEBUG) utils.log('Writing file: ' + aFile,xbmc.LOGDEBUG)
self.updateProgress(aFile) self._updateProgress(aFile)
if(aFile.startswith("-")): if(aFile.startswith("-")):
dest.mkdir(dest.root_path + aFile[1:]) dest.mkdir(dest.root_path + aFile[len(source.root_path) + 1:])
else: else:
if(isinstance(source,DropboxFileSystem)): if(isinstance(source,DropboxFileSystem)):
#if copying from dropbox we need the file handle, use get_file #if copying from dropbox we need the file handle, use get_file
source.get_file(source.root_path + aFile,dest.root_path + aFile) source.get_file(aFile,dest.root_path + aFile[len(source.root_path):])
else: else:
#copy using normal method #copy using normal method
dest.put(source.root_path + aFile,dest.root_path + aFile) dest.put(aFile,dest.root_path + aFile[len(source.root_path):])
def updateProgress(self,message=''): def _createCRC(self,string):
#create hash from string
string = string.lower()
bytes = bytearray(string.encode())
crc = 0xffffffff;
for b in bytes:
crc = crc ^ (b << 24)
for i in range(8):
if (crc & 0x80000000 ):
crc = (crc << 1) ^ 0x04C11DB7
else:
crc = crc << 1;
crc = crc & 0xFFFFFFFF
return '%08x' % crc
def _updateProgress(self,message=''):
self.filesLeft = self.filesLeft - 1 self.filesLeft = self.filesLeft - 1
#update the progress bar #update the progress bar
if(self.progressBar != None): if(self.progressBar != None):
self.progressBar.update(int((float(self.filesTotal - self.filesLeft)/float(self.filesTotal)) * 100),message) self.progressBar.update(int((float(self.filesTotal - self.filesLeft)/float(self.filesTotal)) * 100),message)
def checkCancel(self): def _checkCancel(self):
result = False result = False
if(self.progressBar != None): if(self.progressBar != None):
result = self.progressBar.iscanceled() result = self.progressBar.iscanceled()
return result return result
class FileManager:
fileArray = []
not_dir = ['.zip','.xsp','.rar']
vfs = None
def __init__(self,vfs):
self.vfs = vfs
def walkTree(self,directory):
dirs,files = self.vfs.listdir(directory)
#create all the subdirs first
for aDir in dirs:
dirPath = xbmc.translatePath(directory + "/" + aDir)
file_ext = aDir.split('.')[-1]
self.addFile("-" + dirPath)
#catch for "non directory" type files
if (not any(file_ext in s for s in self.not_dir)):
self.walkTree(dirPath)
#copy all the files
for aFile in files:
filePath = xbmc.translatePath(directory + "/" + aFile)
self.addFile(filePath)
def addFile(self,filename):
try:
filename = filename.decode('UTF-8')
except UnicodeDecodeError:
filename = filename.decode('ISO-8859-2')
#write the full remote path name of this file
utils.log("Add File: " + filename,xbmc.LOGDEBUG)
self.fileArray.append(filename)
def getFiles(self):
result = self.fileArray
self.fileArray = []
return result
def size(self):
return len(self.fileArray)

View File

@ -11,6 +11,9 @@ APP_SECRET = utils.getSetting('dropbox_secret')
class Vfs: class Vfs:
root_path = None root_path = None
def __init__(self,rootString):
self.set_root(rootString)
def set_root(self,rootString): def set_root(self,rootString):
old_root = self.root_path old_root = self.root_path
self.root_path = rootString self.root_path = rootString
@ -63,7 +66,11 @@ class XBMCFileSystem(Vfs):
class DropboxFileSystem(Vfs): class DropboxFileSystem(Vfs):
client = None client = None
def __init__(self): def __init__(self,rootString):
self.set_root(rootString)
self.setup()
def setup(self):
if(APP_KEY == '' or APP_SECRET == ''): if(APP_KEY == '' or APP_SECRET == ''):
xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30058),utils.getString(30059)) xbmcgui.Dialog().ok(utils.getString(30010),utils.getString(30058),utils.getString(30059))
return return
@ -95,7 +102,6 @@ class DropboxFileSystem(Vfs):
#this didn't work, delete the token file #this didn't work, delete the token file
self.deleteToken() self.deleteToken()
def listdir(self,directory): def listdir(self,directory):
if(self.client != None and self.exists(directory)): if(self.client != None and self.exists(directory)):
files = [] files = []
@ -114,6 +120,7 @@ class DropboxFileSystem(Vfs):
def mkdir(self,directory): def mkdir(self,directory):
directory = self._fix_slashes(directory)
if(self.client != None): if(self.client != None):
if(not self.exists(directory)): if(not self.exists(directory)):
self.client.file_create_folder(directory) self.client.file_create_folder(directory)
@ -122,12 +129,14 @@ class DropboxFileSystem(Vfs):
return False return False
def rmdir(self,directory): def rmdir(self,directory):
directory = self._fix_slashes(directory)
if(self.client != None and self.exists(directory)): if(self.client != None and self.exists(directory)):
self.client.file_delete(directory) self.client.file_delete(directory)
else: else:
return False return False
def exists(self,aFile): def exists(self,aFile):
aFile = self._fix_slashes(aFile)
if(self.client != None): if(self.client != None):
try: try:
meta_data = self.client.metadata(aFile) meta_data = self.client.metadata(aFile)
@ -139,6 +148,8 @@ class DropboxFileSystem(Vfs):
return False return False
def put(self,source,dest): def put(self,source,dest):
dest = self._fix_slashes(dest)
if(self.client != None): if(self.client != None):
f = open(source,'rb') f = open(source,'rb')
try: try:
@ -158,9 +169,13 @@ class DropboxFileSystem(Vfs):
f = self.client.get_file(source).read() f = self.client.get_file(source).read()
out.write(f) out.write(f)
out.close() out.close()
return True
else: else:
return False return False
def _fix_slashes(self,filename):
return filename.replace('\\','/')
def setToken(self,key,secret): def setToken(self,key,secret):
#write the token files #write the token files
token_file = open(xbmc.translatePath(utils.data_dir() + "tokens.txt"),'w') token_file = open(xbmc.translatePath(utils.data_dir() + "tokens.txt"),'w')

View File

@ -16,6 +16,7 @@
<setting id="backup_playlists" type="bool" label="30033" default="true" /> <setting id="backup_playlists" type="bool" label="30033" default="true" />
<setting id="backup_thumbnails" type="bool" label="30034" default="true" /> <setting id="backup_thumbnails" type="bool" label="30034" default="true" />
<setting id="backup_config" type="bool" label="30035" default="true" /> <setting id="backup_config" type="bool" label="30035" default="true" />
<setting id="backup_custom_dir" type="folder" label="Additional Directory" default="" />
</category> </category>
<category id="scheduling" label="30013"> <category id="scheduling" label="30013">
<setting id="enable_scheduler" type="bool" label="30060" default="false" /> <setting id="enable_scheduler" type="bool" label="30060" default="false" />