Merge branch 'master' of git+ssh://scm.schwerkraft.elitedvb.net/scmrepos/git/enigma2...
[enigma2-plugins.git] / dvdbackup / src / plugin.py
1 ##
2 ## DVD Backup plugin for enigma2 by AliAbdul
3 ## using the great open source dvdbackup by Olaf Beck
4 ##
5 from Components.ActionMap import ActionMap
6 from Components.config import config, ConfigSubsection, ConfigText, ConfigYesNo, getConfigListEntry
7 from Components.ConfigList import ConfigListScreen
8 from Components.Console import Console as eConsole
9 from Components.Label import Label
10 from Components.Language import language
11 from Components.MenuList import MenuList
12 from Components.MultiContent import MultiContentEntryText, MultiContentEntryProgress
13 from Components.Scanner import Scanner, ScanPath
14 from enigma import eListboxPythonMultiContent, eTimer, gFont, RT_HALIGN_CENTER
15 from fcntl import ioctl
16 from Plugins.Plugin import PluginDescriptor
17 from Screens.Console import Console as ConsoleScreen
18 from Screens.LocationBox import LocationBox
19 from Screens.MessageBox import MessageBox
20 from Screens.Screen import Screen
21 from Screens.VirtualKeyBoard import VirtualKeyBoard
22 from time import time
23 from Tools.BoundFunction import boundFunction
24 from Tools.Directories import fileExists, resolveFilename, SCOPE_LANGUAGE, SCOPE_PLUGINS
25 import gettext, os, stat
26
27 #################################################
28
29 def localeInit():
30         lang = language.getLanguage()
31         os.environ["LANGUAGE"] = lang[:2]
32         gettext.bindtextdomain("enigma2", resolveFilename(SCOPE_LANGUAGE))
33         gettext.textdomain("enigma2")
34         gettext.bindtextdomain("DVDBackup", "%s%s" % (resolveFilename(SCOPE_PLUGINS), "Extensions/DVDBackup/locale/"))
35
36 def _(txt):
37         t = gettext.dgettext("DVDBackup", txt)
38         if t == txt:
39                 t = gettext.gettext(txt)
40         return t
41
42 localeInit()
43 language.addCallback(localeInit)
44
45 #################################################
46
47 config.plugins.DVDBackup = ConfigSubsection()
48 config.plugins.DVDBackup.device = ConfigText(default="/dev/sr0", fixed_size=False)
49 config.plugins.DVDBackup.directory = ConfigText(default="/hdd/movie", fixed_size=False)
50 config.plugins.DVDBackup.name = ConfigText(default=_("Name of DVD"), fixed_size=False)
51 config.plugins.DVDBackup.log = ConfigYesNo(default=True)
52 config.plugins.DVDBackup.create_iso = ConfigYesNo(default=False)
53
54 #################################################
55
56 global SESSION
57 SESSION = None
58
59 def message(msg):
60         SESSION.open(MessageBox, msg, type=MessageBox.TYPE_ERROR, timeout=10)
61
62 #################################################
63
64 def eject(dev):
65         try:
66                 cd = open(dev)
67                 ioctl_flag = int(0x5307)
68                 ioctl(cd.fileno(), ioctl_flag)
69                 ioctl_flag = int(0x5329)
70                 ioctl(cd.fileno(), ioctl_flag)
71                 ioctl_flag = int(0x5309)
72                 ioctl(cd.fileno(), ioctl_flag)
73                 cd.close()
74         except IOError, err:
75                 print err
76
77 #################################################
78
79 class DVDBackupFile:
80         def __init__(self, name, size):
81                 self.name = name
82                 if name != "mkisofs":
83                         self.name = ("%s/%s/%s"%(config.plugins.DVDBackup.directory.value, config.plugins.DVDBackup.name.value, name)).replace("//", "/")
84                 self.size = size
85                 self.progress = 0
86
87         def checkProgress(self):
88                 if self.name != "mkisofs":
89                         if fileExists(self.name):
90                                 if self.progress < 100:
91                                         file_stats = os.stat(self.name)
92                                         self.progress = 100.0 * file_stats[stat.ST_SIZE] / self.size
93                         else:
94                                 self.progress = 0
95
96 #################################################
97
98 class DVDBackup:
99         def __init__(self):
100                 self.console = None
101                 self.working = False
102                 self.startTime = None
103                 self.files = []
104
105         def backup(self):
106                 self.working = True
107                 self.startTime = time()
108                 del self.files
109                 self.files = []
110                 self.getInfo()
111
112         def getInfo(self):
113                 if not self.console:
114                         self.console = eConsole()
115                 self.console.ePopen("dvdbackup --info -i %s"%config.plugins.DVDBackup.device.value, self.gotInfo)
116
117         def gotInfo(self, result, retval, extra_args):
118                 if result and result.__contains__("File Structure DVD") and result.__contains__("Main feature:"):
119                         result = result[result.index("File Structure DVD"): result.index("Main feature:")]
120                         lines = result.split("\n")
121                         folder = ""
122                         for line in lines:
123                                 tmp = line.split("\t")
124                                 if len(tmp) == 1:
125                                         folder = tmp[0]
126                                 elif len(tmp) == 4:
127                                         name = folder+tmp[1]
128                                         size = tmp[2]
129                                         if size.__contains__("."):
130                                                 size = size[:size.index(".")]
131                                         if not name.__contains__("VTS_00_0."):
132                                                 self.files.append(DVDBackupFile(name, int(size)))
133                         if len(self.files) > 0:
134                                 if not self.console:
135                                         self.console = eConsole()
136                                 if config.plugins.DVDBackup.log.value:
137                                         log = " 2>> /tmp/dvdbackup.log"
138                                 else:
139                                         log = ""
140                                 cmd = 'dvdbackup -M -v -i %s -o "%s" -n "%s"%s'%(config.plugins.DVDBackup.device.value, config.plugins.DVDBackup.directory.value, config.plugins.DVDBackup.name.value, log)
141                                 self.console.ePopen(cmd, self.dvdbackupFinished)
142                         else:
143                                 message(_("Could not find any file to backup!"))
144                                 self.working = False
145                 else:
146                         message(_("Could not read the DVD informations!"))
147                         print "[DVD Backup]",result
148                         self.working = False
149
150         def dvdbackupFinished(self, result, retval, extra_args):
151                 if retval != 0:
152                         message(_("Error while backup of DVD!"))
153                         print "[DVD Backup]", retval, result
154                         self.working = False
155                 else:
156                         if config.plugins.DVDBackup.create_iso.value:
157                                 path = ("%s/%s"%(config.plugins.DVDBackup.directory.value, config.plugins.DVDBackup.name.value)).replace("//", "/")
158                                 if not self.console:
159                                         self.console = eConsole()
160                                 self.mkisofs = DVDBackupFile("mkisofs", 0)
161                                 self.files.append(self.mkisofs)
162                                 cmd = 'mkisofs -dvd-video -udf -o "%s.iso" "%s"'%(path, path)
163                                 self.console.ePopen(cmd, self.mkisofsCallback)
164                                 self.console.appContainers[cmd].dataAvail.append(boundFunction(self.mkisofsProgress, cmd))
165                         else:
166                                 self.finished()
167
168         def mkisofsProgress(self, name, data):
169                 if data.__contains__("%"):
170                         for x in data.split("\n"):
171                                 if x.__contains__("%"):
172                                         x = x[:x.index("%")]
173                                         if x.__contains__("."):
174                                                 x = x[:x.index(".")]
175                                         x = x.replace(" ", "")
176                                         if x != "":
177                                                 self.mkisofs.progress = int(x)
178
179         def mkisofsCallback(self, result, retval, extra_args):
180                 if retval != 0:
181                         message(_("Error while backup of DVD!"))
182                         print "[DVD Backup]", result
183                         self.working = False
184                 else:
185                         self.mkisofs.progress = 100
186                         SESSION.openWithCallback(self.mkisofsCallback2, MessageBox, _("mkisofs job done.\nDelete DVD directory?"))
187
188         def mkisofsCallback2(self, yesno):
189                 if yesno:
190                         cmd = ("rm -R %s/%s"%(config.plugins.DVDBackup.directory.value, config.plugins.DVDBackup.name.value)).replace("//", "/")
191                         try: os.system(cmd)
192                         except: pass
193                 self.finished()
194
195         def finished(self):
196                 seconds = int(time() - self.startTime)
197                 minutes = 0
198                 while seconds > 60:
199                         seconds -= 60
200                         minutes += 1
201                 SESSION.openWithCallback(self.eject, MessageBox, "%s\n%s %d:%02d\n\n%s"%(_("Backup of DVD finished."), _("Duration:"), minutes, seconds, _("Eject DVD?")))
202
203         def eject(self, yesno):
204                 if yesno:
205                         eject(config.plugins.DVDBackup.device.value)
206                 self.working = False
207
208 dvdbackup = DVDBackup()
209
210 #################################################
211
212 class DVDBackupList(MenuList):
213         def __init__(self):
214                 MenuList.__init__(self, [], False, eListboxPythonMultiContent)
215                 self.l.setItemHeight(25)
216                 self.l.setFont(0, gFont("Regular", 20))
217
218 #################################################
219
220 def DVDBackupListEntry(file):
221         res = [(file)]
222         res.append(MultiContentEntryText(pos=(0, 0), size=(180, 25), font=0, text=file.name.split("/")[-1]))
223         res.append(MultiContentEntryText(pos=(200, 0), size=(120, 25), font=0, text="%d %s"%((file.size / 1024) / 1024, "MB"), flags=RT_HALIGN_CENTER))
224         res.append(MultiContentEntryProgress(pos=(340, 9), size=(100, 7), percent=file.progress, borderWidth=1))
225         res.append(MultiContentEntryText(pos=(460, 0), size=(60, 25), font=0, text="%d%s"%(file.progress, "%"), flags=RT_HALIGN_CENTER))
226         return res
227
228 #################################################
229
230 class DVDBackupProgress(Screen):
231         skin = """
232         <screen position="center,center" size="560,450" title="DVD Backup">
233                 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
234                 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
235                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
236                 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
237                 <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
238                 <widget name="list" position="0,45" size="560,400" scrollbarMode="showOnDemand" />
239         </screen>"""
240
241         def __init__(self, session):
242                 Screen.__init__(self, session)
243                 
244                 self.refreshTimer = eTimer()
245                 self.refreshTimer.callback.append(self.refreshList)
246                 
247                 self.console = None
248                 self.working = False
249                 
250                 self["key_red"] = Label(_("Abort"))
251                 self["list"] = DVDBackupList()
252                 
253                 self["actions"] = ActionMap(["ColorActions", "OkCancelActions"],
254                         {
255                                 "cancel": self.exit,
256                                 "red": self.abort
257                         }, -1)
258                 
259                 self.onLayoutFinish.append(self.refreshList)
260
261         def exit(self):
262                 if self.working == False:
263                         self.refreshTimer.stop()
264                         self.close()
265
266         def refreshList(self):
267                 list = []
268                 tostart = []
269                 finished = []
270                 for file in dvdbackup.files:
271                         file.checkProgress()
272                         if file.progress == 0:
273                                 tostart.append(DVDBackupListEntry(file))
274                         elif file.progress == 100:
275                                 finished.append(DVDBackupListEntry(file))
276                         else:
277                                 list.append(DVDBackupListEntry(file))
278                 for x in tostart:
279                         list.append(x)
280                 for x in finished:
281                         list.append(x)
282                 self["list"].setList(list)
283                 self.refreshTimer.start(3000, 1)
284
285         def abort(self):
286                 if self.working == False and dvdbackup.working:
287                         self.working = True
288                         if not self.console:
289                                 self.console = eConsole()
290                         tool = "dvdbackup"
291                         for file in dvdbackup.files:
292                                 if file.name == "mkisofs":
293                                         tool = "mkisofs"
294                         self.console.ePopen("killall -9 %s"%tool, self.abortCallback)
295
296         def abortCallback(self, result, retval, extra_args):
297                 self.working = False
298
299 #################################################
300
301 class DVDBackupScreen(ConfigListScreen, Screen):
302         skin = """
303         <screen position="center,center" size="560,175" title="DVD Backup">
304                 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" transparent="1" alphatest="on" />
305                 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" transparent="1" alphatest="on" />
306                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" transparent="1" alphatest="on" />
307                 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" transparent="1" alphatest="on" />
308                 <widget name="key_red" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
309                 <widget name="key_green" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
310                 <widget name="key_yellow" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
311                 <widget name="key_blue" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
312                 <widget name="config" position="0,45" size="560,125" scrollbarMode="showOnDemand" />
313         </screen>"""
314
315         def __init__(self, session, device=None):
316                 Screen.__init__(self, session)
317                 
318                 self.working = False
319                 self.session = session
320                 self.console = None
321                 
322                 self["key_red"] = Label(_("Progress"))
323                 self["key_green"] = Label(_("Backup"))
324                 self["key_yellow"] = Label(_("Keyboard"))
325                 self["key_blue"] = Label(_("Location"))
326                 
327                 if device:
328                         config.plugins.DVDBackup.device.value = device
329                 
330                 ConfigListScreen.__init__(self, [
331                         getConfigListEntry(_("Device:"), config.plugins.DVDBackup.device),
332                         getConfigListEntry(_("Directory:"), config.plugins.DVDBackup.directory),
333                         getConfigListEntry(_("Name:"), config.plugins.DVDBackup.name),
334                         getConfigListEntry(_("Log:"), config.plugins.DVDBackup.log),
335                         getConfigListEntry(_("Create iso:"), config.plugins.DVDBackup.create_iso)])
336                 
337                 self["actions"] = ActionMap(["ColorActions", "OkCancelActions"],
338                         {
339                                 "red": self.progress,
340                                 "green": self.backup,
341                                 "yellow": self.keyboard,
342                                 "blue": self.location,
343                                 "cancel": self.exit
344                         }, -1)
345                 
346                 self["config"].onSelectionChanged.append(self.checkConfig)
347                 self.onLayoutFinish.append(self.getName)
348
349         def progress(self):
350                 if self.working == False:
351                         self.session.open(DVDBackupProgress)
352
353         def backup(self):
354                 if self.working == False:
355                         for x in self["config"].list:
356                                 x[1].save()
357                         dvdbackup.backup()
358                         self.session.openWithCallback(self.close, DVDBackupProgress)
359
360         def exit(self):
361                 if self.working == False:
362                         for x in self["config"].list:
363                                 x[1].cancel()
364                         self.close()
365
366         def checkConfig(self):
367                 current = self["config"].getCurrent()
368                 key = current and current[1]
369                 if isinstance(key, ConfigText):
370                         self["key_yellow"].show()
371                 else:
372                         self["key_yellow"].hide()
373
374         def keyboard(self):
375                 if self.working == False:
376                         current = self["config"].getCurrent()
377                         self.toChange = current and current[1]
378                         if isinstance(self.toChange, ConfigText):
379                                 self.session.openWithCallback(self.keyBoardCallback, VirtualKeyBoard, current and current[0], self.toChange.value)
380
381         def keyBoardCallback(self, callback=None):
382                 if callback:
383                         self.toChange.value = callback
384                         self["config"].setList(self["config"].getList())
385
386         def getName(self):
387                 self.working = True
388                 if not self.console:
389                         self.console = eConsole()
390                 self.console.ePopen("dvdbackup --info -i %s"%config.plugins.DVDBackup.device.value, self.gotInfo)
391
392         def location(self):
393                 self.session.openWithCallback(self.locationCallback, LocationBox)
394
395         def locationCallback(self, callback):
396                 if callback:
397                         config.plugins.DVDBackup.directory.value = callback
398                         self["config"].setList(self["config"].getList())
399
400         def gotInfo(self, result, retval, extra_args):
401                 config.plugins.DVDBackup.name.value = _("Name of DVD")
402                 if result:
403                         lines = result.split("\n")
404                         for line in lines:
405                                 if line.startswith("DVD-Video information of the DVD with title "):
406                                         idx = line.index("title ")
407                                         config.plugins.DVDBackup.name.value = line[idx+6:]
408                                         break
409                 self["config"].setList(self["config"].getList())
410                 self.working = False
411
412 #################################################
413
414 def main(session, **kwargs):
415         global SESSION
416         SESSION = session
417         if dvdbackup.working:
418                 session.open(DVDBackupProgress)
419         else:
420                 session.open(DVDBackupScreen)
421
422 def filescan_open(list, session, **kwargs):
423         global SESSION
424         SESSION = session
425         if len(list) == 1 and list[0].mimetype == "video/x-dvd":
426                 splitted = list[0].path.split('/')
427                 if len(splitted) > 2:
428                         if splitted[1] == 'autofs':
429                                 session.open(DVDBackupScreen, device="/dev/%s"%(splitted[2]))
430                                 return
431
432 def filescan(**kwargs):
433         class LocalScanner(Scanner):
434                 def checkFile(self, file):
435                         return fileExists(file.path)
436         return [LocalScanner(mimetypes=["video/x-dvd"], paths_to_scan=[ScanPath(path="video_ts", with_subdirs=False)], name="DVD", description=_("DVD Backup"), openfnc=filescan_open)]         
437
438 def Plugins(**kwargs):
439         return [PluginDescriptor(name=_("DVD Backup"), description=_("Backup your Video-DVD to your harddisk"), where=[PluginDescriptor.WHERE_EXTENSIONSMENU, PluginDescriptor.WHERE_PLUGINMENU], icon="DVDBackup.png", fnc=main),
440                 PluginDescriptor(where=PluginDescriptor.WHERE_FILESCAN, fnc=filescan)]