18 Commits

Author SHA1 Message Date
Rob Weber
d7e4946d9a fix travis link 2020-12-23 15:52:05 -06:00
Rob Weber
6fdaa4f253 fix syntax error 2020-12-23 15:51:38 -06:00
Rob Weber
5f1f9fef38 version bump 2020-12-23 15:44:32 -06:00
Rob Weber
4098cd18cb updated changelog.md 2020-12-18 09:32:19 -06:00
Rob Weber
8119a09449 fix oauth import 2020-12-18 09:31:52 -06:00
Rob Weber
a0ccd85d9e part of #174, fixes ok() method def change 2020-12-18 09:28:17 -06:00
Rob
71c8d9ae54 ui settings restore upgrade
* added ability to export/save settings as json using GetSettings

* added generic copyFile method instead of duplicating

* copy and load settings file after file restore (right now only reads)

* set settings values from backup when differ than current

* store settings as part of validation file

* prompt for settings restore or set always via toggle

* unused import

* added new strings for settings restore

* updated changelog

* fix pep8 syntax

* swap setting to always prompt instead of always restore (invert)
2020-12-03 14:08:25 -06:00
Rob Weber
b470412b4f removed unused imports 2020-11-18 14:28:09 -06:00
Rob Weber
7a5886cd26 beta version, updated news 2020-11-18 14:10:22 -06:00
Rob Weber
f20887b6e7 update travis CI badge 2020-11-18 14:09:22 -06:00
Rob Weber
a0eb28a5f6 convert xbmc.translatePath to xbmcvfs.translatePath 2020-11-18 14:07:06 -06:00
Rob Weber
a198c9448a update future module 2020-11-17 19:56:15 -06:00
Rob Weber
fa3a30eb55 added flake8 pollyfill dep 2020-11-17 12:55:05 -06:00
Rob Weber
201d04afeb updated version number 2020-11-17 09:54:14 -06:00
Rob Weber
2dabb23c2d Merge branch 'matrix'
# Conflicts:
#	README.md
2020-11-17 09:52:39 -06:00
Rob Weber
2f19ec2b75 added download stats to README.md 2020-06-18 15:37:12 -05:00
Rob Weber
db215873cf updated badge path 2020-06-17 13:51:49 -05:00
Rob Weber
bd963719d4 updated badge path 2020-06-17 13:51:00 -05:00
14 changed files with 187 additions and 166 deletions

View File

@@ -3,7 +3,7 @@ language: python
python: 3.7 python: 3.7
install: install:
- pip install flake8 kodi-addon-checker git+https://github.com/romanvm/kodi-addon-submitter.git - pip install flake8 flake8_polyfill kodi-addon-checker git+https://github.com/romanvm/kodi-addon-submitter.git
before_script: before_script:
- git config core.quotepath false - git config core.quotepath false

View File

