8 Commits

Author SHA1 Message Date
Rob Weber
40b6260521 version bump 2021-04-16 09:40:31 -05:00
Rob Weber
5aad014dbc update changelog 2021-04-16 09:36:26 -05:00
Rob Weber
ef3b820ca5 fix some gui dialog prompts 2021-04-16 09:34:43 -05:00
Rob Weber
76e8e0efeb check for restores right away 2021-04-16 09:30:22 -05:00
Rob Weber
f7e77fd739 fixes #190 - need to set file number to 1 2021-04-16 09:30:11 -05:00
Rob Weber
382dbce4ac added qrcode for dropbox setup 2021-04-08 15:43:26 -05:00
Rob
4b066432be Launcher (#189)
* move launcher code to default.py, modify RunScript in settings
2021-04-01 15:33:38 -05:00
Rob Weber
d71c923e78 forgot to add release date 2021-03-15 13:44:46 -05:00
15 changed files with 218 additions and 108 deletions

View File

@@ -1,13 +1,13 @@
# Backup Addon
![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/)
![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.7) [![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
I've had to recover my database, thumbnails, and source configuration enough times that I just wanted a quick easy way to back them up. That is what this addon is meant to do.
I've had to recover my database, thumbnails, and source configuration enough times that I just wanted a quick easy way to back them up. That is what this addon is meant to do.
## 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 Kodi 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 Kodi folders.
For more specific information please check out the [wiki on Github](https://github.com/robweber/xbmcbackup/wiki) for this project. Advanced descriptions for the following are all there:
@@ -15,17 +15,9 @@ For more specific information please check out the [wiki on Github](https://gith
* [Cloud Storage](https://github.com/robweber/xbmcbackup/wiki/Cloud-Storage)
* [Scheduling](https://github.com/robweber/xbmcbackup/wiki/Scheduling)
* [Scripting](https://github.com/robweber/xbmcbackup/wiki/Scripting)
* [FAQ](https://github.com/robweber/xbmcbackup/wiki/FAQ)
* [FAQ](https://github.com/robweber/xbmcbackup/wiki/FAQ)
## Attributions
Icon files from Open Iconic — www.useiconic.com/open

View File

@@ -1,11 +1,12 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<addon id="script.xbmcbackup"
name="Backup" version="1.6.6" provider-name="robweber">
name="Backup" version="1.6.7" provider-name="robweber">
<requires>
<import addon="xbmc.python" version="3.0.0"/>
<import addon="script.module.dateutil" version="2.8.0" />
<import addon="script.module.future" version="0.18.2+matrix.1" />
<import addon="script.module.dropbox" version="9.4.0" />
<import addon="script.module.pyqrcode" version="1.2.1+matrix.1" />
</requires>
<extension point="xbmc.python.script" library="default.py">
<provides>executable</provides>
@@ -89,8 +90,10 @@
<screenshot>resources/images/screenshot3.jpg</screenshot>
<screenshot>resources/images/screenshot4.jpg</screenshot>
</assets>
<news>Version 1.6.6
- fixed issue with backup rotations not working properly
<news>Version 1.6.7
- fixed issue with RunScript not launching Advanced Editor in some cases
- added qr code for Dropbox setup
- fixed error on advanced settings restore
</news>
</extension>
</addon>

View File

@@ -4,7 +4,19 @@ 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)
## [Version 1.6.7](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.5...robweber:matrix-1.6.7) - 2021-04-16
### Added
- added QRcode when setting up Dropbox, uses pyqrcode
### Fixed
- fixed issue when using ```RunScript()``` within settings to launch Advanced Editor
- error on advanced settings restore prior to reboot
- minor gui dialog fixes
## [Version 1.6.6](https://github.com/robweber/xbmcbackup/compare/matrix-1.6.5...robweber:matrix-1.6.6) - 2021-03-15
### Fixed

View File

@@ -1,7 +1,37 @@
import xbmc
import xbmcgui
import xbmcvfs
import resources.lib.utils as utils
from resources.lib.backup import XbmcBackup
from resources.lib.authorizers import DropboxAuthorizer
from resources.lib.advanced_editor import AdvancedBackupEditor
# mode constants
BACKUP = 0
RESTORE = 1
SETTINGS = 2
ADVANCED_EDITOR = 3
LAUNCHER = 4
def authorize_cloud(cloudProvider):
# drobpox
if(cloudProvider == 'dropbox'):
authorizer = DropboxAuthorizer()
if(authorizer.authorize()):
xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30027), utils.getString(30106)))
else:
xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30107), utils.getString(30027)))
def remove_auth():
# triggered from settings.xml - asks if user wants to delete OAuth token information
shouldDelete = xbmcgui.Dialog().yesno(utils.getString(30093), utils.getString(30094), utils.getString(30095), autoclose=7000)
if(shouldDelete):
# delete any of the known token file types
xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt")) # dropbox
xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "google_drive.dat")) # google drive
def get_params():
@@ -13,6 +43,7 @@ def get_params():
if(args.startswith('?')):
args = args[1:] # legacy in case of url params
splitString = args.split('=')
utils.log(splitString[1])
param[splitString[0]] = splitString[1]
except:
pass
@@ -24,13 +55,13 @@ def get_params():
mode = -1
params = get_params()
if("mode" in params):
if(params['mode'] == 'backup'):
mode = 0
mode = BACKUP
elif(params['mode'] == 'restore'):
mode = 1
mode = RESTORE
elif(params['mode'] == 'launcher'):
mode = LAUNCHER
# if mode wasn't passed in as arg, get from user
if(mode == -1):
@@ -49,15 +80,30 @@ if(mode != -1):
# run the profile backup
backup = XbmcBackup()
if(mode == 2):
if(mode == SETTINGS):
# open the settings dialog
utils.openSettings()
elif(mode == 3 and utils.getSettingInt('backup_selection_type') == 1):
# open the advanced editor
xbmc.executebuiltin('RunScript(special://home/addons/script.xbmcbackup/launcher.py, action=advanced_editor)')
elif(mode == ADVANCED_EDITOR and utils.getSettingInt('backup_selection_type') == 1):
# open the advanced editor but only if in advanced mode
editor = AdvancedBackupEditor()
editor.showMainScreen()
elif(mode == LAUNCHER):
# copied from old launcher.py
if(params['action'] == 'authorize_cloud'):
authorize_cloud(params['provider'])
elif(params['action'] == 'remove_auth'):
remove_auth()
elif(params['action'] == 'advanced_editor'):
editor = AdvancedBackupEditor()
editor.showMainScreen()
elif(params['action'] == 'advanced_copy_config'):
editor = AdvancedBackupEditor()
editor.copySimpleConfig()
elif(backup.remoteConfigured()):
if(mode == backup.Restore):
# if mode was RESTORE
if(mode == RESTORE):
# get list of valid restore points
restorePoints = backup.listBackups()
pointNames = []
@@ -90,6 +136,7 @@ if(mode != -1):
else:
backup.restore()
else:
# mode was BACKUP
backup.backup()
else:
# can't go any further

View File

@@ -1,58 +0,0 @@
# launcher for various helpful functions found in the settings.xml area
import sys
import xbmcgui
import xbmcvfs
import resources.lib.utils as utils
from resources.lib.authorizers import DropboxAuthorizer
from resources.lib.advanced_editor import AdvancedBackupEditor
def authorize_cloud(cloudProvider):
# drobpox
if(cloudProvider == 'dropbox'):
authorizer = DropboxAuthorizer()
if(authorizer.authorize()):
xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30027), utils.getString(30106)))
else:
xbmcgui.Dialog().ok(utils.getString(30010), '%s %s' % (utils.getString(30107), utils.getString(30027)))
def remove_auth():
# triggered from settings.xml - asks if user wants to delete OAuth token information
shouldDelete = xbmcgui.Dialog().yesno(utils.getString(30093), utils.getString(30094), utils.getString(30095), autoclose=7000)
if(shouldDelete):
# delete any of the known token file types
xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "tokens.txt")) # dropbox
xbmcvfs.delete(xbmcvfs.translatePath(utils.data_dir() + "google_drive.dat")) # google drive
def get_params():
param = {}
try:
for i in sys.argv:
args = i
if('=' in args):
if(args.startswith('?')):
args = args[1:] # legacy in case of url params
splitString = args.split('=')
param[splitString[0]] = splitString[1]
except:
pass
return param
params = get_params()
if(params['action'] == 'authorize_cloud'):
authorize_cloud(params['provider'])
elif(params['action'] == 'remove_auth'):
remove_auth()
elif(params['action'] == 'advanced_editor'):
editor = AdvancedBackupEditor()
editor.showMainScreen()
elif(params['action'] == 'advanced_copy_config'):
editor = AdvancedBackupEditor()
editor.copySimpleConfig()

