diff --git a/data/setup.xml b/data/setup.xml index 3d3f5584ec..d66455a528 100755 --- a/data/setup.xml +++ b/data/setup.xml @@ -206,6 +206,7 @@ config.usage.default_path config.usage.timer_path config.usage.instantrec_path + config.recording.setstreamto1 config.recording.asktozap config.recording.margin_before diff --git a/lib/dvb_ci/dvbci.cpp b/lib/dvb_ci/dvbci.cpp index 9451d67abd..45c1db5579 100644 --- a/lib/dvb_ci/dvbci.cpp +++ b/lib/dvb_ci/dvbci.cpp @@ -1027,6 +1027,14 @@ PyObject *eDVBCIInterfaces::readCICaIds(int slotid) return 0; } +int eDVBCIInterfaces::setCIEnabled(int slotid, bool enabled) +{ + eDVBCISlot *slot = getSlot(slotid); + if (slot) + return slot->setEnabled(enabled); + return -1; +} + int eDVBCIInterfaces::setCIClockRate(int slotid, int rate) { singleLock s(m_slot_lock); @@ -1231,6 +1239,20 @@ void eDVBCISlot::data(int what) DEFINE_REF(eDVBCISlot); eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) +{ + char configStr[255]; + slotid = nr; + m_context = context; + state = stateDisabled; + snprintf(configStr, 255, "config.ci.%d.enabled", slotid); + bool enabled = eConfigManager::getConfigBoolValue(configStr, true); + if (enabled) + openDevice(); + else + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 3)); // state disabled +} + +void eDVBCISlot::openDevice() { char filename[128]; @@ -1244,9 +1266,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) plugged = true; m_ci_version = versionUnknown; - slotid = nr; - - sprintf(filename, "/dev/ci%d", nr); + sprintf(filename, "/dev/ci%d", slotid); // possible_caids.insert(0x1702); // possible_providers.insert(providerPair("PREMIERE", 0xC00000)); @@ -1259,7 +1279,7 @@ eDVBCISlot::eDVBCISlot(eMainloop *context, int nr) if (fd >= 0) { - notifier = eSocketNotifier::create(context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); + notifier = eSocketNotifier::create(m_context, fd, eSocketNotifier::Read | eSocketNotifier::Priority | eSocketNotifier::Write); CONNECT(notifier->activated, eDVBCISlot::data); } else { @@ -1273,7 +1293,16 @@ eDVBCISlot::~eDVBCISlot() close(fd); } -void eDVBCISlot::setAppManager( eDVBCIApplicationManagerSession *session ) +void eDVBCISlot::closeDevice() +{ + close(fd); + fd = -1; + notifier->stop(); + data(eSocketNotifier::Priority); + state = stateDisabled; +} + +void eDVBCISlot::setAppManager(eDVBCIApplicationManagerSession *session) { singleLock s(eDVBCIInterfaces::m_slot_lock); application_manager=session; @@ -1607,4 +1636,22 @@ int eDVBCISlot::setClockRate(int rate) return 0; } +int eDVBCISlot::setEnabled(bool enabled) +{ + eDebug("[CI] Slot: %d Enabled: %d, state %d", getSlotID(), enabled, state); + if (enabled && state != stateDisabled) + return 0; + + if (!enabled && state == stateDisabled) + return 0; + + if(enabled) + openDevice(); + else { + closeDevice(); + /* emit */ eDVBCI_UI::getInstance()->m_messagepump.send(eDVBCIInterfaces::Message(eDVBCIInterfaces::Message::slotStateChanged, getSlotID(), 3)); // state disabled + } + return 0; +} + eAutoInitP0 init_eDVBCIInterfaces(eAutoInitNumbers::dvb, "CI Slots"); diff --git a/lib/dvb_ci/dvbci.h b/lib/dvb_ci/dvbci.h index 48dc019b56..def59a6008 100644 --- a/lib/dvb_ci/dvbci.h +++ b/lib/dvb_ci/dvbci.h @@ -66,6 +66,7 @@ class eDVBCISlot: public iObject, public sigc::trackable bool user_mapped; void data(int); bool plugged; + eMainloop *m_context; eDVBCIApplicationManagerSession *getAppManager() { return application_manager; } eDVBCIMMISession *getMMIManager() { return mmi_session; } @@ -85,12 +86,15 @@ class eDVBCISlot: public iObject, public sigc::trackable int setSource(const std::string &source); int setClockRate(int); void determineCIVersion(); + int setEnabled(bool); static std::string getTunerLetter(int tuner_no) { return std::string(1, char(65 + tuner_no)); } public: - enum {stateRemoved, stateInserted, stateInvalid, stateResetted}; + enum {stateRemoved, stateInserted, stateInvalid, stateResetted, stateDisabled}; enum {versionUnknown = -1, versionCI = 0, versionCIPlus1 = 1, versionCIPlus2 = 2}; eDVBCISlot(eMainloop *context, int nr); ~eDVBCISlot(); + void closeDevice(); + void openDevice(); int send(const unsigned char *data, size_t len); @@ -183,6 +187,7 @@ class eDVBCIInterfaces: public eMainloop, private eThread void ciRemoved(eDVBCISlot *slot); int getSlotState(int slot); + int setCIEnabled(int slot, bool enabled); int reset(int slot); int initialize(int slot); int startMMI(int slot); diff --git a/lib/dvb_ci/dvbci_ui.cpp b/lib/dvb_ci/dvbci_ui.cpp index a7adc037b4..d6bb5e787a 100644 --- a/lib/dvb_ci/dvbci_ui.cpp +++ b/lib/dvb_ci/dvbci_ui.cpp @@ -96,5 +96,10 @@ int eDVBCI_UI::setClockRate(int slot, int rate) return eDVBCIInterfaces::getInstance()->setCIClockRate(slot, rate); } +int eDVBCI_UI::setEnabled(int slot, bool enabled) +{ + return eDVBCIInterfaces::getInstance()->setCIEnabled(slot, enabled); +} + //FIXME: correct "run/startlevel" eAutoInitP0 init_dvbciui(eAutoInitNumbers::rc, "DVB-CI UI"); diff --git a/lib/dvb_ci/dvbci_ui.h b/lib/dvb_ci/dvbci_ui.h index d08f257337..fea0964826 100644 --- a/lib/dvb_ci/dvbci_ui.h +++ b/lib/dvb_ci/dvbci_ui.h @@ -34,6 +34,7 @@ class eDVBCI_UI: public eMMI_UI int answerEnq(int slot, char *val); int cancelEnq(int slot); int setClockRate(int slot, int rate); + int setEnabled(int slot, bool enabled); }; #endif diff --git a/lib/python/Components/EpgListGrid.py b/lib/python/Components/EpgListGrid.py index 0c67b8c4be..8b94e531ed 100644 --- a/lib/python/Components/EpgListGrid.py +++ b/lib/python/Components/EpgListGrid.py @@ -527,7 +527,8 @@ def buildEntry(self, service, serviceName, events, picon, channel): duration = ev[3] xpos, ewidth = self.calcEventPosAndWidthHelper(stime, duration, start, end, width) - serviceTimers = self.filteredTimerList.get(':'.join(service.split(':')[:11])) + serviceref = "1" + service[4:] if service[:4] in config.recording.setstreamto1.value else service # converts 4097, 5001, 5002 to 1 + serviceTimers = self.filteredTimerList.get(':'.join(serviceref.split(':')[:11])) if serviceTimers is not None: timer, matchType = RecordTimer.isInTimerOnService(serviceTimers, stime, duration) timerIcon, autoTimerIcon = self.getPixmapsForTimer(timer, matchType, selected) @@ -821,6 +822,7 @@ def snapshotTimers(self, startTime, endTime): # repeat timers represent all their future repetitions, so always include them if (startTime <= timer.end or timer.repeated) and timer.begin < endTime: serviceref = timer.service_ref.ref.toCompareString() + serviceref = "1" + serviceref[4:] if serviceref[:4] in config.recording.setstreamto1.value else serviceref # converts 4097, 5001, 5002 to 1 l = self.filteredTimerList.get(serviceref) if l is None: self.filteredTimerList[serviceref] = l = [timer] diff --git a/lib/python/Components/RecordingConfig.py b/lib/python/Components/RecordingConfig.py index a660ece264..a0cf76f8c3 100644 --- a/lib/python/Components/RecordingConfig.py +++ b/lib/python/Components/RecordingConfig.py @@ -5,6 +5,15 @@ def InitRecordingConfig(): config.recording = ConfigSubsection() # actually this is "recordings always have priority". "Yes" does mean: don't ask. The RecordTimer will ask when value is 0. config.recording.asktozap = ConfigYesNo(default=True) + config.recording.setstreamto1 = ConfigSelection(default=(), choices=[ + ((), _("don't convert")), + (("4097",), _("4097 only")), + (("4097", "5001"), _("4097 + 5001")), + (("4097", "5001", "5002"), _("4097 + 5001 + 5002")), + (("4097", "5002"), _("4097 + 5002")), + (("5001",), _("5001 only")), + (("5001", "5002"), _("5001 + 5002")), + (("5002",), _("5002 only"))]) config.recording.margin_before = ConfigSelectionNumber(min=0, max=120, stepwidth=1, default=3, wraparound=True) config.recording.margin_after = ConfigSelectionNumber(min=0, max=120, stepwidth=1, default=5, wraparound=True) config.recording.split_programme_minutes = ConfigSelectionNumber(min=0, max=30, stepwidth=1, default=15, wraparound=True) diff --git a/lib/python/Components/config.py b/lib/python/Components/config.py index 3831a04f35..4a082d6a53 100644 --- a/lib/python/Components/config.py +++ b/lib/python/Components/config.py @@ -7,7 +7,7 @@ from Components.Harddisk import harddiskmanager from Tools.LoadPixmap import LoadPixmap from copy import copy as copy_copy -from os import path as os_path +from os import fsync, path as os_path, rename, sep from time import localtime, strftime, mktime ACTIONKEY_LEFT = 0 @@ -1908,7 +1908,7 @@ def removedMount(self, mp): x[2] = False def refreshMountpoints(self): - self.mountpoints = [p.mountpoint for p in harddiskmanager.getMountedPartitions() if p.mountpoint != "/"] + self.mountpoints = [p.mountpoint for p in harddiskmanager.getMountedPartitions() if p.mountpoint != sep] self.mountpoints.sort(key=lambda x: -len(x)) def checkChangedMountpoints(self): @@ -1925,7 +1925,7 @@ def checkChangedMountpoints(self): self.addedMount(x) def getMountpoint(self, file): - file = os_path.realpath(file) + "/" + file = os_path.realpath(file) + sep for m in self.mountpoints: if file.startswith(m): return m @@ -2231,18 +2231,17 @@ def unpickle(self, lines, base_file=True): def saveToFile(self, filename): text = self.pickle() try: - import os - f = open(filename + ".writing", "w") - f.write(text) - f.flush() - os.fsync(f.fileno()) - f.close() - os.rename(filename + ".writing", filename) + with open(filename + ".writing", "w", encoding="UTF-8") as f: + f.write(text) + f.flush() + fsync(f.fileno()) + rename(filename + ".writing", filename) except IOError: print("[Config] Couldn't write %s" % filename) def loadFromFile(self, filename, base_file=True): - self.unpickle(open(filename, "r"), base_file) + with open(filename, "r", encoding="UTF-8") as f: + self.unpickle(f, base_file) config = Config() diff --git a/lib/python/RecordTimer.py b/lib/python/RecordTimer.py index 300d3683bb..cf0bf0cfc5 100644 --- a/lib/python/RecordTimer.py +++ b/lib/python/RecordTimer.py @@ -1,26 +1,26 @@ -from boxbranding import getMachineBrand, getMachineName -import os -from enigma import eEPGCache, getBestPlayableServiceReference, eStreamServer, eServiceReference, iRecordableService, quitMainloop, eActionMap, setPreferredTuner, eServiceCenter +from os import access, fsync, makedirs, remove, rename, path as ospath, statvfs, W_OK +from timer import Timer, TimerEntry +import xml.etree.cElementTree +from bisect import insort +from sys import maxsize +from time import localtime, strftime, ctime, time +from enigma import eEPGCache, getBestPlayableServiceReference, eStreamServer, eServiceReference, iRecordableService, quitMainloop, eActionMap, setPreferredTuner, eServiceCenter +from boxbranding import getMachineBrand, getMachineName from Components.config import config +import Components.ParentalControl from Components.UsageConfig import defaultMoviePath from Components.SystemInfo import SystemInfo from Components.TimerSanityCheck import TimerSanityCheck import Screens.InfoBar -import Components.ParentalControl from Screens.MessageBox import MessageBox from Screens.PictureInPicture import PictureInPicture import Screens.Standby from Tools import Directories, Notifications, ASCIItranslit, Trashcan from Tools.XMLTools import stringToXML -from timer import Timer, TimerEntry -import xml.etree.cElementTree import NavigationInstance -from time import localtime, strftime, ctime, time -from bisect import insort -from sys import maxsize # ok, for descriptions etc we have: # service reference (to get the service name) @@ -85,14 +85,14 @@ def findSafeRecordPath(dirname): if not dirname: return None from Components import Harddisk - dirname = os.path.realpath(dirname) + dirname = ospath.realpath(dirname) mountpoint = Harddisk.findMountPoint(dirname) - if not os.path.ismount(mountpoint): + if not ospath.ismount(mountpoint): print("[RecordTimer] media is not mounted:", dirname) return None - if not os.path.isdir(dirname): + if not ospath.isdir(dirname): try: - os.makedirs(dirname) + makedirs(dirname) except Exception as ex: print("[RecordTimer] Failed to create dir '%s':" % dirname, ex) return None @@ -124,8 +124,8 @@ def SetIconDisplay(nrec): return (wdev, max_states) = SID_code_states if nrec == 0: # An absolute setting - clear it... - f = open(wdev, 'w') - f.write('0') + f = open(wdev, "w") + f.write("0") f.close() return # @@ -134,7 +134,7 @@ def SetIconDisplay(nrec): sym = max_states if sym < 0: # Sanity check - just in case... sym = 0 - f = open(wdev, 'w') + f = open(wdev, "w") f.write(str(sym)) f.close() return @@ -177,14 +177,14 @@ def RecordingsState(alter): # type 2 = digital radio sound service # type 10 = advanced codec digital radio sound service -service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 134) || (type == 195)' +service_types_tv = "1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 22) || (type == 25) || (type == 134) || (type == 195)" wasRecTimerWakeup = False # please do not translate log messages class RecordTimerEntry(TimerEntry): - def __init__(self, serviceref, begin, end, name, description, eit, disabled=False, justplay=False, afterEvent=AFTEREVENT.AUTO, checkOldTimers=False, dirname=None, tags=None, descramble='notset', record_ecm='notset', isAutoTimer=False, always_zap=False, rename_repeat=True, conflict_detection=True, pipzap=False, autoTimerId=None): + def __init__(self, serviceref, begin, end, name, description, eit, disabled=False, justplay=False, afterEvent=AFTEREVENT.AUTO, checkOldTimers=False, dirname=None, tags=None, descramble="notset", record_ecm="notset", isAutoTimer=False, always_zap=False, rename_repeat=True, conflict_detection=True, pipzap=False, autoTimerId=None): TimerEntry.__init__(self, int(begin), int(end)) if checkOldTimers: if self.begin < time() - 1209600: @@ -195,10 +195,14 @@ def __init__(self, serviceref, begin, end, name, description, eit, disabled=Fals assert isinstance(serviceref, eServiceReference) + if serviceref and serviceref.toString()[:4] in config.recording.setstreamto1.value: # check if to convert IPTV services (4097, etc) to "1" + serviceref = eServiceReference("1" + serviceref.toString()[4:]) + if serviceref and serviceref.isRecordable(): self.service_ref = serviceref else: self.service_ref = eServiceReference() + # print("[RecordTimer][RecordTimerEntry2] serviceref", self.service_ref) self.eit = eit self.dontSave = False self.name = name @@ -218,14 +222,14 @@ def __init__(self, serviceref, begin, end, name, description, eit, disabled=Fals self.tags = tags or [] self.conflict_detection = conflict_detection - if descramble == 'notset' and record_ecm == 'notset': - if config.recording.ecm_data.value == 'descrambled+ecm': + if descramble == "notset" and record_ecm == "notset": + if config.recording.ecm_data.value == "descrambled+ecm": self.descramble = True self.record_ecm = True - elif config.recording.ecm_data.value == 'scrambled+ecm': + elif config.recording.ecm_data.value == "scrambled+ecm": self.descramble = False self.record_ecm = True - elif config.recording.ecm_data.value == 'normal': + elif config.recording.ecm_data.value == "normal": self.descramble = True self.record_ecm = False else: @@ -237,7 +241,7 @@ def __init__(self, serviceref, begin, end, name, description, eit, disabled=Fals if SystemInfo["DVB-T_priority_tuner_available"] or SystemInfo["DVB-C_priority_tuner_available"] or SystemInfo["DVB-S_priority_tuner_available"] or SystemInfo["ATSC_priority_tuner_available"]: rec_ref = self.service_ref and self.service_ref.ref str_service = rec_ref and rec_ref.toString() - if str_service and '%3a//' not in str_service and not str_service.rsplit(":", 1)[1].startswith("/"): + if str_service and "%3a//" not in str_service and not str_service.rsplit(":", 1)[1].startswith("/"): type_service = rec_ref.getUnsignedData(4) >> 16 if type_service == 0xEEEE: if SystemInfo["DVB-T_priority_tuner_available"] and config.usage.recording_frontend_priority_dvbt.value != "-2": @@ -292,12 +296,12 @@ def freespace(self): return False self.MountPath = dirname - mountwriteable = os.access(dirname, os.W_OK) + mountwriteable = access(dirname, W_OK) if not mountwriteable: self.log(0, ("Mount '%s' is not writeable." % dirname)) return False - s = os.statvfs(dirname) + s = statvfs(dirname) if (s.f_bavail * s.f_bsize) // 1000000 < 1024: self.log(0, "Not enough free space to record") return False @@ -321,7 +325,7 @@ def calculateFilename(self, name=None): filename = begin_date + " - " + service_name if name: if config.recording.filename_composition.value == "event": - filename = name + ' - ' + begin_date + "_" + service_name + filename = name + " - " + begin_date + "_" + service_name elif config.recording.filename_composition.value == "short": filename = strftime("%Y%m%d", localtime(self.begin)) + " - " + name elif config.recording.filename_composition.value == "long": @@ -470,16 +474,14 @@ def _bouquet_search(self): ChannelSelectionInstance.addToHistory(self.service_ref.ref) NavigationInstance.instance.playService(self.service_ref.ref) -# Report the tuner that the current recording is using - def log_tuner(self, level, state): -# If we have a Zap timer then the tuner is for the current service - if self.justplay: + def log_tuner(self, level, state): # Report the tuner that the current recording is using + if self.justplay: # If we have a Zap timer then the tuner is for the current service timer_rs = NavigationInstance.instance.getCurrentService() else: timer_rs = self.record_service feinfo = timer_rs and hasattr(timer_rs, "frontendInfo") and timer_rs.frontendInfo() fedata = feinfo and hasattr(feinfo, "getFrontendData") and feinfo.getFrontendData() - tuner_info = fedata and "tuner_number" in fedata and chr(ord('A') + fedata.get("tuner_number")) or "(fallback) stream" + tuner_info = fedata and "tuner_number" in fedata and chr(ord("A") + fedata.get("tuner_number")) or "(fallback) stream" self.log(level, "%s recording on tuner: %s" % (state, tuner_info)) def activate(self): @@ -540,12 +542,14 @@ def activate(self): return True self.log(7, "prepare failed") if eStreamServer.getInstance().getConnectedClients(): + self.log(71, "eStreamerServer client - stop") eStreamServer.getInstance().stopStream() return False if self.first_try_prepare or (self.ts_dialog is not None and not self.checkingTimeshiftRunning()): self.first_try_prepare = False cur_ref = NavigationInstance.instance.getCurrentlyPlayingServiceReference() - if cur_ref and not cur_ref.getPath(): + rec_ref = self.service_ref and self.service_ref.ref + if cur_ref and not cur_ref.getPath() or rec_ref.toString()[:4] in config.recording.setstreamto1.value: # "or" check if IPTV services (4097, etc) if self.always_zap: return False if Screens.Standby.inStandby: @@ -576,9 +580,9 @@ def activate(self): # Both see the file as existing, but only one can delete it... # with wasrec_lock: - if os.path.exists("/tmp/was_rectimer_wakeup") and not wasRecTimerWakeup: + if ospath.exists("/tmp/was_rectimer_wakeup") and not wasRecTimerWakeup: wasRecTimerWakeup = int(open("/tmp/was_rectimer_wakeup", "r").read()) and True or False - os.remove("/tmp/was_rectimer_wakeup") + remove("/tmp/was_rectimer_wakeup") self.autostate = Screens.Standby.inStandby @@ -609,7 +613,7 @@ def activate(self): if cur_ref_group and cur_ref_group != self.service_ref.ref and self.InfoBarInstance and hasattr(self.InfoBarInstance.session, 'pipshown') and not Components.ParentalControl.parentalControl.isProtected(self.service_ref.ref): if self.InfoBarInstance.session.pipshown: hasattr(self.InfoBarInstance, "showPiP") and self.InfoBarInstance.showPiP() - if hasattr(self.InfoBarInstance.session, 'pip'): + if hasattr(self.InfoBarInstance.session, "pip"): del self.InfoBarInstance.session.pip self.InfoBarInstance.session.pipshown = False self.InfoBarInstance.session.pip = self.InfoBarInstance.session.instantiateDialog(PictureInPicture) @@ -696,8 +700,8 @@ def activate(self): return True from Components.Converter.ClientsStreaming import ClientsStreaming if (not Screens.Standby.inStandby and NavigationInstance.instance.getCurrentlyPlayingServiceReference() and - ('0:0:0:0:0:0:0:0:0' in NavigationInstance.instance.getCurrentlyPlayingServiceReference().toString() or - '4097:' in NavigationInstance.instance.getCurrentlyPlayingServiceReference().toString()) + ("0:0:0:0:0:0:0:0:0" in NavigationInstance.instance.getCurrentlyPlayingServiceReference().toString() or + "4097:" in NavigationInstance.instance.getCurrentlyPlayingServiceReference().toString()) ): return True @@ -734,7 +738,7 @@ def activate(self): def keypress(self, key=None, flag=1): if flag and self.wasInStandby: self.wasInStandby = False - eActionMap.getInstance().unbindAction('', self.keypress) + eActionMap.getInstance().unbindAction("", self.keypress) def setAutoincreaseEnd(self, entry=None): if not self.autoincrease: @@ -858,9 +862,9 @@ def failureCB(self, answer): self.log(13, "ok, zapped away") #NavigationInstance.instance.stopUserServices() self._bouquet_search() - if not self.first_try_prepare and self.InfoBarInstance and hasattr(self.InfoBarInstance.session, 'pipshown') and self.InfoBarInstance.session.pipshown: + if not self.first_try_prepare and self.InfoBarInstance and hasattr(self.InfoBarInstance.session, "pipshown") and self.InfoBarInstance.session.pipshown: hasattr(self.InfoBarInstance, "showPiP") and self.InfoBarInstance.showPiP() - if hasattr(self.InfoBarInstance.session, 'pip'): + if hasattr(self.InfoBarInstance.session, "pip"): del self.InfoBarInstance.session.pip self.InfoBarInstance.session.pipshown = False else: @@ -907,13 +911,13 @@ def gotRecordEvent(self, record, event): # we have record_service as property to automatically subscribe to record service events def setRecordService(self, service): if self.__record_service is not None: -# print("[RecordTimer][remove callback]") + # print("[RecordTimer][remove callback]") NavigationInstance.instance.record_event.remove(self.gotRecordEvent) self.__record_service = service if self.__record_service is not None: -# print("[RecordTimer][add callback]") + # print("[RecordTimer][add callback]") NavigationInstance.instance.record_event.append(self.gotRecordEvent) record_service = property(lambda self: self.__record_service, setRecordService) @@ -922,7 +926,8 @@ def setRecordService(self, service): def createTimer(xml): begin = int(xml.get("begin")) end = int(xml.get("end")) - serviceref = eServiceReference(str(xml.get("serviceref"))) + pre_serviceref = xml.get("serviceref") + serviceref = eServiceReference("1" + pre_serviceref[4:]) if pre_serviceref[:4] in config.recording.setstreamto1.value else eServiceReference(pre_serviceref) # check if to convert IPTV services (4097, etc) to "1" description = str(xml.get("description")) repeated = str(xml.get("repeated")) rename_repeat = int(xml.get("rename_repeat") or "1") @@ -980,12 +985,13 @@ def __init__(self): def doActivate(self, w, dosave=True): # when activating a timer for servicetype 4097, # and SystemApp has player enabled, then skip recording. - if "4097:" in w.service_ref.toString() and Directories.isPluginInstalled("ServiceApp") and config.plugins.serviceapp.servicemp3.replace.value == True: + # Or always skip if in ("5001", "5002") as these cannot be recorded. + if w.service_ref.toString().startswith("4097:") and Directories.isPluginInstalled("ServiceApp") and config.plugins.serviceapp.servicemp3.replace.value == True or w.service_ref.toString()[:4] in ("5001", "5002"): print("[RecordTimer][doActivate] found Serviceapp & player enabled - disable this timer recording") w.state = RecordTimerEntry.StateEnded from Tools.Notifications import AddPopup from Screens.MessageBox import MessageBox - AddPopup(_("Recording IPTV 4097 with systemapp enabled, timer ended!\nPlease recheck it!"), type=MessageBox.TYPE_ERROR, timeout=0, id="TimerRecordingFailed") + AddPopup(_("Recording IPTV with systemapp enabled, timer ended!\nPlease recheck it!"), type=MessageBox.TYPE_ERROR, timeout=0, id="TimerRecordingFailed") # when activating a timer which has already passed, # simply abort the timer. don't run trough all the stages. elif w.shouldSkip(): @@ -1001,9 +1007,7 @@ def doActivate(self, w, dosave=True): self.timer_list.remove(w) except: print("[RecordTimer] Remove list failed") - - # did this timer reached the last state? - if w.state < RecordTimerEntry.StateEnded: + if w.state < RecordTimerEntry.StateEnded: # did this timer reached the last state? # no, sort it into active list insort(self.timer_list, w) else: @@ -1046,9 +1050,7 @@ def isRecording(self): return True return False - # justLoad is passed on to record() - # - def loadTimer(self, justLoad=False): + def loadTimer(self, justLoad=False): # justLoad is passed on to record() try: file = open(self.Filename, 'r') doc = xml.etree.cElementTree.parse(file) @@ -1061,7 +1063,7 @@ def loadTimer(self, justLoad=False): print("[RecordTimer] timers.xml failed to load!") try: - os.rename(self.Filename, self.Filename + "_old") + rename(self.Filename, self.Filename + "_old") except (IOError, OSError): print("[RecordTimer] renaming broken timer failed") return @@ -1174,9 +1176,9 @@ def saveTimer(self): file.writelines(list) file.flush() - os.fsync(file.fileno()) + fsync(file.fileno()) file.close() - os.rename(self.Filename + ".writing", self.Filename) + rename(self.Filename + ".writing", self.Filename) def getNextZapTime(self): now = time() @@ -1366,7 +1368,7 @@ def isInTimer(self, service, begin, duration): for timer in self.timer_list: # repeat timers represent all their future repetitions, so always include them if (startAt <= timer.end or timer.repeated) and timer.begin < endAt: - check = timer.service_ref.toCompareString() == refstr + check = timer.service_ref.toCompareString().split(":", 2)[2] == refstr.split(":", 2)[2] if check: matchType = RecordTimer.__checkTimer(timer, check_offset_time, begin, end, duration) if matchType is not None: @@ -1390,7 +1392,7 @@ def isInTimerOnService(serviceTimerList, begin, duration): return returnValue or (None, None) def removeEntry(self, entry): - # print("[RecordTimer] Remove " + str(entry)) + # print("[RecordTimer] Remove " + str(entry)) # avoid re-enqueuing entry.repeated = False diff --git a/lib/python/Screens/About.py b/lib/python/Screens/About.py index 9be48f6ffe..8243dbe82c 100644 --- a/lib/python/Screens/About.py +++ b/lib/python/Screens/About.py @@ -332,7 +332,7 @@ def Stage1Complete(self, result, retval, extra_args=None): if pathExists("/media/autofs"): for entry in sorted(listdir("/media/autofs")): mountEntry = path.join("/media/autofs", entry) - self.mountinfo += _("\n %s is also enabled for autofs network mount" % (mountEntry)) + self.mountinfo += _("\n %s is also enabled for autofs network mount") % (mountEntry) if self.mountinfo: self["mounts"].setText(self.mountinfo) else: diff --git a/lib/python/Screens/Ci.py b/lib/python/Screens/Ci.py index 79d48d3e90..cadced46f0 100644 --- a/lib/python/Screens/Ci.py +++ b/lib/python/Screens/Ci.py @@ -13,10 +13,11 @@ forceNotShowCiMessages = False - def setCIBitrate(configElement): eDVBCI_UI.getInstance().setClockRate(configElement.slotid, eDVBCI_UI.rateNormal if configElement.value == "no" else eDVBCI_UI.rateHigh) +def setCIEnabled(configElement): + eDVBCI_UI.getInstance().setEnabled(configElement.slotid, configElement.value) def setdvbCiDelay(configElement): open(SystemInfo["CommonInterfaceCIDelay"], "w").write(configElement.value) @@ -33,6 +34,9 @@ def InitCiConfig(): if SystemInfo["CommonInterface"]: for slot in range(SystemInfo["CommonInterface"]): config.ci.append(ConfigSubsection()) + config.ci[slot].enabled = ConfigYesNo(default=True) + config.ci[slot].enabled.slotid = slot + config.ci[slot].enabled.addNotifier(setCIEnabled) config.ci[slot].canDescrambleMultipleServices = ConfigSelection(choices=[("auto", _("auto")), ("no", _("no")), ("yes", _("yes"))], default="auto") config.ci[slot].use_static_pin = ConfigYesNo(default=True) config.ci[slot].static_pin = ConfigPIN(default=0) @@ -433,6 +437,7 @@ def appendEntries(self, slot, state): self.state[slot] = state if self.slot > 1: self.list.append(("**************************", ConfigNothing(), 3, slot)) + self.list.append((_("CI %s enabled" % (slot)), config.ci[slot].enabled, -1, slot)) self.list.append((_("Reset"), ConfigNothing(), 0, slot)) self.list.append((_("Init"), ConfigNothing(), 1, slot)) @@ -443,7 +448,11 @@ def appendEntries(self, slot, state): elif self.state[slot] == 2: #module ready appname = eDVBCI_UI.getInstance().getAppName(slot) self.list.append((appname, ConfigNothing(), 2, slot)) - self.list.append(getConfigListEntry(_("Set pin code persistent"), config.ci[slot].use_static_pin, 3, slot)) + elif self.state[slot] == 3: # module disabled by the user + self.list.append((_("module disabled"), ConfigNothing(), 2, slot)) + return + + self.list.append(getConfigListEntry(_("Set persistent PIN code"), config.ci[slot].use_static_pin, 3, slot)) self.list.append((_("Enter persistent PIN code"), ConfigNothing(), 5, slot)) self.list.append((_("Reset persistent PIN code"), ConfigNothing(), 6, slot)) self.list.append(getConfigListEntry(_("Show CI messages"), config.ci[slot].show_ci_messages, 3, slot)) @@ -465,6 +474,7 @@ def updateState(self, slot): if slot > 0: slotidx += 1 #do not change separator + slotidx += 1 #do not change CI Enabled slotidx += 1 #do not change Reset slotidx += 1 #do not change Init @@ -475,7 +485,11 @@ def updateState(self, slot): elif state == 2: #module ready appname = eDVBCI_UI.getInstance().getAppName(slot) self.list[slotidx] = (appname, ConfigNothing(), 2, slot) - + if len(self.list) <= slotidx + 1: + self.list = [] + self.appendEntries(slot, state) + elif state == 3: + self.list = self.list[0:slotidx+1] lst = self["entries"] lst.list = self.list lst.l.setList(self.list)