[MerlinMusicPlayer] fixed google cover display
[enigma2-plugins.git] / epgbackup / src / EPGBackupSupport.py
1 # -*- coding: UTF-8 -*-
2
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.MessageBox import MessageBox
5
6 from Components.config import config
7 from enigma import eEPGCache
8 from enigma import eTimer
9 from Tools import Notifications
10 from Screens.TextBox import TextBox
11
12 from . import _
13
14 # Error-print
15 from EPGBackupTools import debugOut, _getLogFilename, EPGBACKUP_NOTIFICATIONDOMAIN
16 from traceback import format_exc
17
18 # SH-Script
19 from Tools.Directories import SCOPE_PLUGINS, resolveFilename
20 import os
21 import subprocess
22 SH_EXEC_FILE = resolveFilename(SCOPE_PLUGINS, "Extensions/EPGBackup/EPGBackup.sh")
23 SH_TMP_OUTPUT="/tmp/.EPGBackup.sh.output"
24 BOOTCOUNTERFILE="/tmp/.EPGBackup.boot.counter"
25
26 FORCERESTORENOFILES="FORCEBACKUP_NOFILES"
27 FORCERESTORECANCEL="FORCEBACKUP_CANCEL"
28 EPGBACKUP_SHELL_CONSTANTS = { 'INSTALL': 'install',
29                 'UNINSTALL': 'uninstall',
30                 'FORCERESTORE': 'restore',
31                 'MAKEBACKUP': 'backup',
32                 'GETLASTFILE': 'getlastfile',
33                 'GETLASTFILE_BACKUP': 'backup',
34                 'GETLASTFILE_RESTORE': 'restore',
35                 'GETLASTFILE_ERROR': 'error',
36                 'SETFORCERESTORE': 'setforcefile',
37                 'EPGINFO': 'epginfo',
38                 'EPGINFOSORTSIZE': 'bySize',
39                 'STRINGBIGGEST': 'biggest',
40                 'STRINGYOUNGEST': 'youngest',
41                 'STRINGFORCED': 'force',
42 }
43 class EPGBackupSupport:
44         """Class for the Backup-Functionality"""
45         epgrefresh_instance = None
46
47         def __init__(self, session):
48                 # Initialize
49                 self.session = session
50                 
51                 self.backuptimer = eTimer()
52                 self.backuptimer.callback.append(self.makeBackup)
53                 
54                 # while postinst doesn't work in git-make
55                 self.autoinstall(config.plugins.epgbackup.backup_enabled)
56                 config.plugins.epgbackup.backup_enabled.addNotifier(self.autoinstall, initial_call = False, immediate_feedback = True)
57
58                 config.plugins.epgbackup.backupSaveInterval.addNotifier(self.startStopBackupTimer, initial_call = False, immediate_feedback = True)
59                 try:
60                         from Plugins.Extensions.EPGRefresh.EPGRefresh import epgrefresh
61                         self.epgrefresh_instance = epgrefresh
62                         config.plugins.epgbackup.callAfterEPGRefresh.addNotifier(self.enableBackupAfterEPGRefresh, initial_call = True, immediate_feedback = True)
63                 except:
64                         debugOut("EPGRefresh not installed!", forced=True)
65                         debugOut("Debug: EPGRefresh-Import-Error:\n" + str(format_exc()))
66                 
67                 self.notifyBootCount()
68
69         def notifyBootCount(self):
70                 try:
71                         if os.path.exists(BOOTCOUNTERFILE):
72                                 bootCount = ""
73                                 fo=open(BOOTCOUNTERFILE)
74                                 line = fo.readline()
75                                 while (line):
76                                         bootCount = line
77                                         line = fo.readline()
78                                 fo.close
79                                 
80                                 # We have succesfully booted, so delete the counter-File
81                                 os.remove(BOOTCOUNTERFILE)
82                                 
83                                 bootCount= int(bootCount)
84                                 if bootCount > int(config.plugins.epgbackup.max_boot_count.value):
85                                         backupedFile = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE"], EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE_BACKUP"], getoutput = True)
86                                         Notifications.AddNotificationWithCallback(self.askDeleteBadBackupCB, MessageBox, \
87                                                 text = _("The EPG-Backup was not performed, because there were %d unsuccessfully boot-attempts!\nThe last restored backup-file was \"%s\".\nDo you want to delete the file?") \
88                                                 % (bootCount, backupedFile), type = MessageBox.TYPE_YESNO, \
89                                                 timeout = 10, domain = EPGBACKUP_NOTIFICATIONDOMAIN)
90                 except:
91                         debugOut("checkBootCount-Error:\n" + str(format_exc()), forced=True)
92         
93         def askDeleteBadBackupCB(self, deleteIt):
94                 try:
95                         if deleteIt:
96                                 backupedFile = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE"], EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE_BACKUP"], getoutput = True)
97                                 if backupedFile != "":
98                                         debugOut("Deleting file \"%s\"..." % (backupedFile))
99                                         os.system("rm -f %s" % (backupedFile))
100                 except:
101                                 debugOut("askDeleteBadBackupCB-Error:\n" + str(format_exc()), forced=True)
102
103         def enableBackupAfterEPGRefresh(self, configentry):
104                 try:
105                         if self.epgrefresh_instance:
106                                 debugOut("addEPGRefresh-Notifier: " + str(configentry.value))
107                                 if configentry.value:
108                                         self.epgrefresh_instance.addFinishNotifier(self.makeBackup)
109                                 else:
110                                         self.epgrefresh_instance.removeFinishNotifier(self.makeBackup)
111                 except:
112                         debugOut("enableBackupAfterEPGRefresh-Error, maybe wrong Versoin of epgrefresh?:\n" + str(format_exc()), forced=True)
113
114         def startStopBackupTimer(self, configentry = None):
115                 try:
116                         if configentry == None:
117                                 configentry = config.plugins.epgbackup.backupSaveInterval
118                         self.timerInterval = int(configentry.value) * 60 # minutes
119                         if self.timerInterval > 0:
120                                 debugOut("backuptimer-Interval: " + str(self.timerInterval) + " seconds")
121                                 self.backuptimer.startLongTimer(self.timerInterval)
122                         else:
123                                 debugOut("backuptimer stopped!")
124                                 self.backuptimer.stop()
125                 except:
126                         debugOut("startStopBackupTimer-Error:\n" + str(format_exc()), forced=True)
127
128         def __getErrortext(self):
129                 errorTxt = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE"], EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE_ERROR"], getoutput = True)
130                 if not errorTxt or errorTxt == "":
131                         errorTxt = _("General Error!")
132                         return errorTxt
133                 elif errorTxt.count("#") > 0:
134                         params = errorTxt.split("#")
135                         errorTxt = params[0]
136                         param1 = params[1]
137                         param2 = params[2]
138                 
139                 if errorTxt == "BACKUP_RESTORE_DISABLED":
140                         errorTxt = _("Backup and Restore are disabled!")
141                 elif errorTxt == "BACKUP_EPGFILE_TOO_SMALL":
142                         errorTxt = _("EPG-File is too small for Backup: Size: %s; your setting: %s") % (param1, param2)
143                 elif errorTxt == "BACKUP_NO_EPGFILE_FOUND":
144                         errorTxt = _("No EPG-File found at %s!") % (param1)
145                 elif errorTxt == "RESTORE_BACKUPFILE_SMALLER":
146                         errorTxt = _("Backup-File to restore is smaller or equal EPG-file: Backup-File: %s; Epg-File: %s") % (param1, param2)
147                 elif errorTxt == "RESTORE_BACKUPFILE_OLDER":
148                         errorTxt = _("Backup-File to restore is older or equal EPG-file: Backup-File: %s; Epg-File: %s") % (param1, param2)
149                 elif errorTxt == "RESTORE_MAXBOOTCOUNT_REACHED":
150                         errorTxt = _("Maximum Number of unsuccessfully boots reached!")
151                 elif errorTxt == "RESTORE_ORIGINALFILE_VALID":
152                         errorTxt = _("The EPG-File is still valid!")
153                 
154                 return errorTxt
155         
156         def showLogFileCB(self, showIt):
157                 try:
158                         if showIt:
159                                 logFile = _getLogFilename()
160                                 if logFile != "":
161                                         if os.path.exists(logFile):
162                                                 logTxt = self._executeSh("/bin/cat", logFile, getoutput = True)
163                                                 self.session.open(TextBox, text = _("Logfile %s:\n%s") % (logFile, logTxt))
164                                         else:
165                                                 self.session.open(MessageBox, \
166                                                         _("There is no logfile named \"%s\"!") % (logFile), \
167                                                         type = MessageBox.TYPE_ERROR)
168                 except:
169                         debugOut("showLogFileCB-Error:\n" + str(format_exc()), forced=True)
170         
171         def makeBackup(self, interactive = False):
172                 try:
173                         debugOut("making a backup!")
174                         eEPGCache.getInstance().Lock()
175                         eEPGCache.getInstance().save()
176                         eEPGCache.getInstance().Unlock()
177                         self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["MAKEBACKUP"])
178                         self.startStopBackupTimer()
179                         if interactive or config.plugins.epgbackup.show_messages_background.value:
180                                 backupedFile = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE"], EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE_BACKUP"], getoutput = True)
181                                 if backupedFile != "":
182                                         Notifications.AddPopup(
183                                                 _("Backup \"%s\" successfully created!") % (backupedFile), \
184                                                 MessageBox.TYPE_INFO, 10, domain = EPGBACKUP_NOTIFICATIONDOMAIN)
185                                 else:
186                                         errorTxt = self.__getErrortext()
187                                         Notifications.AddNotificationWithCallback(self.showLogFileCB, MessageBox, \
188                                                 text = _("Couldn't create a backup.\nReason: %s.\nPress OK to see the logfile!") \
189                                                 % (errorTxt), type = MessageBox.TYPE_ERROR, \
190                                                 timeout = 30, domain = EPGBACKUP_NOTIFICATIONDOMAIN)
191                 except:
192                         debugOut("makeBackup-Error:\n" + str(format_exc()), forced=True)
193         
194         def forceDefaultRestore(self):
195                 self._defaultRestore(self.__forceRestoreCB, \
196                         _("Select a file to force a restore"))
197
198         def forceRestore(self):
199                 self._forceRestore(self.__forceRestoreCB, _("Select a file to force a restore"))
200                 
201         def forceRestoreBySize(self):
202                 self._forceRestore(self.__forceRestoreCB, _("Select a file to force a restore"), \
203                         sortMode = EPGBACKUP_SHELL_CONSTANTS["EPGINFOSORTSIZE"])
204         
205         def setNextBootRestore(self):
206                 self._defaultRestore(self.__setNextBootRestoreCB, \
207                         _("Select a file to force a restore on next boot"))
208
209         def _defaultRestore(self, callback, boxTitle):
210                 if config.plugins.epgbackup.backup_strategy.getValue() in ("biggest_before_youngest", "biggest"):
211                         self._forceRestore(callback, boxTitle, sortMode = EPGBACKUP_SHELL_CONSTANTS["EPGINFOSORTSIZE"])
212                 else:
213                         self._forceRestore(callback, boxTitle)
214         
215         def _forceRestore(self, callback, boxTitle, sortMode = ""):
216                 backupList = self._getBackupFiles(sortMode)
217                 if len(backupList) == 0:
218                         backupList.append((_("No Backupfiles found"), FORCERESTORENOFILES))
219                 backupList.insert(0, (_("Cancel"), FORCERESTORECANCEL))
220                 self.session.openWithCallback(callback,
221                         ChoiceBox, boxTitle, backupList)
222         
223         def __forceRestoreCB(self, backupinfo):
224                 try:
225                         if backupinfo is None:
226                                 return
227                         else:
228                                 backupfile = backupinfo [1].rstrip()
229                                 if FORCERESTORECANCEL != backupfile and FORCERESTORENOFILES != backupfile:
230                                         self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["FORCERESTORE"], backupfile)
231                                         restoredFile = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE"], EPGBACKUP_SHELL_CONSTANTS["GETLASTFILE_RESTORE"], getoutput = True)
232                                         if restoredFile != "":
233                                                 eEPGCache.getInstance().Lock()
234                                                 eEPGCache.getInstance().load()
235                                                 eEPGCache.getInstance().Unlock()
236                                                 self.session.open(MessageBox, \
237                                                         _("Backup-file \"%s\" successfully loaded!") % (restoredFile), \
238                                                         type = MessageBox.TYPE_INFO)
239                                         else:
240                                                 errorTxt = self.__getErrortext()
241                                                 Notifications.AddNotificationWithCallback(self.showLogFileCB, MessageBox, \
242                                                         text = _("Couldn't load backup-file.\nReason: %s.\nPress OK to see the logfile!") \
243                                                         % (errorTxt), type = MessageBox.TYPE_ERROR, \
244                                                         timeout = 30, domain = EPGBACKUP_NOTIFICATIONDOMAIN)
245                 except:
246                         debugOut("__forceRestoreCB-Error:\n" + str(format_exc()), forced=True)
247
248         def __setNextBootRestoreCB(self, backupinfo):
249                 if backupinfo is None:
250                         return
251                 else:
252                         backupfile = backupinfo [1].rstrip()
253                         if FORCERESTORECANCEL != backupfile and FORCERESTORENOFILES != backupfile:
254                                 self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["SETFORCERESTORE"], backupfile)
255                                 self.session.open(MessageBox, \
256                                         _("Backup-file \"%s\" will be loaded on next boot!") % (backupfile), \
257                                         type = MessageBox.TYPE_INFO)
258
259         def _getBackupFiles(self, sortMode):
260                 try:
261                         backupList = []
262                         backupStrList = self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["EPGINFO"], sortMode, True)
263                         if backupStrList:
264                                 backupfiles = backupStrList.split("\n")
265                         if backupfiles:
266                                 for backupfile in backupfiles:
267                                         if backupfile:
268                                                 backupfile = backupfile.replace(EPGBACKUP_SHELL_CONSTANTS["STRINGBIGGEST"], _("FILELIST_BIGGEST"))
269                                                 backupfile = backupfile.replace(EPGBACKUP_SHELL_CONSTANTS["STRINGYOUNGEST"], _("FILELIST_YOUNGEST"))
270                                                 backupfile = backupfile.replace(EPGBACKUP_SHELL_CONSTANTS["STRINGFORCED"], _("FILELIST_FORCED"))
271                                                 backupList.append(( backupfile, backupfile.split(" ")[0] ))
272                 except:
273                         debugOut("getBackupFiles-Error:\n" + str(format_exc()), forced=True)
274                 return backupList
275         
276         def autoinstall(self, configentry):
277                 if configentry.value:
278                         self.install()
279                 else:
280                         self.uninstall()
281         
282         def install(self):
283                 if os.path.exists(SH_EXEC_FILE):
284                         self._executeSh("/bin/chmod", "u+x", SH_EXEC_FILE)
285                 self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["INSTALL"], \
286                         config.plugins.epgbackup.showin_usr_scripts.value)
287         
288         def uninstall(self):
289                 self.executeShScript(EPGBACKUP_SHELL_CONSTANTS["UNINSTALL"])
290                 
291         def executeShScript(self, sh_action, param1 = "", getoutput = False):
292                 debugOut("EPGBackup.sh execute with params %s %s" %(sh_action, param1))
293                 return self._executeSh(SH_EXEC_FILE, sh_action, param1, getoutput)
294
295         def _executeSh(self, sh_cmd, param1 = "", param2 = "", getoutput = False):
296                 outtext = ""
297                 try:
298                         outtext = subprocess.check_output("%s %s %s" % (sh_cmd, param1, param2),
299                                 stderr=subprocess.STDOUT, 
300                                 shell=True)
301                 except subprocess.CalledProcessError as cpe:
302                         debugOut("sh-Execute-Error:\n%s: %s" %(str(cpe.returncode), cpe.output))
303                 return outtext
304
305
306