1 # -*- coding: utf-8 -*-
2 from Plugins.SystemPlugins.Hotplug.plugin import hotplugNotifier
3 from Screens.Screen import Screen
4 from Screens.MessageBox import MessageBox
5 from Screens.ChoiceBox import ChoiceBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.TaskView import JobView
8 from Components.About import about
9 from Components.ActionMap import ActionMap
10 from Components.Sources.StaticText import StaticText
11 from Components.Sources.List import List
12 from Components.Label import Label
13 from Components.FileList import FileList
14 from Components.MenuList import MenuList
15 from Components.MultiContent import MultiContentEntryText
16 from Components.ScrollLabel import ScrollLabel
17 from Components.Harddisk import harddiskmanager
18 from Components.Task import Task, Job, job_manager, Condition
19 from Tools.Directories import fileExists, isMount
20 from Tools.HardwareInfo import HardwareInfo
21 from Tools.Downloader import downloadWithProgress
22 from enigma import eConsoleAppContainer, gFont, RT_HALIGN_LEFT, RT_HALIGN_CENTER, RT_VALIGN_CENTER, RT_WRAP, eTimer
23 from os import system, path, access, stat, remove, W_OK, R_OK
24 from twisted.web import client
25 from twisted.internet import reactor, defer
26 from twisted.python import failure
29 class ImageDownloadJob(Job):
30 def __init__(self, url, filename, device=None, mountpoint="/"):
31 Job.__init__(self, _("Download .NFI-Files for USB-Flasher"))
33 if isMount(mountpoint):
34 UmountTask(self, mountpoint)
35 MountTask(self, device, mountpoint)
36 ImageDownloadTask(self, url, mountpoint+filename)
37 ImageDownloadTask(self, url[:-4]+".nfo", mountpoint+filename[:-4]+".nfo")
39 UmountTask(self, mountpoint)
42 self.tasks[0].args += self.tasks[0].retryargs
45 class MountTask(Task):
46 def __init__(self, job, device, mountpoint):
47 Task.__init__(self, job, ("mount"))
50 self.mountpoint = mountpoint
51 self.args += [ device, mountpoint, "-o"+options ]
54 def processOutput(self, data):
55 print "[MountTask] output:", data
57 class UmountTask(Task):
58 def __init__(self, job, mountpoint):
59 Task.__init__(self, job, ("mount"))
60 self.setTool("umount")
61 self.args += [mountpoint]
64 class DownloaderPostcondition(Condition):
65 def check(self, task):
66 return task.returncode == 0
68 def getErrorMessage(self, task):
69 return self.error_message
71 class ImageDownloadTask(Task):
72 def __init__(self, job, url, path):
73 Task.__init__(self, job, _("Downloading"))
74 self.postconditions.append(DownloaderPostcondition())
78 self.error_message = ""
79 self.last_recvbytes = 0
80 self.error_message = None
84 def run(self, callback):
85 self.callback = callback
86 self.download = downloadWithProgress(self.url,self.path)
87 self.download.addProgress(self.download_progress)
88 self.download.start().addCallback(self.download_finished).addErrback(self.download_failed)
89 print "[ImageDownloadTask] downloading", self.url, "to", self.path
92 print "[ImageDownloadTask] aborting", self.url
97 def download_progress(self, recvbytes, totalbytes):
98 #print "[update_progress] recvbytes=%d, totalbytes=%d" % (recvbytes, totalbytes)
99 if ( recvbytes - self.last_recvbytes ) > 10000: # anti-flicker
100 self.progress = int(100*(float(recvbytes)/float(totalbytes)))
101 self.name = _("Downloading") + ' ' + "%d of %d kBytes" % (recvbytes/1024, totalbytes/1024)
102 self.last_recvbytes = recvbytes
104 def download_failed(self, failure_instance=None, error_message=""):
105 self.error_message = error_message
106 if error_message == "" and failure_instance is not None:
107 self.error_message = failure_instance.getErrorMessage()
108 Task.processFinished(self, 1)
110 def download_finished(self, string=""):
112 self.finish(aborted = True)
114 Task.processFinished(self, 0)
116 class StickWizardJob(Job):
117 def __init__(self, path):
118 Job.__init__(self, _("USB stick wizard"))
121 while self.device[-1:] == "/" or self.device[-1:].isdigit():
122 self.device = self.device[:-1]
124 box = HardwareInfo().get_device_name()
125 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s.tar.bz2" % box
126 self.downloadfilename = "/tmp/dreambox-nfiflasher-%s.tar.bz2" % box
127 self.imagefilename = "/tmp/nfiflash_%s.img" % box
128 #UmountTask(self, device)
130 ImageDownloadTask(self, url, self.downloadfilename)
134 class PartitionTaskPostcondition(Condition):
135 def check(self, task):
136 return task.returncode == 0
138 def getErrorMessage(self, task):
140 task.ERROR_BLKRRPART: ("Device or resource busy"),
141 task.ERROR_UNKNOWN: (task.errormsg)
144 class PartitionTask(Task):
145 ERROR_UNKNOWN, ERROR_BLKRRPART = range(2)
146 def __init__(self, job):
147 Task.__init__(self, job, ("partitioning"))
148 self.postconditions.append(PartitionTaskPostcondition())
150 self.setTool("sfdisk")
151 self.args += [self.job.device]
153 self.initial_input = "0 - 0x6 *\n;\n;\n;\ny"
156 def run(self, callback):
157 Task.run(self, callback)
159 def processOutput(self, data):
160 print "[PartitionTask] output:", data
161 if data.startswith("BLKRRPART:"):
162 self.error = self.ERROR_BLKRRPART
164 self.error = self.ERROR_UNKNOWN
167 class UnpackTask(Task):
168 def __init__(self, job):
169 Task.__init__(self, job, ("Unpacking USB flasher image..."))
172 self.args += ["-xjvf", self.job.downloadfilename]
175 self.delayTimer = eTimer()
176 self.delayTimer.callback.append(self.progress_increment)
178 def run(self, callback):
179 Task.run(self, callback)
180 self.delayTimer.start(950, False)
182 def progress_increment(self):
185 def processOutput(self, data):
186 print "[UnpackTask] output: \'%s\'" % data
187 self.job.imagefilename = data
190 self.delayTimer.callback.remove(self.progress_increment)
192 class CopyTask(Task):
193 def __init__(self, job):
194 Task.__init__(self, job, ("Copying USB flasher boot image to stick..."))
197 self.args += ["if=%s" % self.job.imagefilename, "of=%s1" % self.job.device]
200 self.delayTimer = eTimer()
201 self.delayTimer.callback.append(self.progress_increment)
203 def run(self, callback):
204 Task.run(self, callback)
205 self.delayTimer.start(100, False)
207 def progress_increment(self):
210 def processOutput(self, data):
211 print "[CopyTask] output:", data
214 self.delayTimer.callback.remove(self.progress_increment)
216 class NFOViewer(Screen):
218 <screen name="NFOViewer" position="center,center" size="610,410" title="Changelog viewer" >
219 <widget name="changelog" position="10,10" size="590,380" font="Regular;16" />
222 def __init__(self, session, nfo):
223 Screen.__init__(self, session)
224 self["changelog"] = ScrollLabel(nfo)
226 self["ViewerActions"] = ActionMap(["SetupActions", "ColorActions", "DirectionActions"],
232 "down": self.pageDown,
236 self["changelog"].pageUp()
239 self["changelog"].pageDown()
244 class feedDownloader:
245 def __init__(self, feed_base, box, OE_vers):
246 print "[feedDownloader::init] feed_base=%s, box=%s" % (feed_base, box)
247 self.feed_base = feed_base
248 self.OE_vers = OE_vers
251 def getList(self, callback, errback):
252 self.urlbase = "%s/%s/%s/images/" % (self.feed_base, self.OE_vers, self.box)
253 print "[getList]", self.urlbase
254 self.callback = callback
255 self.errback = errback
256 client.getPage(self.urlbase).addCallback(self.feed_finished).addErrback(self.feed_failed)
258 def feed_failed(self, failure_instance):
259 print "[feed_failed]", str(failure_instance)
260 self.errback(failure_instance.getErrorMessage())
262 def feed_finished(self, feedhtml):
263 print "[feed_finished]"
264 fileresultmask = re.compile("<a class=[\'\"]nfi[\'\"] href=[\'\"](?P<url>.*?)[\'\"]>(?P<name>.*?.nfi)</a>", re.DOTALL)
265 searchresults = fileresultmask.finditer(feedhtml)
268 for x in searchresults:
270 if url[0:7] != "http://":
271 url = self.urlbase + x.group("url")
272 name = x.group("name")
274 fileresultlist.append(entry)
275 self.callback(fileresultlist, self.OE_vers)
277 class DeviceBrowser(Screen, HelpableScreen):
279 <screen name="DeviceBrowser" position="center,center" size="520,430" title="Please select target medium" >
280 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
281 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
282 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
283 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
284 <widget source="message" render="Label" position="5,50" size="510,150" font="Regular;16" />
285 <widget name="filelist" position="5,210" size="510,220" scrollbarMode="showOnDemand" />
288 def __init__(self, session, startdir, message="", showDirectories = True, showFiles = True, showMountpoints = True, matchingPattern = "", useServiceRef = False, inhibitDirs = False, inhibitMounts = False, isTop = False, enableWrapAround = False, additionalExtensions = None):
289 Screen.__init__(self, session)
291 HelpableScreen.__init__(self)
293 self["key_red"] = StaticText(_("Cancel"))
294 self["key_green"] = StaticText()
295 self["message"] = StaticText(message)
297 self.filelist = FileList(startdir, showDirectories = showDirectories, showFiles = showFiles, showMountpoints = showMountpoints, matchingPattern = matchingPattern, useServiceRef = useServiceRef, inhibitDirs = inhibitDirs, inhibitMounts = inhibitMounts, isTop = isTop, enableWrapAround = enableWrapAround, additionalExtensions = additionalExtensions)
298 self["filelist"] = self.filelist
300 self["FilelistActions"] = ActionMap(["SetupActions", "ColorActions"],
308 hotplugNotifier.append(self.hotplugCB)
309 self.onShown.append(self.updateButton)
310 self.onClose.append(self.removeHotplug)
312 def hotplugCB(self, dev, action):
313 print "[hotplugCB]", dev, action
316 def updateButton(self):
318 if self["filelist"].getFilename() or self["filelist"].getCurrentDirectory():
319 self["key_green"].text = _("Use")
321 self["key_green"].text = ""
323 def removeHotplug(self):
324 print "[removeHotplug]"
325 hotplugNotifier.remove(self.hotplugCB)
328 if self.filelist.canDescent():
329 if self["filelist"].showMountpoints == True and self["filelist"].showDirectories == False:
332 self.filelist.descent()
335 print "[use]", self["filelist"].getCurrentDirectory(), self["filelist"].getFilename()
336 if self["filelist"].getCurrentDirectory() is not None:
337 if self.filelist.canDescent() and self["filelist"].getFilename() and len(self["filelist"].getFilename()) > len(self["filelist"].getCurrentDirectory()):
338 self.filelist.descent()
339 self.close(self["filelist"].getCurrentDirectory())
340 elif self["filelist"].getFilename():
341 self.close(self["filelist"].getFilename())
346 (ALLIMAGES, RELEASE, EXPERIMENTAL, STICK_WIZARD, START) = range(5)
348 class NFIDownload(Screen):
350 <screen name="NFIDownload" position="center,center" size="610,410" title="NFIDownload" >
351 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
352 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
353 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
354 <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
355 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#9f1313" transparent="1" />
356 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#1f771f" transparent="1" />
357 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#a08500" transparent="1" />
358 <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" valign="center" halign="center" backgroundColor="#18188b" transparent="1" />
359 <ePixmap pixmap="skin_default/border_menu_350.png" position="5,50" zPosition="1" size="350,300" transparent="1" alphatest="on" />
360 <widget source="menu" render="Listbox" position="15,60" size="330,290" scrollbarMode="showOnDemand">
361 <convert type="TemplatedMultiContent">
364 MultiContentEntryText(pos = (2, 2), size = (330, 24), flags = RT_HALIGN_LEFT, text = 1), # index 0 is the MenuText,
365 ], True, "showOnDemand")
367 "fonts": [gFont("Regular", 22)],
372 <widget source="menu" render="Listbox" position="360,50" size="240,300" scrollbarMode="showNever" selectionDisabled="1">
373 <convert type="TemplatedMultiContent">
376 MultiContentEntryText(pos = (2, 2), size = (240, 300), flags = RT_HALIGN_CENTER|RT_VALIGN_CENTER|RT_WRAP, text = 2), # index 2 is the Description,
377 ], False, "showNever")
379 "fonts": [gFont("Regular", 22)],
384 <widget source="status" render="Label" position="5,360" zPosition="10" size="600,50" halign="center" valign="center" font="Regular;22" transparent="1" shadowColor="black" shadowOffset="-1,-1" />
387 def __init__(self, session, destdir=None):
388 Screen.__init__(self, session)
389 #self.skin_path = plugin_path
392 self.box = HardwareInfo().get_device_name()
393 self.feed_base = "http://www.dreamboxupdate.com/opendreambox" #/1.5/%s/images/" % self.box
394 self.usbmountpoint = "/mnt/usb/"
398 self["menu"] = List(self.menulist)
399 self["key_red"] = StaticText(_("Close"))
400 self["key_green"] = StaticText()
401 self["key_yellow"] = StaticText()
402 self["key_blue"] = StaticText()
404 self["status"] = StaticText(_("Please wait... Loading list..."))
406 self["shortcuts"] = ActionMap(["OkCancelActions", "ColorActions", "ShortcutActions", "DirectionActions"],
411 "blue": self.keyBlue,
413 "upRepeated": self.keyUp,
414 "downRepeated": self.keyDown,
415 "down": self.keyDown,
416 "cancel": self.close,
418 self.onShown.append(self.go)
419 self.feedlists = [[],[],[]]
421 self.container = eConsoleAppContainer()
422 self.container.dataAvail.append(self.tool_avail)
425 self.nfofilename = ""
427 self.target_dir = None
429 def tool_avail(self, string):
430 print "[tool_avail]" + string
431 self.taskstring += string
434 self.onShown.remove(self.go)
435 self.umountCallback = self.getMD5
439 url = "http://www.dreamboxupdate.com/download/opendreambox/dreambox-nfiflasher-%s-md5sums" % self.box
440 client.getPage(url).addCallback(self.md5sums_finished).addErrback(self.feed_failed)
442 def md5sums_finished(self, data):
443 print "[md5sums_finished]", data
444 self.stickimage_md5 = data
448 if self.branch == START:
452 self["menu"].setList(self.menulist)
453 #elif self.branch == ALLIMAGES or self.branch == STICK_WIZARD:
457 self.session.open(NFOViewer, self.nfo)
460 print "[keyOk]", self["menu"].getCurrent()
461 current = self["menu"].getCurrent()
463 if self.branch == START:
464 currentEntry = current[0]
465 if currentEntry == RELEASE:
467 self.branch = RELEASE
468 self.askDestination()
469 elif currentEntry == EXPERIMENTAL:
471 self.branch = EXPERIMENTAL
472 self.askDestination()
473 elif currentEntry == ALLIMAGES:
474 self.branch = ALLIMAGES
476 elif currentEntry == STICK_WIZARD:
477 self.askStartWizard()
478 elif self.branch == ALLIMAGES:
479 self.image_idx = self["menu"].getIndex()
480 self.askDestination()
484 self["menu"].selectPrevious()
488 self["menu"].selectNext()
491 def updateButtons(self):
492 current = self["menu"].getCurrent()
494 if self.branch == START:
495 self["key_red"].text = _("Close")
496 currentEntry = current[0]
497 if currentEntry in (RELEASE, EXPERIMENTAL):
498 self.nfo_download(currentEntry, 0)
499 self["key_green"].text = _("Download")
501 self.nfofilename = ""
503 self["key_blue"].text = ""
504 self["key_green"].text = _("continue")
506 elif self.branch == ALLIMAGES:
507 self["key_red"].text = _("Back")
508 self["key_green"].text = _("Download")
509 self.nfo_download(ALLIMAGES, self["menu"].getIndex())
511 def listImages(self):
514 mask = re.compile("%s/(?P<OE_vers>1\.\d)/%s/images/(?P<branch>.*?)-%s_(?P<version>.*?).nfi" % (self.feed_base, self.box, self.box), re.DOTALL)
515 for name, url in self.feedlists[ALLIMAGES]:
516 result = mask.match(url)
518 if result.group("version").startswith("20"):
519 version = ( result.group("version")[:4]+'-'+result.group("version")[4:6]+'-'+result.group("version")[6:8] )
521 version = result.group("version")
522 description = "\nOpendreambox %s\n%s image\n%s\n" % (result.group("OE_vers"), result.group("branch"), version)
523 imagelist.append((url, name, _("Download %s from Server" ) % description, None))
524 self["menu"].setList(imagelist)
526 def getUSBPartitions(self):
527 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
528 print "[getUSBPartitions]", allpartitions
530 for x in allpartitions:
531 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
532 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
533 usbpartition.append(x)
536 def askDestination(self):
537 usbpartition = self.getUSBPartitions()
538 if len(usbpartition) == 1:
539 self.target_dir = usbpartition[0][1]
540 self.ackDestinationDevice(device_description=usbpartition[0][0])
542 self.session.openWithCallback(self.DeviceBrowserClosed, DeviceBrowser, None, showDirectories=True, showMountpoints=True, inhibitMounts=["/autofs/sr0/"])
544 def DeviceBrowserClosed(self, path):
545 print "[DeviceBrowserClosed]", str(path)
546 self.target_dir = path
548 self.ackDestinationDevice()
552 def ackDestinationDevice(self, device_description=None):
553 if device_description == None:
554 dev = self.target_dir
556 dev = device_description
557 message = _("Do you want to download the image to %s ?") % (dev)
558 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askDestination), (_("Cancel"),self.keyRed)]
559 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
561 def ackDestination_query(self, choice):
562 print "[ackDestination_query]", choice
563 if isinstance(choice, tuple):
568 def ackedDestination(self):
569 print "[ackedDestination]", self.branch, self.target_dir, self.target_dir[8:]
570 self.container.setCWD("/mnt")
571 if self.target_dir[:8] == "/autofs/":
572 self.target_dir = "/dev/" + self.target_dir[8:-1]
574 if self.branch == STICK_WIZARD:
575 job = StickWizardJob(self.target_dir)
576 job.afterEvent = "close"
577 job_manager.AddJob(job)
578 job_manager.failed_jobs = []
579 self.session.openWithCallback(self.StickWizardCB, JobView, job, afterEventChangeable = False)
581 elif self.branch != STICK_WIZARD:
582 url = self.feedlists[self.branch][self.image_idx][1]
583 filename = self.feedlists[self.branch][self.image_idx][0]
584 print "[getImage] start downloading %s to %s" % (url, filename)
585 job = ImageDownloadJob(url, filename, self.target_dir, self.usbmountpoint)
586 job.afterEvent = "close"
587 job_manager.AddJob(job)
588 job_manager.failed_jobs = []
589 self.session.openWithCallback(self.ImageDownloadCB, JobView, job, afterEventChangeable = False)
591 def StickWizardCB(self, ret=None):
592 print "[StickWizardCB]", ret
593 # print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
594 if len(job_manager.failed_jobs) == 0:
595 self.session.open(MessageBox, _("The USB stick was prepared to be bootable.\nNow you can download an NFI image file!"), type = MessageBox.TYPE_INFO)
596 if len(self.feedlists[ALLIMAGES]) == 0:
601 self.umountCallback = self.checkUSBStick
604 def ImageDownloadCB(self, ret):
605 print "[ImageDownloadCB]", ret
606 # print job_manager.active_jobs, job_manager.failed_jobs, job_manager.job_classes, job_manager.in_background, job_manager.active_job
607 if len(job_manager.failed_jobs) == 0:
608 self.session.open(MessageBox, _("To update your Dreambox firmware, please follow these steps:\n1) Turn off your box with the rear power switch and plug in the bootable USB stick.\n2) Turn mains back on and hold the DOWN button on the front panel pressed for 10 seconds.\n3) Wait for bootup and follow instructions of the wizard."), type = MessageBox.TYPE_INFO)
610 self.umountCallback = self.keyRed
614 self.feedDownloader15 = feedDownloader(self.feed_base, self.box, OE_vers="1.5")
615 self.feedDownloader16 = feedDownloader(self.feed_base, self.box, OE_vers="1.6")
616 self.feedlists = [[],[],[]]
617 self.feedDownloader15.getList(self.gotFeed, self.feed_failed)
618 self.feedDownloader16.getList(self.gotFeed, self.feed_failed)
620 def feed_failed(self, message=""):
621 self["status"].text = _("Could not connect to Dreambox .NFI Image Feed Server:") + "\n" + str(message) + "\n" + _("Please check your network settings!")
623 def gotFeed(self, feedlist, OE_vers):
624 print "[gotFeed]", OE_vers
626 experimentallist = []
628 for name, url in feedlist:
629 if name.find("release") > -1:
630 releaselist.append((name, url))
631 if name.find("experimental") > -1:
632 experimentallist.append((name, url))
633 self.feedlists[ALLIMAGES].append((name, url))
636 self.feedlists[RELEASE] = releaselist + self.feedlists[RELEASE]
637 self.feedlists[EXPERIMENTAL] = experimentallist + self.feedlists[RELEASE]
638 elif OE_vers == "1.5":
639 self.feedlists[RELEASE] = self.feedlists[RELEASE] + releaselist
640 self.feedlists[EXPERIMENTAL] = self.feedlists[EXPERIMENTAL] + experimentallist
644 def checkUSBStick(self):
645 self.target_dir = None
646 allpartitions = [ (r.description, r.mountpoint) for r in harddiskmanager.getMountedPartitions(onlyhotplug = True)]
647 print "[checkUSBStick] found partitions:", allpartitions
649 for x in allpartitions:
650 print x, x[1] == '/', x[0].find("USB"), access(x[1], R_OK)
651 if x[1] != '/' and x[0].find("USB") > -1: # and access(x[1], R_OK) is True:
652 usbpartition.append(x)
655 if len(usbpartition) == 1:
656 self.target_dir = usbpartition[0][1]
657 self.md5_passback = self.getFeed
658 self.md5_failback = self.askStartWizard
659 self.md5verify(self.stickimage_md5, self.target_dir)
660 elif usbpartition == []:
661 print "[NFIFlash] needs to create usb flasher stick first!"
662 self.askStartWizard()
664 self.askStartWizard()
666 def askStartWizard(self):
667 self.branch = STICK_WIZARD
668 message = _("""This plugin creates a USB stick which can be used to update the firmware of your Dreambox in case it has no network connection or only WLAN access.
669 First, you need to prepare a USB stick so that it is bootable.
670 In the next step, an NFI image file can be downloaded from the update server and saved on the USB stick.
671 If you already have a prepared bootable USB stick, please insert it now. Otherwise plug in a USB stick with a minimum size of 64 MB!""")
672 self.session.openWithCallback(self.wizardDeviceBrowserClosed, DeviceBrowser, None, message, showDirectories=True, showMountpoints=True, inhibitMounts=["/","/autofs/sr0/","/autofs/sda1/","/media/hdd/","/media/net/",self.usbmountpoint,"/media/dvd/"])
674 def wizardDeviceBrowserClosed(self, path):
675 print "[wizardDeviceBrowserClosed]", path
676 self.target_dir = path
678 self.md5_passback = self.getFeed
679 self.md5_failback = self.wizardQuery
680 self.md5verify(self.stickimage_md5, self.target_dir)
684 def wizardQuery(self):
685 print "[wizardQuery]"
686 description = self.target_dir
687 for name, dev in self.getUSBPartitions():
688 if dev == self.target_dir:
690 message = _("You have chosen to create a new .NFI flasher bootable USB stick. This will repartition the USB stick and therefore all data on it will be erased.") + "\n"
691 message += _("The following device was found:\n\n%s\n\nDo you want to write the USB flasher to this stick?") % description
692 choices = [(_("Yes"), self.ackedDestination), (_("List of Storage Devices"),self.askStartWizard), (_("Cancel"),self.close)]
693 self.session.openWithCallback(self.ackDestination_query, ChoiceBox, title=message, list=choices)
698 latest_release = "Release %s (Opendreambox 1.5)" % self.feedlists[RELEASE][0][0][-9:-4]
699 self.menulist.append((RELEASE, _("Get latest release image"), _("Download %s from Server" ) % latest_release, None))
704 dat = self.feedlists[EXPERIMENTAL][0][0][-12:-4]
705 latest_experimental = "Experimental %s-%s-%s (Opendreambox 1.6)" % (dat[:4], dat[4:6], dat[6:])
706 self.menulist.append((EXPERIMENTAL, _("Get latest experimental image"), _("Download %s from Server") % latest_experimental, None))
710 self.menulist.append((ALLIMAGES, _("Choose image to download"), _("Select desired image from feed list" ), None))
711 self.menulist.append((STICK_WIZARD, _("USB stick wizard"), _("Prepare another USB stick for image flashing" ), None))
712 self["menu"].setList(self.menulist)
713 self["status"].text = _("Currently installed image") + ": %s" % (about.getImageVersionString())
717 def nfo_download(self, branch, idx):
718 nfourl = (self.feedlists[branch][idx][1])[:-4]+".nfo"
719 self.nfofilename = (self.feedlists[branch][idx][0])[:-4]+".nfo"
720 print "[check_for_NFO]", nfourl
721 client.getPage(nfourl).addCallback(self.nfo_finished).addErrback(self.nfo_failed)
723 def nfo_failed(self, failure_instance):
724 print "[nfo_failed] " + str(failure_instance)
725 self["key_blue"].text = ""
726 self.nfofilename = ""
729 def nfo_finished(self,nfodata=""):
730 print "[nfo_finished] " + str(nfodata)
731 self["key_blue"].text = _("Changelog viewer")
734 def md5verify(self, md5, path):
736 print "[verify_md5]", md5, path, cmd
737 self.container.setCWD(path)
738 self.container.appClosed.append(self.md5finished)
739 self.container.execute(cmd)
740 self.container.write(md5)
741 self.container.dataSent.append(self.md5ready)
743 def md5ready(self, retval):
744 self.container.sendEOF()
746 def md5finished(self, retval):
747 print "[md5finished]", str(retval)
748 self.container.appClosed.remove(self.md5finished)
749 self.container.dataSent.remove(self.md5ready)
751 print "check passed! calling", repr(self.md5_passback)
754 print "check failed! calling", repr(self.md5_failback)
758 cmd = "umount " + self.usbmountpoint
759 print "[umount]", cmd
760 self.container.setCWD('/')
761 self.container.appClosed.append(self.umountFinished)
762 self.container.execute(cmd)
764 def umountFinished(self, retval):
765 print "[umountFinished]", str(retval)
766 self.container.appClosed.remove(self.umountFinished)
767 self.umountCallback()
769 def main(session, **kwargs):
770 session.open(NFIDownload,"/home/root")
772 def filescan_open(list, session, **kwargs):
773 dev = "/dev/" + (list[0].path).rsplit('/',1)[0][7:]
774 print "mounting device " + dev + " to /mnt/usb..."
775 system("mount "+dev+" /mnt/usb/ -o rw,sync")
776 session.open(NFIDownload,"/mnt/usb/")
778 def filescan(**kwargs):
779 from Components.Scanner import Scanner, ScanPath
781 Scanner(mimetypes = ["application/x-dream-image"],
784 ScanPath(path = "", with_subdirs = False),
787 description = (_("Download .NFI-Files for USB-Flasher")+"..."),
788 openfnc = filescan_open, )