View File

@@ -213,8 +213,8 @@ msgid "Removing backup"
msgstr "Removing backup"
msgctxt "#30056"
msgid "Go to this URL to authorize"
msgstr "Go to this URL to authorize"
msgid "Scan or click this URL to authorize, click OK AFTER completion"
msgstr "Scan or click this URL to authorize, click OK AFTER completion"
msgctxt "#30057"
msgid "Click OK AFTER completion"

View File

@@ -1,5 +1,6 @@
import xbmcgui
import xbmcvfs
import pyqrcode
import resources.lib.tinyurl as tinyurl
import resources.lib.utils as utils
@@ -11,6 +12,30 @@ except ImportError:
pass
class QRCode(xbmcgui.WindowXMLDialog):
def __init__(self, *args, **kwargs):
self.image = kwargs["image"]
self.text = kwargs["text"]
self.url = kwargs['url']
def onInit(self):
self.imagecontrol = 501
self.textbox1 = 502
self.textbox2 = 504
self.okbutton = 503
self.showdialog()
def showdialog(self):
self.getControl(self.imagecontrol).setImage(self.image)
self.getControl(self.textbox1).setText(self.text)
self.getControl(self.textbox2).setText(self.url)
self.setFocus(self.getControl(self.okbutton))
def onClick(self, controlId):
if (controlId == self.okbutton):
self.close()
class DropboxAuthorizer:
APP_KEY = ""
APP_SECRET = ""
@@ -52,7 +77,20 @@ class DropboxAuthorizer:
# print url in log
utils.log("Authorize URL: " + url)
xbmcgui.Dialog().ok(utils.getString(30010), '%s\n%s\n%s' % (utils.getString(30056), utils.getString(30057), str(tinyurl.shorten(url), 'utf-8')))
# create a QR Code
shortUrl = str(tinyurl.shorten(url), 'utf-8')
imageFile = xbmcvfs.translatePath(utils.data_dir() + '/qrcode.png')
qrIMG = pyqrcode.create(shortUrl)
qrIMG.png(imageFile, scale=10)
# show the dialog prompt to authorize
qr = QRCode("script-backup-qrcode.xml", utils.addon_dir(), "default", image=imageFile, text=utils.getString(30056), url=shortUrl)
qr.doModal()
# cleanup
del qr
xbmcvfs.delete(imageFile)
# get the auth code
code = xbmcgui.Dialog().input(utils.getString(30027) + ' ' + utils.getString(30103))

View File

@@ -272,10 +272,12 @@ 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), "%s\n%s" % (utils.getString(30039), utils.getString(30040)), utils.getString(30041))
restartXbmc = xbmcgui.Dialog().yesno(utils.getString(30038), "%s\n%s\n%s" % (utils.getString(30039), utils.getString(30040), utils.getString(30041)))
if(restartXbmc):
# add only this file to the file list
self.transferSize = 1
self.transferLeft = 1
fileManager.addFile(self.remote_vfs.root_path + "config/advancedsettings.xml")
self._copyFiles(fileManager.getFiles(), self.remote_vfs, self.xbmc_vfs)

View File

@@ -22,6 +22,21 @@ class BackupScheduler:
self.enabled = utils.getSettingBool("enable_scheduler")
self.next_run_path = xbmcvfs.translatePath(utils.data_dir()) + 'next_run.txt'
# display upgrade messages if they exist
if(utils.getSettingInt('upgrade_notes') < UPGRADE_INT):
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30132))
utils.setSetting('upgrade_notes', str(UPGRADE_INT))
# check if a backup should be resumed
resumeRestore = self._resumeCheck()
if(resumeRestore):
restore = XbmcBackup()
restore.selectRestore(self.restore_point)
# skip the advanced settings check
restore.skipAdvanced()
restore.restore()
if(self.enabled):
# sleep for 2 minutes so Kodi can start and time can update correctly
@@ -56,21 +71,6 @@ class BackupScheduler:
def start(self):
# display upgrade messages if they exist
if(utils.getSettingInt('upgrade_notes') < UPGRADE_INT):
xbmcgui.Dialog().ok(utils.getString(30010), utils.getString(30132))
utils.setSetting('upgrade_notes', str(UPGRADE_INT))
# check if a backup should be resumed
resumeRestore = self._resumeCheck()
if(resumeRestore):
restore = XbmcBackup()
restore.selectRestore(self.restore_point)
# skip the advanced settings check
restore.skipAdvanced()
restore.restore()
while(not self.monitor.abortRequested()):
if(self.enabled):
@@ -178,7 +178,7 @@ class BackupScheduler:
self.restore_point = rFile.read()
rFile.close()
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), "%s\n%s" % (utils.getString(30043), utils.getString(30044)))
return shouldContinue

