From: hschang Date: Thu, 22 Feb 2018 05:14:01 +0000 (+0900) Subject: Fix default recording path and usb recording. X-Git-Url: http://code.vuplus.com/gitweb/?p=vuplus_dvbapp;a=commitdiff_plain;h=1d557af556c71a9c658deea9cec783a66903c136 Fix default recording path and usb recording. --- diff --git a/RecordTimer.py b/RecordTimer.py index 32fb923..c3e9de7 100755 --- a/RecordTimer.py +++ b/RecordTimer.py @@ -18,6 +18,8 @@ from ServiceReference import ServiceReference from time import localtime, strftime, ctime, time from bisect import insort +import os + # ok, for descriptions etc we have: # service reference (to get the service name) # name (title) @@ -47,6 +49,25 @@ class AFTEREVENT: DEEPSTANDBY = 2 AUTO = 3 +def findSafeRecordPath(dirname): + if not dirname: + return None + + from Components import Harddisk + dirname = os.path.realpath(dirname) + mountpoint = Harddisk.findMountPoint(dirname) + if mountpoint in ('/', '/media'): + print '[RecordTimer] media is not mounted:', dirname + return None + if not os.path.isdir(dirname): + try: + os.makedirs(dirname) + except Exception, ex: + print '[RecordTimer] Failed to create dir "%s":' % dirname, ex + return None + + return dirname + # please do not translate log messages class RecordTimerEntry(timer.TimerEntry, object): ######### the following static methods and members are only in use when the box is in (soft) standby @@ -164,21 +185,31 @@ class RecordTimerEntry(timer.TimerEntry, object): if config.recording.ascii_filenames.value: filename = ASCIItranslit.legacyEncode(filename) - if not self.dirname or not Directories.fileExists(self.dirname, 'w'): - if self.dirname: - self.dirnameHadToFallback = True - dirname = defaultMoviePath() + if not self.dirname: + dirname = findSafeRecordPath(defaultMoviePath()) else: - dirname = self.dirname + dirname = findSafeRecordPath(self.dirname) + if dirname is None: + dirname = findSafeRecordPath(defaultMoviePath()) + self.dirnameHadToFallback = True + + if not dirname: + return None + self.Filename = Directories.getRecordingFilename(filename, dirname) self.log(0, "Filename calculated as: '%s'" % self.Filename) #begin_date + " - " + service_name + description) + return self.Filename def tryPrepare(self): if self.justplay: return True else: - self.calculateFilename() + if not self.calculateFilename(): + self.do_backoff() + self.start_prepare = time() + self.backoff + return False + rec_ref = self.service_ref and self.service_ref.ref if rec_ref and rec_ref.flags & eServiceReference.isGroup: rec_ref = getBestPlayableServiceReference(rec_ref, eServiceReference()) @@ -410,6 +441,18 @@ class RecordTimerEntry(timer.TimerEntry, object): record_service = property(lambda self: self.__record_service, setRecordService) + def isUsbRecordingPath(self): + dirname = None + + if self.dirname: + dirname = findSafeRecordPath(self.dirname) + + if dirname is None: + dirname = findSafeRecordPath(defaultMoviePath()) + + from Components import Harddisk + return Harddisk.isUsbStorage(dirname) + def createTimer(xml): begin = int(xml.get("begin")) end = int(xml.get("end")) @@ -466,6 +509,18 @@ class RecordTimer(timer.Timer): print "unable to load timers from file!" def doActivate(self, w): + if w.state == RecordTimerEntry.StateWaiting: + from Components.SystemInfo import SystemInfo + if SystemInfo.get("DisableUsbRecord", True) and w.isUsbRecordingPath(): + service_name = w.service_ref.getServiceName() + self.timer_list.remove(w) + if w.dontSave is False: + w.resetState() + w.disable() + self.addTimerEntry(w) + Notifications.AddNotification(MessageBox, _("Can not recording on a USB storage.\nService name : %s"% service_name), MessageBox.TYPE_ERROR) + return + # when activating a timer which has already passed, # simply abort the timer. don't run trough all the stages. if w.shouldSkip(): diff --git a/lib/python/Components/Harddisk.py b/lib/python/Components/Harddisk.py index 0e73dee..9b3a684 100755 --- a/lib/python/Components/Harddisk.py +++ b/lib/python/Components/Harddisk.py @@ -58,6 +58,56 @@ def enableUdevEvent(enable = True): print "CMD : ", cmd system(cmd) +def findMountPoint(path): + 'Example: findMountPoint("/media/hdd/some/file") returns "/media/hdd"' + path = os.path.abspath(path) + while not os.path.ismount(path): + path = os.path.dirname(path) + return path + +def getDeviceFile(dev_path): + for parts in getProcMounts(): + if os.path.realpath(parts[1]).startswith(dev_path): + return parts[0] + +def getMountPath(mountPath): + mountPath = os.path.realpath(mountPath) + while not os.path.ismount(mountPath): + mountPath = os.path.dirname(mountPath) + + return mountPath + +def getDeviceInterface(mountPath): + mountPath = getMountPath(mountPath) + + if mountPath == '/': + return None + + from Components.Harddisk import getDeviceFile + dev = getDeviceFile(mountPath) + + if dev and dev.startswith("/dev/sd"): + dev = os.path.basename(dev) + phyPath = os.path.realpath('/sys/block/' + dev[:3]) + + # check usb + for x in glob.glob("/sys/bus/usb/devices/usb*"): + if phyPath.find(os.path.realpath(x)) != -1: + from Tools.HardwareInfo import HardwareInfo + if (HardwareInfo().get_vu_device_name() == "zero4k") and (phyPath.find("f0b00500.ehci_v2/usb2/2-1") != -1): + return "ata" + else: + return "usb" + + # check ata + if phyPath.find("/ata") != -1: + return "ata" + + return None + +def isUsbStorage(dirname): + return getDeviceInterface(dirname) in (None, "usb") + DEVTYPE_UDEV = 0 DEVTYPE_DEVFS = 1 diff --git a/lib/python/Components/SystemInfo.py b/lib/python/Components/SystemInfo.py index e4bae61..5b01c4c 100644 --- a/lib/python/Components/SystemInfo.py +++ b/lib/python/Components/SystemInfo.py @@ -34,4 +34,5 @@ SystemInfo["WOWLSupport"] = HardwareInfo().get_vu_device_name() == "ultimo4k" SystemInfo["ScrambledPlayback"] = HardwareInfo().get_vu_device_name() in ("solo4k", "ultimo4k", "uno4kse", "zero4k") SystemInfo["FastChannelChange"] = fileExists("/proc/stb/frontend/fbc/fcc") SystemInfo["MiniTV"] = fileExists("/proc/stb/lcd/live_enable") +SystemInfo["DisableUsbRecord"] = HardwareInfo().get_vu_device_name() in ("solo4k", "uno4kse", "zero4k") diff --git a/lib/python/Components/UsageConfig.py b/lib/python/Components/UsageConfig.py index d262448..36db2ad 100644 --- a/lib/python/Components/UsageConfig.py +++ b/lib/python/Components/UsageConfig.py @@ -1,6 +1,7 @@ from Components.Harddisk import harddiskmanager from Components.NimManager import nimmanager from config import ConfigSubsection, ConfigYesNo, config, ConfigSelection, ConfigText, ConfigNumber, ConfigSet, ConfigLocations +from Tools.Directories import defaultRecordingLocation from Tools.Directories import resolveFilename, SCOPE_HDD from enigma import Misc_Options, eEnv from enigma import setTunerTypePriorityOrder, setPreferredTuner @@ -35,7 +36,7 @@ def InitUsageConfig(): ("standard", _("standard")), ("swap", _("swap PiP and main picture")), ("swapstop", _("move PiP to main picture")), ("stop", _("stop PiP")) ]) - config.usage.default_path = ConfigText(default = resolveFilename(SCOPE_HDD)) + config.usage.default_path = ConfigText(default = "") config.usage.timer_path = ConfigText(default = "") config.usage.instantrec_path = ConfigText(default = "") config.usage.timeshift_path = ConfigText(default = "/media/hdd/") @@ -226,7 +227,7 @@ def updateChoices(sel, choices): sel.setChoices(map(str, choices), defval) def preferredPath(path): - if config.usage.setup_level.index < 2 or path == "": + if config.usage.setup_level.index < 2 or path == "" or not path: return None # config.usage.default_path.value, but delay lookup until usage elif path == "": return config.movielist.last_videodir.value @@ -242,5 +243,5 @@ def preferredInstantRecordPath(): return preferredPath(config.usage.instantrec_path.value) def defaultMoviePath(): - return config.usage.default_path.value + return defaultRecordingLocation(config.usage.default_path.value) diff --git a/lib/python/Screens/InfoBarGenerics.py b/lib/python/Screens/InfoBarGenerics.py index cce091e..0b01bf8 100755 --- a/lib/python/Screens/InfoBarGenerics.py +++ b/lib/python/Screens/InfoBarGenerics.py @@ -39,7 +39,7 @@ from time import time, localtime, strftime from os import stat as os_stat, system as os_system from bisect import insort -from RecordTimer import RecordTimerEntry, RecordTimer +from RecordTimer import RecordTimerEntry, RecordTimer, findSafeRecordPath # hack alert! from Menu import MainMenu, mdom @@ -1223,6 +1223,13 @@ class InfoBarTimeshift: if self.timeshift_enabled: print "hu, timeshift already enabled?" else: + from Components import Harddisk + if Harddisk.getMountPath(config.usage.timeshift_path.value) != '/' and \ + SystemInfo.get("DisableUsbRecord", True) and \ + Harddisk.isUsbStorage(config.usage.timeshift_path.value): + self.session.open(MessageBox, _("Timeshift not possible on a USB storage."), MessageBox.TYPE_ERROR) + return 0 + if not ts.startTimeshift(): self.timeshift_enabled = 1 @@ -1663,18 +1670,14 @@ class InfoBarInstantRecord: self.session.nav.RecordTimer.timeChanged(entry) def instantRecord(self): - dir = preferredInstantRecordPath() - if not dir or not fileExists(dir, 'w'): - dir = defaultMoviePath() - if not fileExists("/hdd", 0): print "not found /hdd" os_system("ln -s /media/hdd /hdd") -# - try: - stat = os_stat(dir) - except: - # XXX: this message is a little odd as we might be recording to a remote device + + recPath = preferredInstantRecordPath() + if not findSafeRecordPath(recPath) and not findSafeRecordPath(defaultMoviePath()): + if not recPath: + recPath = "" self.session.open(MessageBox, _("No HDD found or HDD not initialized!"), MessageBox.TYPE_ERROR) return diff --git a/lib/python/Screens/RecordPaths.py b/lib/python/Screens/RecordPaths.py index 22ca9fc..55159d9 100644 --- a/lib/python/Screens/RecordPaths.py +++ b/lib/python/Screens/RecordPaths.py @@ -36,16 +36,16 @@ class RecordPathsSettings(Screen,ConfigListScreen): }, -2) def checkReadWriteDir(self, configele): + value = configele.value print "checkReadWrite: ", configele.value - if configele.value in [x[0] for x in self.styles] or fileExists(configele.value, "w"): - configele.last_value = configele.value + if not value or value in [x[0] for x in self.styles] or fileExists(value, "w"): + configele.last_value = value return True else: - dir = configele.value configele.value = configele.last_value self.session.open( MessageBox, - _("The directory %s is not writable.\nMake sure you select a writable directory instead.")%dir, + _("The directory %s is not writable.\nMake sure you select a writable directory instead.") % value, type = MessageBox.TYPE_ERROR ) return False @@ -55,11 +55,11 @@ class RecordPathsSettings(Screen,ConfigListScreen): styles_keys = [x[0] for x in self.styles] tmp = config.movielist.videodirs.value default = config.usage.default_path.value - if default not in tmp: + if default and default not in tmp: tmp = tmp[:] tmp.append(default) print "DefaultPath: ", default, tmp - self.default_dirname = ConfigSelection(default = default, choices = tmp) + self.default_dirname = ConfigSelection(default = default, choices = [("", _(""))] + tmp) tmp = config.movielist.videodirs.value default = config.usage.timer_path.value if default not in tmp and default not in styles_keys: @@ -148,10 +148,10 @@ class RecordPathsSettings(Screen,ConfigListScreen): styles_keys = [x[0] for x in self.styles] tmp = config.movielist.videodirs.value default = self.default_dirname.value - if default not in tmp: + if default and default not in tmp: tmp = tmp[:] tmp.append(default) - self.default_dirname.setChoices(tmp, default=default) + self.default_dirname.setChoices([("", _(""))] + tmp, default=default) tmp = config.movielist.videodirs.value default = self.timer_dirname.value if default not in tmp and default not in styles_keys: diff --git a/lib/python/Tools/Directories.py b/lib/python/Tools/Directories.py index f0ef0de..b886459 100755 --- a/lib/python/Tools/Directories.py +++ b/lib/python/Tools/Directories.py @@ -17,6 +17,8 @@ try: except: have_utime = False +import os + SCOPE_TRANSPONDERDATA = 0 SCOPE_SYSETC = 1 SCOPE_FONTS = 2 @@ -151,11 +153,64 @@ def resolveFilename(scope, base = "", path_prefix = None): return path + base # this is only the BASE - an extension must be added later. -def pathExists(path): - return os_path.exists(path) +pathExists = os.path.exists +isMount = os.path.ismount + +def bestRecordingLocation(candidates): + path = '' + + from Components import Harddisk + ata_devices = [candidate for candidate in candidates if Harddisk.getDeviceInterface(candidate[1]) == "ata"] + + if len(ata_devices) == 1: + path = ata_devices[0][1] + + elif len(ata_devices): + best = "" + for device in ata_devices: + dev = os.path.basename(device[0]) + if not best or (best > dev): + best = dev + path = device[1] + else: # Find the largest usb disk + biggest = 0 + for candidate in candidates: + try: + stat = os.statvfs(candidate[1]) + # must have some free space (i.e. not read-only) + if stat.f_bavail: + # Free space counts double + size = (stat.f_blocks + stat.f_bavail) * stat.f_bsize + if size > biggest: + path = candidate[1] + biggest = size + except Exception, e: + print "[DRL]", e -def isMount(path): - return os_path.ismount(path) + return path + +def defaultRecordingLocation(candidate=None): + if candidate and os.path.exists(candidate): + return candidate + # First, try whatever /hdd points to, or /media/hdd + try: + path = os.path.realpath('/hdd') + except: + path = '/media/hdd' + if not os.path.exists(path) or not os.path.ismount(path): + path = '' + from Components import Harddisk + mounts = [m for m in Harddisk.getProcMounts() if m[1].startswith('/media/')] + path = bestRecordingLocation([m for m in mounts if m[0].startswith('/dev/')]) + if path: + # If there's a movie subdir, we'd probably want to use that. + movie = os.path.join(path, 'movie') + if os.path.isdir(movie): + path = movie + if not path.endswith('/'): + path += '/' # Bad habits die hard, old code relies on this + + return path def createDir(path, makeParents = False): try: @@ -188,6 +243,9 @@ def fileExists(f, mode='r'): return access(f, acc_mode) def getRecordingFilename(basename, dirname = None): + if not dirname.endswith('/'): + dirname += '/' + # filter out non-allowed characters non_allowed_characters = "/.\\:*?<>|\"" filename = "" diff --git a/timer.py b/timer.py index aaae0b2..d58a83e 100644 --- a/timer.py +++ b/timer.py @@ -232,6 +232,10 @@ class Timer: self.setNextActivation(min) def timeChanged(self, timer): + if timer not in (self.processed_timers + self.timer_list): + print "timer not found" + return + print "time changed" timer.timeChanged() if timer.state == TimerEntry.StateEnded: