2012-09-05 22:50:25 +02:00
|
|
|
import xbmc
|
2013-05-09 21:24:10 +02:00
|
|
|
import xbmcvfs
|
|
|
|
import xbmcgui
|
2012-09-06 22:28:41 +02:00
|
|
|
import datetime
|
2012-09-05 22:50:25 +02:00
|
|
|
import time
|
2012-09-13 16:52:17 +02:00
|
|
|
import os
|
2012-09-05 22:50:25 +02:00
|
|
|
import resources.lib.utils as utils
|
2012-09-06 22:28:41 +02:00
|
|
|
from resources.lib.croniter import croniter
|
2012-09-05 22:50:25 +02:00
|
|
|
from resources.lib.backup import XbmcBackup
|
|
|
|
|
|
|
|
class BackupScheduler:
|
2013-04-01 17:59:20 +02:00
|
|
|
monitor = None
|
2012-09-05 22:50:25 +02:00
|
|
|
enabled = "false"
|
2012-09-06 22:28:41 +02:00
|
|
|
next_run = 0
|
2017-10-14 17:01:51 +02:00
|
|
|
next_run_path = None
|
2013-05-09 21:24:10 +02:00
|
|
|
restore_point = None
|
2012-09-06 22:28:41 +02:00
|
|
|
|
2012-09-05 22:50:25 +02:00
|
|
|
def __init__(self):
|
2013-04-01 17:59:20 +02:00
|
|
|
self.monitor = UpdateMonitor(update_method = self.settingsChanged)
|
2012-09-05 22:50:25 +02:00
|
|
|
self.enabled = utils.getSetting("enable_scheduler")
|
2017-10-14 17:01:51 +02:00
|
|
|
self.next_run_path = os.path.join(xbmc.translatePath(utils.data_dir()),'next_run')
|
2012-09-06 22:28:41 +02:00
|
|
|
|
|
|
|
if(self.enabled == "true"):
|
2017-10-14 17:01:51 +02:00
|
|
|
try:
|
|
|
|
fh = open(self.next_run_path, 'r')
|
|
|
|
fc = fh.read()
|
|
|
|
fh.close()
|
|
|
|
nr = float(fc)
|
|
|
|
except:
|
|
|
|
nr = 0
|
|
|
|
if(0 < nr <= time.time()):
|
|
|
|
utils.log("scheduled backup was missed, doing it now...")
|
|
|
|
progress_mode = int(utils.getSetting('progress_mode'))
|
|
|
|
if(progress_mode == 0):
|
|
|
|
progress_mode = 1 # Kodi just started, don't block it with a foreground progress bar
|
|
|
|
self.doScheduledBackup(progress_mode)
|
|
|
|
utils.log("...completed!")
|
2012-09-06 22:28:41 +02:00
|
|
|
self.setup()
|
|
|
|
|
|
|
|
def setup(self):
|
|
|
|
#scheduler was turned on, find next run time
|
|
|
|
utils.log("scheduler enabled, finding next run time")
|
2013-04-01 17:59:20 +02:00
|
|
|
self.findNextRun(time.time())
|
2012-09-05 22:50:25 +02:00
|
|
|
|
|
|
|
def start(self):
|
2013-05-09 21:24:10 +02:00
|
|
|
|
|
|
|
#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.run(XbmcBackup.Restore)
|
|
|
|
|
2012-09-05 22:50:25 +02:00
|
|
|
while(not xbmc.abortRequested):
|
2012-09-13 16:52:17 +02:00
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
if(self.enabled == "true"):
|
2012-09-13 16:52:17 +02:00
|
|
|
#scheduler is still on
|
2012-09-06 22:28:41 +02:00
|
|
|
now = time.time()
|
|
|
|
|
|
|
|
if(self.next_run <= now):
|
2014-01-20 19:42:49 +01:00
|
|
|
progress_mode = int(utils.getSetting('progress_mode'))
|
2017-10-14 17:01:51 +02:00
|
|
|
self.doScheduledBackup(progress_mode)
|
2012-12-13 22:11:25 +01:00
|
|
|
|
|
|
|
#check if we should shut the computer down
|
|
|
|
if(utils.getSetting("cron_shutdown") == 'true'):
|
|
|
|
#wait 10 seconds to make sure all backup processes and files are completed
|
|
|
|
time.sleep(10)
|
2012-12-30 22:19:17 +01:00
|
|
|
xbmc.executebuiltin('ShutDown()')
|
2012-12-13 22:11:25 +01:00
|
|
|
else:
|
|
|
|
#find the next run time like normal
|
2013-04-01 17:59:20 +02:00
|
|
|
self.findNextRun(now)
|
2012-09-06 22:28:41 +02:00
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
xbmc.sleep(500)
|
2012-09-05 22:50:25 +02:00
|
|
|
|
2013-09-09 20:27:59 +02:00
|
|
|
#delete monitor to free up memory
|
|
|
|
del self.monitor
|
|
|
|
|
2017-10-14 17:01:51 +02:00
|
|
|
def doScheduledBackup(self,progress_mode):
|
|
|
|
if(progress_mode != 2):
|
|
|
|
utils.showNotification(utils.getString(30053))
|
|
|
|
|
|
|
|
backup = XbmcBackup()
|
|
|
|
|
|
|
|
if(backup.remoteConfigured()):
|
|
|
|
|
|
|
|
if(int(utils.getSetting('progress_mode')) in [0,1]):
|
|
|
|
backup.run(XbmcBackup.Backup,True)
|
|
|
|
else:
|
|
|
|
backup.run(XbmcBackup.Backup,False)
|
|
|
|
|
|
|
|
#check if this is a "one-off"
|
|
|
|
if(int(utils.getSetting("schedule_interval")) == 0):
|
|
|
|
#disable the scheduler after this run
|
|
|
|
self.enabled = "false"
|
|
|
|
utils.setSetting('enable_scheduler','false')
|
|
|
|
else:
|
|
|
|
utils.showNotification(utils.getString(30045))
|
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
def findNextRun(self,now):
|
2017-01-13 18:28:48 +01:00
|
|
|
progress_mode = int(utils.getSetting('progress_mode'))
|
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
#find the cron expression and get the next run time
|
|
|
|
cron_exp = self.parseSchedule()
|
2012-09-06 22:28:41 +02:00
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
cron_ob = croniter(cron_exp,datetime.datetime.fromtimestamp(now))
|
|
|
|
new_run_time = cron_ob.get_next(float)
|
2012-09-06 22:28:41 +02:00
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
if(new_run_time != self.next_run):
|
|
|
|
self.next_run = new_run_time
|
|
|
|
utils.log("scheduler will run again on " + datetime.datetime.fromtimestamp(self.next_run).strftime('%m-%d-%Y %H:%M'))
|
2017-10-14 17:01:51 +02:00
|
|
|
try:
|
|
|
|
fh = open(self.next_run_path, 'w')
|
|
|
|
fh.write(str(self.next_run))
|
|
|
|
fh.close()
|
|
|
|
except: pass
|
2017-01-13 18:28:48 +01:00
|
|
|
|
|
|
|
#only show when not in silent mode
|
|
|
|
if(progress_mode != 2):
|
|
|
|
utils.showNotification(utils.getString(30081) + " " + datetime.datetime.fromtimestamp(self.next_run).strftime('%m-%d-%Y %H:%M'))
|
2013-04-01 17:59:20 +02:00
|
|
|
|
|
|
|
def settingsChanged(self):
|
|
|
|
current_enabled = utils.getSetting("enable_scheduler")
|
|
|
|
|
|
|
|
if(current_enabled == "true" and self.enabled == "false"):
|
|
|
|
#scheduler was just turned on
|
|
|
|
self.enabled = current_enabled
|
|
|
|
self.setup()
|
|
|
|
elif (current_enabled == "false" and self.enabled == "true"):
|
|
|
|
#schedule was turn off
|
|
|
|
self.enabled = current_enabled
|
|
|
|
|
|
|
|
if(self.enabled == "true"):
|
|
|
|
#always recheck the next run time after an update
|
|
|
|
self.findNextRun(time.time())
|
2012-09-06 22:28:41 +02:00
|
|
|
|
2012-09-05 22:50:25 +02:00
|
|
|
def parseSchedule(self):
|
|
|
|
schedule_type = int(utils.getSetting("schedule_interval"))
|
|
|
|
cron_exp = utils.getSetting("cron_schedule")
|
|
|
|
|
|
|
|
hour_of_day = utils.getSetting("schedule_time")
|
|
|
|
hour_of_day = int(hour_of_day[0:2])
|
2013-08-25 17:58:23 +02:00
|
|
|
if(schedule_type == 0 or schedule_type == 1):
|
2012-09-05 22:50:25 +02:00
|
|
|
#every day
|
|
|
|
cron_exp = "0 " + str(hour_of_day) + " * * *"
|
2013-08-25 17:58:23 +02:00
|
|
|
elif(schedule_type == 2):
|
2012-09-05 22:50:25 +02:00
|
|
|
#once a week
|
|
|
|
day_of_week = utils.getSetting("day_of_week")
|
|
|
|
cron_exp = "0 " + str(hour_of_day) + " * * " + day_of_week
|
2013-08-25 17:58:23 +02:00
|
|
|
elif(schedule_type == 3):
|
2012-09-05 22:50:25 +02:00
|
|
|
#first day of month
|
|
|
|
cron_exp = "0 " + str(hour_of_day) + " 1 * *"
|
|
|
|
|
2013-05-09 21:24:10 +02:00
|
|
|
return cron_exp
|
|
|
|
|
|
|
|
def _resumeCheck(self):
|
|
|
|
shouldContinue = False
|
|
|
|
if(xbmcvfs.exists(xbmc.translatePath(utils.data_dir() + "resume.txt"))):
|
|
|
|
rFile = xbmcvfs.File(xbmc.translatePath(utils.data_dir() + "resume.txt"),'r')
|
|
|
|
self.restore_point = rFile.read()
|
|
|
|
rFile.close()
|
|
|
|
xbmcvfs.delete(xbmc.translatePath(utils.data_dir() + "resume.txt"))
|
2013-05-09 21:35:31 +02:00
|
|
|
shouldContinue = xbmcgui.Dialog().yesno(utils.getString(30042),utils.getString(30043),utils.getString(30044))
|
2013-05-09 21:24:10 +02:00
|
|
|
|
|
|
|
return shouldContinue
|
|
|
|
|
2013-04-01 17:59:20 +02:00
|
|
|
|
|
|
|
class UpdateMonitor(xbmc.Monitor):
|
|
|
|
update_method = None
|
|
|
|
|
|
|
|
def __init__(self,*args, **kwargs):
|
|
|
|
xbmc.Monitor.__init__(self)
|
|
|
|
self.update_method = kwargs['update_method']
|
|
|
|
|
|
|
|
def onSettingsChanged(self):
|
|
|
|
self.update_method()
|
2012-09-05 22:50:25 +02:00
|
|
|
|
|
|
|
BackupScheduler().start()
|