@@ -1,5 +1,5 @@
# Backup Addon # Backup Addon
![Kodi Version](https://img.shields.io/endpoint?url=https%3A%2F%2Fweberjr.com%2Fkodi-shield%2Frobweber%2Fxbmcbackup%2Fmaster%2Ftrue%2Ftrue) [![Build Status](https://img.shields.io/travis/robweber/xbmcbackup/matrix)](https://travis-ci.org/robweber/xbmcbackup) [![License](https://img.shields.io/github/license/robweber/xbmcbackup)](https://github.com/robweber/xbmcbackup/blob/master/LICENSE.txt) [![PEP8](https://img.shields.io/badge/code%20style-pep8-orange.svg)](https://www.python.org/dev/peps/pep-0008/) ![Kodi Version](https://img.shields.io/endpoint?url=https%3A%2F%2Fweberjr.com%2Fkodi-shield%2Fversion%2Frobweber%2Fxbmcbackup%2Fmatrix%2Ftrue%2Ftrue) ![Total Downloads](https://img.shields.io/endpoint?url=https%3A%2F%2Fweberjr.com%2Fkodi-shield%2Fdownloads%2Fmatrix%2Fscript.xbmcbackup%2F1.6.4) [![Build Status](https://img.shields.io/travis/com/robweber/xbmcbackup/matrix)](https://travis-ci.com/robweber/xbmcbackup) [![License](https://img.shields.io/github/license/robweber/xbmcbackup)](https://github.com/robweber/xbmcbackup/blob/master/LICENSE.txt) [![PEP8](https://img.shields.io/badge/code%20style-pep8-orange.svg)](https://www.python.org/dev/peps/pep-0008/)
## About ## About

View File

@@ -1,15 +1,15 @@
<?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="Backup" version="1.6.3" provider-name="robweber"> name="Backup" version="1.6.4" provider-name="robweber">
<requires> <requires>
<import addon="xbmc.python" version="3.0.0"/> <import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.8.0" /> <import addon="script.module.dateutil" version="2.8.0" />
<import addon="script.module.future" version="0.16.0.4"/> <import addon="script.module.future" version="0.18.2+matrix.1" />
<import addon="script.module.dropbox" version="9.4.0"/> <import addon="script.module.dropbox" version="9.4.0" />
</requires> </requires>
<extension point="xbmc.python.script" library="default.py"> <extension point="xbmc.python.script" library="default.py">
<provides>executable</provides> <provides>executable</provides>
</extension> </extension>
<extension point="xbmc.service" library="service.py" /> <extension point="xbmc.service" library="service.py" />
<extension point="xbmc.addon.metadata"> <extension point="xbmc.addon.metadata">
<summary lang="ar_SA">إنسخ إحتياطياً قاعده بيانات إكس بى إم سى وملفات اﻹعدادات فى حاله وقوع إنهيار مع إمكانيه اﻹسترجاع</summary> <summary lang="ar_SA">إنسخ إحتياطياً قاعده بيانات إكس بى إم سى وملفات اﻹعدادات فى حاله وقوع إنهيار مع إمكانيه اﻹسترجاع</summary>
@@ -89,14 +89,11 @@
<screenshot>resources/images/screenshot3.jpg</screenshot> <screenshot>resources/images/screenshot3.jpg</screenshot>
<screenshot>resources/images/screenshot4.jpg</screenshot> <screenshot>resources/images/screenshot4.jpg</screenshot>
</assets> </assets>
<news>Version 1.6.3 <news>Version 1.6.4
- fixed validatePath error (issue #166) - updated deprecated Kodi python methods
Version 1.6.2 - added better system settings/restore functionality (enabled by default)
- replaced PNG screenshots with JPG - fixed Dropbox oauth import
Version 1.6.1 - fixed xbmcgui.Dialog().ok() parameter list
- added file transfer size to progress bar
- progress bar now based on transfer size, not total file count
- fixed rotate backups error - thanks @AnonTester
</news> </news>
</extension> </extension>
</addon> </addon>

View File

@@ -4,6 +4,28 @@ 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/) The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## [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
### Changed
- updated script.module.future version to current
- swapped xbmc.translatePath for xbmcvfs.translatePath, deprecated
### Fixed
- fixed calls to ```xbmcgui.Dialog().ok()```, method definition changed to only allow one message arg with Kodi 19
- fixed import of dropbox Oauth package in authorizer flow
### Removed
- removed old xml GuiSettings parsing for settings restore
## [Version 1.6.3](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.2...robweber:matrix-1.6.3) - 2020-06-15 ## [Version 1.6.3](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.2...robweber:matrix-1.6.3) - 2020-06-15
### Changed ### Changed
@@ -48,7 +70,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- addon.xml updated to use Leia specific syntax and library imports - addon.xml updated to use Leia specific syntax and library imports
- removed specific encode() calls per Python2/3 compatibility - removed specific encode() calls per Python2/3 compatibility
- call isdigit() method on the string directly instead of str.isdigit() (results in unicode error) - call isdigit() method on the string directly instead of str.isdigit() (results in unicode error)
- added flake8 testing to travis-ci - added flake8 testing to travis-ci
- updated code to make python3 compatible - updated code to make python3 compatible
- updated code for pep9 styling - updated code for pep9 styling
- use setArt() to set ListItem icons as the icon= constructor is deprecated - use setArt() to set ListItem icons as the icon= constructor is deprecated
@@ -66,16 +88,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Updated Changelog format to the one suggested by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) - Updated Changelog format to the one suggested by [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
- Added script.module.dropbox import as a dependency for Dropbox filesystem - Added script.module.dropbox import as a dependency for Dropbox filesystem
### Changed ### Changed
- Fixed issue getting xbmcbackup.val file from non-zipped remote directories. Was being copied as though it was a local file so it was failing. - Fixed issue getting xbmcbackup.val file from non-zipped remote directories. Was being copied as though it was a local file so it was failing.
- Use linux path separator (/) all the time, Kodi will interpret this correctly on windows. Was causing issues with remote file systems since os.path.sep - Use linux path separator (/) all the time, Kodi will interpret this correctly on windows. Was causing issues with remote file systems since os.path.sep
- Fixed minor python code style changes based on kodi-addon-checker output - Fixed minor python code style changes based on kodi-addon-checker output
### Removed ### Removed
- files releated to dropbox library, using script.module.dropbox import now - files releated to dropbox library, using script.module.dropbox import now
## Version 1.5.1 - 2019-09-10 ## Version 1.5.1 - 2019-09-10
@@ -85,7 +107,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## Version 1.5.0 - 2019-08-26 ## Version 1.5.0 - 2019-08-26
### Added ### Added
- Added new Advanced file editor and file selection based on a .json - Added new Advanced file editor and file selection based on a .json
### Removed ### Removed
- File backups and restores will not work with old version - breaking change with previous versions PR117 - File backups and restores will not work with old version - breaking change with previous versions PR117
@@ -95,7 +117,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added ### Added
- added file chunk support for Dropbox uploads - added file chunk support for Dropbox uploads
- added scheduler delay to assist with time sync (rpi mostly), will delay startup by 2 min - added scheduler delay to assist with time sync (rpi mostly), will delay startup by 2 min
### Changed ### Changed
- fixed settings duplicate ids, thanks aster-anto - fixed settings duplicate ids, thanks aster-anto
@@ -107,7 +129,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## Version 1.1.1 ## Version 1.1.1
### Added ### Added
- added ability to "catchup" on missed scheduled backup - added ability to "catchup" on missed scheduled backup
### Changed ### Changed
- fixed error on authorizers (missing secret/key) - fixed error on authorizers (missing secret/key)
@@ -118,10 +140,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added ### Added
- added tinyurl generation for oauth urls - added tinyurl generation for oauth urls
### Changed ### Changed
- moved authorize to settings area for cloud storage - moved authorize to settings area for cloud storage
## Version 1.0.9 ## Version 1.0.9
### Changed ### Changed
@@ -142,7 +164,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
### Added ### Added
- added progress for zip extraction - hopefully helps with extract errors - added progress for zip extraction - hopefully helps with extract errors
### Changed ### Changed
- fix for custom directories not working recursively - fix for custom directories not working recursively
@@ -282,7 +304,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
## Version 0.3.9 ## Version 0.3.9
- added "just once" scheduler for one-off type backups - added "just once" scheduler for one-off type backups
- show notification on scheduler - show notification on scheduler
- update updated language files from Transifex - update updated language files from Transifex

View File

@@ -1,6 +1,5 @@
# launcher for various helpful functions found in the settings.xml area # launcher for various helpful functions found in the settings.xml area
import sys import sys
import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
import resources.lib.utils as utils import resources.lib.utils as utils
@@ -14,9 +13,9 @@ def authorize_cloud(cloudProvider):
authorizer = DropboxAuthorizer() authorizer = DropboxAuthorizer()
if(authorizer.authorize()): if(authorizer.authorize()):
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30027) + ' ' + utils.getString(30106)) xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30027), utils.getString(30106)))
else: else:
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30107) + ' ' + utils.getString(30027)) xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30107), utils.getString(30027)))
def remove_auth(): def remove_auth():
@@ -25,8 +24,8 @@ def remove_auth():
if(shouldDelete): if(shouldDelete):
# delete any of the known token file types # delete any of the known token file types
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "tokens.txt")) # dropbox xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt")) # dropbox
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "google_drive.dat")) # google drive xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "google_drive.dat")) # google drive
def get_params(): def get_params():

