2 from xml.dom.minidom import parse as minidom_parse
3 from os import path as os_path
4 from AutoTimerConfiguration import parseConfig, writeConfig
6 # Navigation (RecordTimer)
7 import NavigationInstance
10 from ServiceReference import ServiceReference
11 from RecordTimer import RecordTimerEntry
12 from Components.TimerSanityCheck import TimerSanityCheck
15 from time import localtime, time
18 from enigma import eEPGCache, eServiceReference
21 from Components.config import config
24 from AutoTimerComponent import AutoTimerComponent
26 XML_CONFIG = "/etc/enigma2/autotimer.xml"
28 def getTimeDiff(timer, begin, end):
29 if begin <= timer.begin <= end:
30 return end - timer.begin
31 elif timer.begin <= begin <= timer.end:
32 return timer.end - begin
35 class AutoTimerIgnoreTimerException(Exception):
36 def __init__(self, cause):
40 return "[AutoTimer] " + str(self.cause)
43 return str(type(self))
46 """Read and save xml configuration, query EPGCache"""
50 self.epgcache = eEPGCache.getInstance()
55 self.uniqueTimerId = 0
56 self.defaultTimer = AutoTimerComponent(
66 # Abort if no config found
67 if not os_path.exists(XML_CONFIG):
68 print "[AutoTimer] No configuration file present"
71 # Parse if mtime differs from whats saved
72 mtime = os_path.getmtime(XML_CONFIG)
73 if mtime == self.configMtime:
74 print "[AutoTimer] No changes in configuration, won't parse"
78 self.configMtime = mtime
81 dom = minidom_parse(XML_CONFIG)
83 # Empty out timers and reset Ids
85 self.uniqueTimerId = 0
86 self.defaultTimer.clear(-1, True)
89 for configuration in dom.getElementsByTagName("autotimer"):
93 configuration.getAttribute("version"),
97 self.uniqueTimerId = len(self.timers)
100 writeConfig(XML_CONFIG, self.defaultTimer, self.timers)
104 def add(self, timer):
105 self.timers.append(timer)
107 def getEnabledTimerList(self):
108 return [x for x in self.timers if x.enabled]
110 def getTimerList(self):
113 def getTupleTimerList(self):
115 return [(x,) for x in list]
117 def getSortedTupleTimerList(self):
118 list = self.timers[:]
120 return [(x,) for x in list]
122 def getUniqueId(self):
123 self.uniqueTimerId += 1
124 return self.uniqueTimerId
126 def remove(self, uniqueId):
128 for timer in self.timers:
129 if timer.id == uniqueId:
134 def set(self, timer):
136 for stimer in self.timers:
138 self.timers[idx] = timer
141 self.timers.append(timer)
145 def parseEPG(self, simulateOnly = False):
146 if NavigationInstance.instance is None:
147 print "[AutoTimer] Navigation is not available, can't parse EPG"
157 # Save Recordings in a dict to speed things up a little
158 # We include processed timers as we might search for duplicate descriptions
160 for timer in NavigationInstance.instance.RecordTimer.timer_list + NavigationInstance.instance.RecordTimer.processed_timers:
161 if not recorddict.has_key(str(timer.service_ref)):
162 recorddict[str(timer.service_ref)] = [timer]
164 recorddict[str(timer.service_ref)].append(timer)
167 for timer in self.getEnabledTimerList():
168 # Search EPG, default to empty list
169 ret = self.epgcache.search(('RI', 100, eEPGCache.PARTIAL_TITLE_SEARCH, timer.match, eEPGCache.NO_CASE_CHECK)) or []
171 for serviceref, eit in ret:
172 eserviceref = eServiceReference(serviceref)
174 evt = self.epgcache.lookupEventId(eserviceref, eit)
176 print "[AutoTimer] Could not create Event!"
179 # Try to determine real service (we always choose the last one)
180 n = evt.getNumOfLinkageServices()
182 i = evt.getLinkageService(eserviceref, n-1)
183 serviceref = i.toString()
186 name = evt.getEventName()
187 description = evt.getShortDescription()
188 begin = evt.getBeginTime()
189 duration = evt.getDuration()
190 end = begin + duration
192 # If event starts in less than 60 seconds skip it
193 if begin < time() + 60:
197 timestamp = localtime(begin)
200 timer.update(begin, timestamp)
202 # Check Duration, Timespan and Excludes
203 if timer.checkServices(serviceref) \
204 or timer.checkDuration(duration) \
205 or timer.checkTimespan(timestamp) \
206 or timer.checkFilter(name, description,
207 evt.getExtendedDescription(), str(timestamp.tm_wday)):
210 if timer.hasOffset():
211 # Apply custom Offset
212 begin, end = timer.applyOffset(begin, end)
215 begin -= config.recording.margin_before.value * 60
216 end += config.recording.margin_after.value * 60
221 # Append to timerlist and abort if simulating
222 timers.append((name, begin, end, serviceref, timer.name))
230 # Check for double Timers
231 # We first check eit and if user wants us to guess event based on time
232 # we try this as backup. The allowed diff should be configurable though.
234 for rtimer in recorddict.get(serviceref, []):
235 if rtimer.eit == eit or config.plugins.autotimer.try_guessing.value and getTimeDiff(rtimer, begin, end) > ((duration/10)*8):
238 # Abort if we don't want to modify timers or timer is repeated
239 if config.plugins.autotimer.refresh.value == "none" or newEntry.repeated:
240 raise AutoTimerIgnoreTimerException("Won't modify existing timer because either no modification allowed or repeated timer")
242 if hasattr(newEntry, "isAutoTimer"):
243 print "[AutoTimer] Modifying existing AutoTimer!"
245 if config.plugins.autotimer.refresh.value != "all":
246 raise AutoTimerIgnoreTimerException("Won't modify existing timer because it's no timer set by us")
247 print "[AutoTimer] Warning, we're messing with a timer which might not have been set by us"
251 # Modify values saved in timer
253 newEntry.description = description
254 newEntry.begin = int(begin)
255 newEntry.end = int(end)
256 newEntry.service_ref = ServiceReference(serviceref)
259 elif timer.getAvoidDuplicateDescription() == 1 and rtimer.description == description:
260 raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
261 if newEntry is None and timer.getAvoidDuplicateDescription() == 2:
262 for list in recorddict.values():
264 if rtimer.description == description:
265 raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
267 except AutoTimerIgnoreTimerException, etite:
271 # Event not yet in Timers
273 if timer.checkCounter(timestamp):
278 print "[AutoTimer] Adding an event."
279 newEntry = RecordTimerEntry(ServiceReference(serviceref), begin, end, name, description, eit)
281 # Mark this entry as AutoTimer (only AutoTimers will have this Attribute set)
282 newEntry.isAutoTimer = True
285 if timer.hasAfterEvent():
286 afterEvent = timer.getAfterEventTimespan(localtime(end))
287 if afterEvent is None:
288 afterEvent = timer.getAfterEvent()
289 if afterEvent is not None:
290 newEntry.afterEvent = afterEvent
292 newEntry.dirname = timer.destination
293 newEntry.justplay = timer.justplay
294 newEntry.tags = timer.tags # This needs my enhanced tag support patch to work
297 if NavigationInstance.instance.RecordTimer.record(newEntry) is None:
299 if recorddict.has_key(serviceref):
300 recorddict[serviceref].append(newEntry)
302 recorddict[serviceref] = [newEntry]
304 # XXX: this won't perform a sanity check, but do we actually want to do so?
305 NavigationInstance.instance.RecordTimer.timeChanged(newEntry)
307 return (total, new, modified, timers)