View File

@@ -147,7 +147,7 @@
<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>
<data>RunScript(script.xbmcbackup,mode=launcher,action=authorize_cloud,provider=dropbox)</data>
</control>
</setting>
</group>
@@ -160,7 +160,7 @@
<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>
<data>RunScript(script.xbmcbackup,mode=launcher,action=remove_auth)</data>
</control>
</setting>
</group>
@@ -252,7 +252,7 @@
<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>
<data>RunScript(script.xbmcbackup,mode=launcher,action=advanced_editor)</data>
</control>
</setting>
<setting id="advanced_defaults" type="action" label="30139" help="">
@@ -262,7 +262,7 @@
<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>
<data>RunScript(script.xbmcbackup,mode=launcher,action=advanced_copy_config)</data>
</control>
</setting>
</group>

View File

@@ -0,0 +1,74 @@
<?xml version="1.0" encoding="UTF-8"?>
<window>
<coordinates>
<left>502</left>
<top>345</top>
</coordinates>
<controls>
<animation type="WindowOpen" reversible="false">
<effect type="zoom" start="80" end="100" center="960,540" delay="160" tween="back" time="240" />
<effect type="fade" delay="160" end="100" time="240" />
</animation>
<animation type="WindowClose" reversible="false">
<effect type="zoom" start="100" end="80" center="960,540" easing="in" tween="back" time="240" />
<effect type="fade" start="100" end="0" time="240" />
</animation>
<control type="image">
<left>-1920</left>
<top>-1080</top>
<width>5760</width>
<height>3240</height>
<animation effect="fade" start="0" end="100" time="300">WindowOpen</animation>
<animation effect="fade" start="100" end="0" time="200">WindowClose</animation>
<texture colordiffuse="C2FFFFFF">background-black.png</texture>
</control>
<control type="image">
<left>0</left>
<top>0</top>
<width>915</width>
<height>450</height>
<texture border="2">dialog-bg.png</texture>
</control>
<control type="textbox" id="502">
<left>0</left>
<top>20</top>
<width>915</width>
<height>300</height>
<font>font12_title</font>
<align>center</align>
<aligny>top</aligny>
<shadowcolor>FF000000</shadowcolor>
</control>
<control type="textbox" id="504">
<left>0</left>
<top>60</top>
<width>915</width>
<height>300</height>
<font>font12_title</font>
<align>center</align>
<aligny>top</aligny>
<shadowcolor>FF000000</shadowcolor>
</control>
<control type="image" id="501">
<left>300</left>
<top>80</top>
<width>300</width>
<height>300</height>
<aspectratio aligny="center" align="center">keep</aspectratio>
</control>
<control type="button" id="503">
<left>302</left>
<top>350</top>
<width>300</width>
<height>90</height>
<font>font12_title</font>
<textcolor>FFF0F0F0</textcolor>
<textoffsetx>20</textoffsetx>
<label>OK</label>
<align>center</align>
<aligny>center</aligny>
<texturefocus border="40" colordiffuse="FF12B2E7">dialogbutton-fo.png</texturefocus>
<texturenofocus border="40">dialogbutton-nofo.png</texturenofocus>
</control>
</controls>
</window>

Binary file not shown.

After

Width:  |  Height:  |  Size: 166 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB