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))
229 # Check for double Timers
230 # We first check eit and if user wants us to guess event based on time
231 # we try this as backup. The allowed diff should be configurable though.
233 for rtimer in recorddict.get(serviceref, []):
234 if rtimer.eit == eit or config.plugins.autotimer.try_guessing.value and getTimeDiff(rtimer, begin, end) > ((duration/10)*8):
237 # Abort if we don't want to modify timers or timer is repeated
238 if config.plugins.autotimer.refresh.value == "none" or newEntry.repeated:
239 raise AutoTimerIgnoreTimerException("Won't modify existing timer because either no modification allowed or repeated timer")
241 if hasattr(newEntry, "isAutoTimer"):
242 print "[AutoTimer] Modifying existing AutoTimer!"
244 if config.plugins.autotimer.refresh.value != "all":
245 raise AutoTimerIgnoreTimerException("Won't modify existing timer because it's no timer set by us")
246 print "[AutoTimer] Warning, we're messing with a timer which might not have been set by us"
248 func = NavigationInstance.instance.RecordTimer.timeChanged
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."
280 newEntry = RecordTimerEntry(ServiceReference(serviceref), begin, end, name, description, eit)
281 func = NavigationInstance.instance.RecordTimer.record
283 # Mark this entry as AutoTimer (only AutoTimers will have this Attribute set)
284 newEntry.isAutoTimer = True
286 if not recorddict.has_key(serviceref):
287 recorddict[serviceref] = [newEntry]
289 recorddict[serviceref].append(newEntry)
292 if timer.hasAfterEvent():
293 afterEvent = timer.getAfterEventTimespan(localtime(end))
294 if afterEvent is None:
295 afterEvent = timer.getAfterEvent()
296 if afterEvent is not None:
297 newEntry.afterEvent = afterEvent
299 newEntry.dirname = timer.destination
300 newEntry.justplay = timer.justplay
301 newEntry.tags = timer.tags # This needs my enhanced tag support patch to work
303 # Do a sanity check, although it does not do much right now
304 timersanitycheck = TimerSanityCheck(NavigationInstance.instance.RecordTimer.timer_list, newEntry)
305 if not timersanitycheck.check():
306 print "[Autotimer] Sanity check failed"
308 print "[Autotimer] Sanity check passed"
310 # Either add to List or change time
313 return (total, new, modified, timers)