View File

@@ -581,3 +581,14 @@ msgctxt "#30147"
msgid "Toggle Sub Folders" msgid "Toggle Sub Folders"
msgstr "" msgstr ""
msgctxt "#30148"
msgid "Ask before restoring Kodi UI settings"
msgstr ""
msgctxt "#30149"
msgid "Restore Kodi UI Settings"
msgstr ""
msgctxt "#30150"
msgid "Restore saved Kodi system settings from backup?"
msgstr ""

View File

@@ -1,5 +1,4 @@
import json import json
import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
import os.path import os.path
@@ -7,7 +6,7 @@ from . import utils as utils
class BackupSetManager: class BackupSetManager:
jsonFile = xbmc.translatePath(utils.data_dir() + "custom_paths.json") jsonFile = xbmcvfs.translatePath(utils.data_dir() + "custom_paths.json")
paths = None paths = None
def __init__(self): def __init__(self):
@@ -106,7 +105,7 @@ class AdvancedBackupEditor:
rootFolder = rootFolder + '/' rootFolder = rootFolder + '/'
# check that this path even exists # check that this path even exists
if(not xbmcvfs.exists(xbmc.translatePath(rootFolder))): if(not xbmcvfs.exists(xbmcvfs.translatePath(rootFolder))):
self.dialog.ok(utils.getString(30117), utils.getString(30118), rootFolder) self.dialog.ok(utils.getString(30117), utils.getString(30118), rootFolder)
return None return None
else: else:
@@ -227,7 +226,7 @@ class AdvancedBackupEditor:
shouldContinue = self.dialog.yesno(utils.getString(30139), utils.getString(30140), utils.getString(30141)) shouldContinue = self.dialog.yesno(utils.getString(30139), utils.getString(30140), utils.getString(30141))
if(shouldContinue): if(shouldContinue):
source = xbmc.translatePath(os.path.join(utils.addon_dir(), 'resources', 'data', 'default_files.json')) source = xbmcvfs.translatePath(os.path.join(utils.addon_dir(), 'resources', 'data', 'default_files.json'))
dest = xbmc.translatePath(os.path.join(utils.data_dir(), 'custom_paths.json')) dest = xbmcvfs.translatePath(os.path.join(utils.data_dir(), 'custom_paths.json'))
xbmcvfs.copy(source, dest) xbmcvfs.copy(source, dest)

View File

@@ -1,4 +1,3 @@
import xbmc
import xbmcgui import xbmcgui
import xbmcvfs import xbmcvfs
import resources.lib.tinyurl as tinyurl import resources.lib.tinyurl as tinyurl
@@ -7,6 +6,7 @@ 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: try:
from dropbox import dropbox from dropbox import dropbox
from dropbox import oauth
except ImportError: except ImportError:
pass pass
@@ -24,7 +24,7 @@ class DropboxAuthorizer:
if(self.APP_KEY == '' and self.APP_SECRET == ''): 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)) xbmcgui.Dialog().ok(utils.getString(30010), '%s %s\n%s' % (utils.getString(30027), utils.getString(30058), utils.getString(30059)))
result = False result = False
@@ -46,13 +46,13 @@ class DropboxAuthorizer:
self._deleteToken() 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) flow = oauth.DropboxOAuth2FlowNoRedirect(self.APP_KEY, self.APP_SECRET)
url = flow.start() url = flow.start()
# print url in log # print url in log
utils.log("Authorize URL: " + url) utils.log("Authorize URL: " + url)
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30056), utils.getString(30057), tinyurl.shorten(url)) xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s\n%s' % (utils.getString(30056), utils.getString(30057), str(tinyurl.shorten(url), 'utf-8')))
# get the auth code # get the auth code
code = xbmcgui.Dialog().input(utils.getString(30027) + ' ' + utils.getString(30103)) code = xbmcgui.Dialog().input(utils.getString(30027) + ' ' + utils.getString(30103))
@@ -89,14 +89,14 @@ class DropboxAuthorizer:
def _setToken(self, token): 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 = open(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt"), 'w')
token_file.write(token) token_file.write(token)
token_file.close() token_file.close()
def _getToken(self): def _getToken(self):
# get token, if it exists # get token, if it exists
if(xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + "tokens.txt"))): if(xbmcvfs.exists(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt"))):
token_file = open(xbmc.translatePath(utils.data_dir() + "tokens.txt")) token_file = open(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt"))
token = token_file.read() token = token_file.read()
token_file.close() token_file.close()
@@ -105,5 +105,5 @@ class DropboxAuthorizer:
return "" return ""
def _deleteToken(self): def _deleteToken(self):
if(xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + "tokens.txt"))): if(xbmcvfs.exists(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt"))):
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "tokens.txt")) xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt"))

View File

@@ -47,7 +47,7 @@ class XbmcBackup:
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): def __init__(self):
self.xbmc_vfs = XBMCFileSystem(xbmc.translatePath('special://home')) self.xbmc_vfs = XBMCFileSystem(xbmcvfs.translatePath('special://home'))
self.configureRemote() self.configureRemote()
utils.log(utils.getString(30046)) utils.log(utils.getString(30046))
@@ -165,7 +165,7 @@ class XbmcBackup:
# backup all the files # backup all the files
self.transferLeft = self.transferSize self.transferLeft = self.transferSize
for fileGroup in allFiles: for fileGroup in allFiles:
self.xbmc_vfs.set_root(xbmc.translatePath(fileGroup['source'])) self.xbmc_vfs.set_root(xbmcvfs.translatePath(fileGroup['source']))
self.remote_vfs.set_root(fileGroup['dest'] + fileGroup['name']) self.remote_vfs.set_root(fileGroup['dest'] + fileGroup['name'])
filesCopied = self._copyFiles(fileGroup['files'], self.xbmc_vfs, self.remote_vfs) filesCopied = self._copyFiles(fileGroup['files'], self.xbmc_vfs, self.remote_vfs)
@@ -183,11 +183,11 @@ class XbmcBackup:
# 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" zip_name = self.remote_vfs.root_path[:-1] + ".zip"
self.remote_vfs.cleanup() self.remote_vfs.cleanup()
self.xbmc_vfs.rename(xbmc.translatePath("special://temp/xbmc_backup_temp.zip"), xbmc.translatePath("special://temp/" + zip_name)) self.xbmc_vfs.rename(xbmcvfs.translatePath("special://temp/xbmc_backup_temp.zip"), xbmcvfs.translatePath("special://temp/" + zip_name))
fileManager.addFile(xbmc.translatePath("special://temp/" + zip_name)) fileManager.addFile(xbmcvfs.translatePath("special://temp/" + zip_name))
# set root to data dir home and reset remote # set root to data dir home and reset remote
self.xbmc_vfs.set_root(xbmc.translatePath("special://temp/")) self.xbmc_vfs.set_root(xbmcvfs.translatePath("special://temp/"))
self.remote_vfs = self.saved_remote_vfs self.remote_vfs = self.saved_remote_vfs
# update the amount to transfer # update the amount to transfer
@@ -197,10 +197,10 @@ class XbmcBackup:
if(not fileCopied): 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)) shouldContinue = xbmcgui.Dialog().ok(utils.getString(30089), '%s\n%s' % (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)) self.xbmc_vfs.rmfile(xbmcvfs.translatePath("special://temp/" + zip_name))
# remove old backups # remove old backups
self._rotateBackups() self._rotateBackups()
@@ -220,9 +220,9 @@ class XbmcBackup:
utils.log("copying zip file: " + self.restore_point) 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/")) self.xbmc_vfs.set_root(xbmcvfs.translatePath("special://temp/"))
if(not self.xbmc_vfs.exists(xbmc.translatePath("special://temp/" + self.restore_point))): if(not self.xbmc_vfs.exists(xbmcvfs.translatePath("special://temp/" + self.restore_point))):
# copy just this file from the remote vfs # copy just this file from the remote vfs
self.transferSize = self.remote_vfs.fileSize(self.remote_base_path + self.restore_point) self.transferSize = self.remote_vfs.fileSize(self.remote_base_path + self.restore_point)
zipFile = [] zipFile = []
@@ -235,13 +235,13 @@ class XbmcBackup:
utils.log("zip file exists already") 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') zip_vfs = ZipFileSystem(xbmcvfs.translatePath("special://temp/" + self.restore_point), 'r')
extractor = ZipExtractor() extractor = ZipExtractor()
if(not extractor.extract(zip_vfs, xbmc.translatePath("special://temp/"), self.progressBar)): if(not extractor.extract(zip_vfs, xbmcvfs.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() zip_vfs.cleanup()
self.xbmc_vfs.rmfile(xbmc.translatePath("special://temp/" + self.restore_point)) self.xbmc_vfs.rmfile(xbmcvfs.translatePath("special://temp/" + self.restore_point))
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30101)) xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30101))
return return
@@ -250,12 +250,12 @@ class XbmcBackup:
self.progressBar.updateProgress(0, utils.getString(30049) + "......") 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.remote_vfs = XBMCFileSystem(xbmcvfs.translatePath("special://temp/" + self.restore_point.split(".")[0] + "/"))
self.xbmc_vfs.set_root(xbmc.translatePath("special://home/")) self.xbmc_vfs.set_root(xbmcvfs.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)): 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) xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s' % (utils.getString(30045), self.remote_vfs.root_path))
return return
valFile = self._checkValidationFile(self.remote_vfs.root_path) valFile = self._checkValidationFile(self.remote_vfs.root_path)
@@ -284,6 +284,12 @@ class XbmcBackup:
xbmcgui.Dialog().ok(utils.getString(30077), utils.getString(30078)) xbmcgui.Dialog().ok(utils.getString(30077), utils.getString(30078))
return return
# check if settings should be restored from this backup
restoreSettings = not utils.getSettingBool('always_prompt_restore_settings')
if(not restoreSettings and 'system_settings' in valFile):
# prompt the user to restore settings yes/no
restoreSettings = xbmcgui.Dialog().yesno(utils.getString(30149), utils.getString(30150))
# 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']] restoreSets = [n['name'] for n in valFile['directories']]
@@ -294,13 +300,14 @@ class XbmcBackup:
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 is not None): if(selectedSets is not 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: for index in selectedSets:
# add this directory # add this directory
aDir = valFile['directories'][index] aDir = valFile['directories'][index]
self.xbmc_vfs.set_root(xbmc.translatePath(aDir['path'])) self.xbmc_vfs.set_root(xbmcvfs.translatePath(aDir['path']))
if(self.remote_vfs.exists(self.remote_vfs.root_path + aDir['name'] + '/')): 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'] + '/') fileManager.walkTree(self.remote_vfs.root_path + aDir['name'] + '/')
@@ -309,7 +316,7 @@ class XbmcBackup:
allFiles.append({"source": self.remote_vfs.root_path + aDir['name'], "dest": self.xbmc_vfs.root_path, "files": fileManager.getFiles()}) allFiles.append({"source": self.remote_vfs.root_path + aDir['name'], "dest": self.xbmc_vfs.root_path, "files": fileManager.getFiles()})
else: else:
utils.log("error path not found: " + self.remote_vfs.root_path + aDir['name']) 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']) xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s' % (utils.getString(30045), self.remote_vfs.root_path + aDir['name']))
# restore all the files # restore all the files
self.transferLeft = self.transferSize self.transferLeft = self.transferSize
@@ -318,17 +325,19 @@ class XbmcBackup:
self.xbmc_vfs.set_root(fileGroup['dest']) self.xbmc_vfs.set_root(fileGroup['dest'])
self._copyFiles(fileGroup['files'], self.remote_vfs, self.xbmc_vfs) self._copyFiles(fileGroup['files'], self.remote_vfs, self.xbmc_vfs)
# update the Kodi settings - if we can
if('system_settings' in valFile and restoreSettings):
self.progressBar.updateProgress(98, "Restoring Kodi settings")
gui_settings = GuiSettingsManager()
gui_settings.restore(valFile['system_settings'])
self.progressBar.updateProgress(99, "Clean up operations .....") self.progressBar.updateProgress(99, "Clean up operations .....")
if(self.restore_point.split('.')[-1] == 'zip'): 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.rmfile(xbmcvfs.translatePath("special://temp/" + self.restore_point))
self.xbmc_vfs.rmdir(self.remote_vfs.root_path) self.xbmc_vfs.rmdir(self.remote_vfs.root_path)
# 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') xbmc.executebuiltin('UpdateLocalAddons')
@@ -342,15 +351,15 @@ class XbmcBackup:
if(mode == self.Backup and self.remote_vfs.root_path != ''): if(mode == self.Backup and self.remote_vfs.root_path != ''):
if(utils.getSettingBool("compress_backups")): if(utils.getSettingBool("compress_backups")):
# delete old temp file # delete old temp file
if(self.xbmc_vfs.exists(xbmc.translatePath('special://temp/xbmc_backup_temp.zip'))): if(self.xbmc_vfs.exists(xbmcvfs.translatePath('special://temp/xbmc_backup_temp.zip'))):
if(not self.xbmc_vfs.rmfile(xbmc.translatePath('special://temp/xbmc_backup_temp.zip'))): if(not self.xbmc_vfs.rmfile(xbmcvfs.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)) xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s' % (utils.getString(30096), utils.getString(30097)))
return False 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.saved_remote_vfs = self.remote_vfs
self.remote_vfs = ZipFileSystem(xbmc.translatePath("special://temp/xbmc_backup_temp.zip"), "w") self.remote_vfs = ZipFileSystem(xbmcvfs.translatePath("special://temp/xbmc_backup_temp.zip"), "w")
self.remote_vfs.set_root(self.remote_vfs.root_path + time.strftime("%Y%m%d%H%M") + "/") 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) progressBarTitle = progressBarTitle + utils.getString(30023) + ": " + utils.getString(30016)
@@ -404,14 +413,8 @@ class XbmcBackup:
self._updateProgress('%s remaining, writing %s' % (utils.diskString(self.transferLeft), os.path.basename(aFile['file'][len(source.root_path):]))) self._updateProgress('%s remaining, writing %s' % (utils.diskString(self.transferLeft), os.path.basename(aFile['file'][len(source.root_path):])))
self.transferLeft = self.transferLeft - aFile['size'] self.transferLeft = self.transferLeft - aFile['size']
wroteFile = True # copy the file
destFile = dest.root_path + aFile['file'][len(source.root_path):] wroteFile = self._copyFile(source, dest, aFile['file'], dest.root_path + aFile['file'][len(source.root_path):])
if(isinstance(source, DropboxFileSystem)):
# if copying from cloud storage we need the file handle, use get_file
wroteFile = source.get_file(aFile['file'], destFile)
else:
# copy using normal method
wroteFile = dest.put(aFile['file'], destFile)
# if result is still true but this file failed # if result is still true but this file failed
if(not wroteFile and result): if(not wroteFile and result):
@@ -419,11 +422,23 @@ class XbmcBackup:
return result return result
def _copyFile(self, source, dest, sourceFile, destFile):
result = True
if(isinstance(source, DropboxFileSystem)):
# if copying from cloud storage we need the file handle, use get_file
result = source.get_file(sourceFile, destFile)
else:
# copy using normal method
result = dest.put(sourceFile, destFile)
return result
def _addBackupDir(self, folder_name, root_path, dirList): def _addBackupDir(self, folder_name, root_path, dirList):
utils.log('Backup set: ' + folder_name) utils.log('Backup set: ' + folder_name)
fileManager = FileManager(self.xbmc_vfs) fileManager = FileManager(self.xbmc_vfs)
self.xbmc_vfs.set_root(xbmc.translatePath(root_path)) self.xbmc_vfs.set_root(xbmcvfs.translatePath(root_path))
for aDir in dirList: for aDir in dirList:
fileManager.addDir(aDir) fileManager.addDir(aDir)
@@ -472,30 +487,35 @@ class XbmcBackup:
remove_num = remove_num + 1 remove_num = remove_num + 1
def _createValidationFile(self, dirList): def _createValidationFile(self, dirList):
valInfo = {"name": "XBMC Backup Validation File", "xbmc_version": xbmc.getInfoLabel('System.BuildVersion'), "type": 0} valInfo = {"name": "XBMC Backup Validation File", "xbmc_version": xbmc.getInfoLabel('System.BuildVersion'), "type": 0, "system_settings": []}
valDirs = [] valDirs = []
# save list of file sets
for aDir in dirList: for aDir in dirList:
valDirs.append({"name": aDir['name'], "path": aDir['source']}) valDirs.append({"name": aDir['name'], "path": aDir['source']})
valInfo['directories'] = valDirs valInfo['directories'] = valDirs
vFile = xbmcvfs.File(xbmc.translatePath(utils.data_dir() + "xbmcbackup.val"), 'w') # dump all current Kodi settings
gui_settings = GuiSettingsManager()
valInfo['system_settings'] = gui_settings.backup()
vFile = xbmcvfs.File(xbmcvfs.translatePath(utils.data_dir() + "xbmcbackup.val"), 'w')
vFile.write(json.dumps(valInfo)) vFile.write(json.dumps(valInfo))
vFile.write("") vFile.write("")
vFile.close() vFile.close()
success = self.remote_vfs.put(xbmc.translatePath(utils.data_dir() + "xbmcbackup.val"), self.remote_vfs.root_path + "xbmcbackup.val") success = self._copyFile(self.xbmc_vfs, self.remote_vfs, xbmcvfs.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")) xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "xbmcbackup.val"))
if(success): 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"))): if(not xbmcvfs.exists(xbmcvfs.translatePath(utils.data_dir() + ".nomedia"))):
nmFile = xbmcvfs.File(xbmc.translatePath(utils.data_dir() + ".nomedia"), 'w') nmFile = xbmcvfs.File(xbmcvfs.translatePath(utils.data_dir() + ".nomedia"), 'w')
nmFile.close() nmFile.close()
success = self.remote_vfs.put(xbmc.translatePath(utils.data_dir() + ".nomedia"), self.remote_vfs.root_path + ".nomedia") success = self._copyFile(self.xbmc_vfs, self.remote_vfs, xbmcvfs.translatePath(utils.data_dir() + ".nomedia"), self.remote_vfs.root_path + ".nomedia")
return success return success
@@ -503,16 +523,13 @@ class XbmcBackup:
result = None result = None
# copy the file and open it # copy the file and open it
if(isinstance(self.remote_vfs, DropboxFileSystem)): self._copyFile(self.remote_vfs, self.xbmc_vfs, path + "xbmcbackup.val", xbmcvfs.translatePath(utils.data_dir() + "xbmcbackup_restore.val"))
self.remote_vfs.get_file(path + "xbmcbackup.val", xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val"))
else:
self.xbmc_vfs.put(path + "xbmcbackup.val", xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val"))
with xbmcvfs.File(xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val"), 'r') as vFile: with xbmcvfs.File(xbmcvfs.translatePath(utils.data_dir() + "xbmcbackup_restore.val"), 'r') as vFile:
jsonString = vFile.read() jsonString = vFile.read()
# delete after checking # delete after checking
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "xbmcbackup_restore.val")) xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "xbmcbackup_restore.val"))
try: try:
result = json.loads(jsonString) result = json.loads(jsonString)
@@ -530,11 +547,11 @@ class XbmcBackup:
return result return result
def _createResumeBackupFile(self): def _createResumeBackupFile(self):
with xbmcvfs.File(xbmc.translatePath(utils.data_dir() + "resume.txt"), 'w') as f: with xbmcvfs.File(xbmcvfs.translatePath(utils.data_dir() + "resume.txt"), 'w') as f:
f.write(self.restore_point) f.write(self.restore_point)
def _readBackupConfig(self, aFile): def _readBackupConfig(self, aFile):
with xbmcvfs.File(xbmc.translatePath(aFile), 'r') as f: with xbmcvfs.File(xbmcvfs.translatePath(aFile), 'r') as f:
jsonString = f.read() jsonString = f.read()
return json.loads(jsonString) return json.loads(jsonString)
@@ -555,8 +572,8 @@ class FileManager:
def walk(self): def walk(self):
for aDir in self.root_dirs: for aDir in self.root_dirs:
self.addFile('-' + xbmc.translatePath(aDir['path'])) self.addFile('-' + xbmcvfs.translatePath(aDir['path']))
self.walkTree(xbmc.translatePath(aDir['path']), aDir['recurse']) self.walkTree(xbmcvfs.translatePath(aDir['path']), aDir['recurse'])
def walkTree(self, directory, recurse=True): def walkTree(self, directory, recurse=True):
if(utils.getSettingBool('verbose_logging')): if(utils.getSettingBool('verbose_logging')):
@@ -571,7 +588,7 @@ class FileManager:
if(recurse): if(recurse):
# create all the subdirs first # create all the subdirs first
for aDir in dirs: for aDir in dirs:
dirPath = xbmcvfs.validatePath(xbmc.translatePath(directory + self.pathSep + aDir)) dirPath = xbmcvfs.validatePath(xbmcvfs.translatePath(directory + self.pathSep + aDir))
file_ext = aDir.split('.')[-1] file_ext = aDir.split('.')[-1]
# check if directory is excluded # check if directory is excluded
@@ -591,14 +608,14 @@ class FileManager:
# copy all the files # copy all the files
for aFile in files: for aFile in files:
filePath = xbmc.translatePath(directory + self.pathSep + aFile) filePath = xbmcvfs.translatePath(directory + self.pathSep + aFile)
self.addFile(filePath) self.addFile(filePath)
def addDir(self, dirMeta): def addDir(self, dirMeta):
if(dirMeta['type'] == 'include'): if(dirMeta['type'] == 'include'):
self.root_dirs.append({'path': dirMeta['path'], 'recurse': dirMeta['recurse']}) self.root_dirs.append({'path': dirMeta['path'], 'recurse': dirMeta['recurse']})
else: else:
self.excludeFile(xbmc.translatePath(dirMeta['path'])) self.excludeFile(xbmcvfs.translatePath(dirMeta['path']))
def addFile(self, filename): def addFile(self, filename):
# write the full remote path name of this file # write the full remote path name of this file

View File

@@ -1,72 +1,47 @@
import json import json
import xbmc import xbmc
import xbmcvfs
from . import utils as utils from . import utils as utils
from xml.dom import minidom
from xml.parsers.expat import ExpatError
class GuiSettingsManager: class GuiSettingsManager:
doc = None filename = 'kodi_settings.json'
systemSettings = None
def __init__(self): def __init__(self):
# first make a copy of the file # get all of the current Kodi settings
xbmcvfs.copy(xbmc.translatePath('special://home/userdata/guisettings.xml'), xbmc.translatePath("special://home/userdata/guisettings.xml.restored")) json_response = json.loads(xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettings","params":{"level":"expert"}}'))
# read in the copy self.systemSettings = json_response['result']['settings']
self._readFile(xbmc.translatePath('special://home/userdata/guisettings.xml.restored'))
def run(self): def backup(self):
# get a list of all the settings we can manipulate via json utils.log('Backing up Kodi settings')
json_response = json.loads(xbmc.executeJSONRPC('{"jsonrpc":"2.0", "id":1, "method":"Settings.GetSettings","params":{"level":"advanced"}}'))
settings = json_response['result']['settings'] # return all current settings
currentSettings = {} return self.systemSettings
for aSetting in settings: def restore(self, restoreSettings):
if('value' in aSetting): utils.log('Restoring Kodi settings')
currentSettings[aSetting['id']] = aSetting['value']
# parse the existing xml file and get all the settings we need to restore updateJson = {"jsonrpc": "2.0", "id": 1, "method": "Settings.SetSettingValue", "params": {"setting": "", "value": ""}}
restoreSettings = self.__parseNodes(self.doc.getElementsByTagName('setting'))
# get a list where the restore setting value != the current value # create a setting=value dict of the current settings
updateSettings = {k: v for k, v in list(restoreSettings.items()) if (k in currentSettings and currentSettings[k] != v)} settingsDict = {}
for aSetting in self.systemSettings:
# ignore action types, no value
if(aSetting['type'] != 'action'):
settingsDict[aSetting['id']] = aSetting['value']
# go through all the found settings and update them restoreCount = 0
jsonObj = {"jsonrpc": "2.0", "id": 1, "method": "Settings.SetSettingValue", "params": {"setting": "", "value": ""}} for aSetting in restoreSettings:
for anId, aValue in list(updateSettings.items()): # only update a setting if its different than the current (action types have no value)
utils.log("updating: " + anId + ", value: " + str(aValue)) if(aSetting['type'] != 'action' and settingsDict[aSetting['id']] != aSetting['value']):
if(utils.getSettingBool('verbose_logging')):
utils.log('%s different than current: %s' % (aSetting['id'], str(aSetting['value'])))
jsonObj['params']['setting'] = anId updateJson['params']['setting'] = aSetting['id']
jsonObj['params']['value'] = aValue updateJson['params']['value'] = aSetting['value']
xbmc.executeJSONRPC(json.dumps(jsonObj)) xbmc.executeJSONRPC(json.dumps(updateJson))
restoreCount = restoreCount + 1
def __parseNodes(self, nodeList): utils.log('Update %d settings' % restoreCount)
result = {}
for node in nodeList:
nodeValue = ''
if(node.firstChild is not None):
nodeValue = node.firstChild.nodeValue
# check for numbers and booleans
if(nodeValue.isdigit()):
nodeValue = int(nodeValue)
elif(nodeValue == 'true'):
nodeValue = True
elif(nodeValue == 'false'):
nodeValue = False
result[node.getAttribute('id')] = nodeValue
return result
def _readFile(self, fileLoc):
if(xbmcvfs.exists(fileLoc)):
try:
self.doc = minidom.parse(fileLoc)
except ExpatError:
utils.log("Can't read " + fileLoc)

View File

@@ -20,7 +20,7 @@ class BackupScheduler:
def __init__(self): def __init__(self):
self.monitor = UpdateMonitor(update_method=self.settingsChanged) self.monitor = UpdateMonitor(update_method=self.settingsChanged)
self.enabled = utils.getSettingBool("enable_scheduler") self.enabled = utils.getSettingBool("enable_scheduler")
self.next_run_path = xbmc.translatePath(utils.data_dir()) + 'next_run.txt' self.next_run_path = xbmcvfs.translatePath(utils.data_dir()) + 'next_run.txt'
if(self.enabled): if(self.enabled):
@@ -173,11 +173,11 @@ class BackupScheduler:
def _resumeCheck(self): def _resumeCheck(self):
shouldContinue = False shouldContinue = False
if(xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + "resume.txt"))): if(xbmcvfs.exists(xbmcvfs.translatePath(utils.data_dir() + "resume.txt"))):
rFile = xbmcvfs.File(xbmc.translatePath(utils.data_dir() + "resume.txt"), 'r') rFile = xbmcvfs.File(xbmcvfs.translatePath(utils.data_dir() + "resume.txt"), 'r')
self.restore_point = rFile.read() self.restore_point = rFile.read()
rFile.close() rFile.close()
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "resume.txt")) xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "resume.txt"))
shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30042), utils.getString(30043), utils.getString(30044)) shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30042), utils.getString(30043), utils.getString(30044))
return shouldContinue return shouldContinue

View File

@@ -1,6 +1,7 @@
import xbmc import xbmc
import xbmcgui import xbmcgui
import xbmcaddon import xbmcaddon
import xbmcvfs
__addon_id__ = 'script.xbmcbackup' __addon_id__ = 'script.xbmcbackup'
__Addon = xbmcaddon.Addon(__addon_id__) __Addon = xbmcaddon.Addon(__addon_id__)
@@ -23,7 +24,7 @@ def log(message, loglevel=xbmc.LOGDEBUG):
def showNotification(message): def showNotification(message):
xbmcgui.Dialog().notification(getString(30010), message, time=4000, icon=xbmc.translatePath(__Addon.getAddonInfo('path') + "/resources/images/icon.png")) xbmcgui.Dialog().notification(getString(30010), message, time=4000, icon=xbmcvfs.translatePath(__Addon.getAddonInfo('path') + "/resources/images/icon.png"))
def getSetting(name): def getSetting(name):

View File

@@ -2,7 +2,6 @@ from __future__ import unicode_literals
import zipfile import zipfile
import os.path import os.path
import sys import sys
import xbmc
import xbmcvfs import xbmcvfs
import xbmcgui import xbmcgui
from dropbox import dropbox from dropbox import dropbox
@@ -68,10 +67,10 @@ class XBMCFileSystem(Vfs):
return xbmcvfs.listdir(directory) return xbmcvfs.listdir(directory)
def mkdir(self, directory): def mkdir(self, directory):
return xbmcvfs.mkdir(xbmc.translatePath(directory)) return xbmcvfs.mkdir(xbmcvfs.translatePath(directory))
def put(self, source, dest): def put(self, source, dest):
return xbmcvfs.copy(xbmc.translatePath(source), xbmc.translatePath(dest)) return xbmcvfs.copy(xbmcvfs.translatePath(source), xbmcvfs.translatePath(dest))
def rmdir(self, directory): def rmdir(self, directory):
return xbmcvfs.rmdir(directory, True) return xbmcvfs.rmdir(directory, True)
@@ -108,7 +107,7 @@ class ZipFileSystem(Vfs):
def put(self, source, dest): def put(self, source, dest):
aFile = xbmcvfs.File(xbmc.translatePath(source), 'r') aFile = xbmcvfs.File(xbmcvfs.translatePath(source), 'r')
self.zip.writestr(dest, aFile.readBytes()) self.zip.writestr(dest, aFile.readBytes())

View File

@@ -3,6 +3,7 @@
<category id="general" label="30011" level="expert"> <category id="general" label="30011" level="expert">
<setting id="compress_backups" type="bool" label="30087" default="false" /> <setting id="compress_backups" type="bool" label="30087" default="false" />
<setting id="backup_rotation" type="number" label="30026" default="0" /> <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 id="progress_mode" type="enum" label="30022" lvalues="30082|30083|30084" default="0" />
<setting type="sep" /> <setting type="sep" />
<setting id="verbose_logging" type="bool" label="Enable Verbose Logging" default="false" /> <setting id="verbose_logging" type="bool" label="Enable Verbose Logging" default="false" />