2 from xml.etree.cElementTree import parse as cet_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 configuration = cet_parse(XML_CONFIG).getroot()
83 # Empty out timers and reset Ids
85 self.defaultTimer.clear(-1, True)
90 configuration.get("version"),
94 self.uniqueTimerId = len(self.timers)
97 writeConfig(XML_CONFIG, self.defaultTimer, self.timers)
101 def add(self, timer):
102 self.timers.append(timer)
104 def getEnabledTimerList(self):
105 return [x for x in self.timers if x.enabled]
107 def getTimerList(self):
110 def getTupleTimerList(self):
112 return [(x,) for x in list]
114 def getSortedTupleTimerList(self):
115 list = self.timers[:]
117 return [(x,) for x in list]
119 def getUniqueId(self):
120 self.uniqueTimerId += 1
121 return self.uniqueTimerId
123 def remove(self, uniqueId):
125 for timer in self.timers:
126 if timer.id == uniqueId:
131 def set(self, timer):
133 for stimer in self.timers:
135 self.timers[idx] = timer
138 self.timers.append(timer)
142 def parseEPG(self, simulateOnly = False):
143 if NavigationInstance.instance is None:
144 print "[AutoTimer] Navigation is not available, can't parse EPG"
154 # Save Recordings in a dict to speed things up a little
155 # We include processed timers as we might search for duplicate descriptions
157 for timer in NavigationInstance.instance.RecordTimer.timer_list + NavigationInstance.instance.RecordTimer.processed_timers:
158 if not recorddict.has_key(str(timer.service_ref)):
159 recorddict[str(timer.service_ref)] = [timer]
161 recorddict[str(timer.service_ref)].append(timer)
164 for timer in self.getEnabledTimerList():
165 # Search EPG, default to empty list
166 ret = self.epgcache.search(('RI', 100, eEPGCache.PARTIAL_TITLE_SEARCH, timer.match, eEPGCache.NO_CASE_CHECK)) or []
168 for serviceref, eit in ret:
169 eserviceref = eServiceReference(serviceref)
171 evt = self.epgcache.lookupEventId(eserviceref, eit)
173 print "[AutoTimer] Could not create Event!"
176 # Try to determine real service (we always choose the last one)
177 n = evt.getNumOfLinkageServices()
179 i = evt.getLinkageService(eserviceref, n-1)
180 serviceref = i.toString()
183 name = evt.getEventName()
184 description = evt.getShortDescription()
185 begin = evt.getBeginTime()
186 duration = evt.getDuration()
187 end = begin + duration
189 # If event starts in less than 60 seconds skip it
190 if begin < time() + 60:
194 timestamp = localtime(begin)
197 timer.update(begin, timestamp)
199 # Check Duration, Timespan and Excludes
200 if timer.checkServices(serviceref) \
201 or timer.checkDuration(duration) \
202 or timer.checkTimespan(timestamp) \
203 or timer.checkFilter(name, description,
204 evt.getExtendedDescription(), str(timestamp.tm_wday)):
207 if timer.hasOffset():
208 # Apply custom Offset
209 begin, end = timer.applyOffset(begin, end)
212 begin -= config.recording.margin_before.value * 60
213 end += config.recording.margin_after.value * 60
218 # Append to timerlist and abort if simulating
219 timers.append((name, begin, end, serviceref, timer.name))
227 # Check for double Timers
228 # We first check eit and if user wants us to guess event based on time
229 # we try this as backup. The allowed diff should be configurable though.
230 for rtimer in recorddict.get(serviceref, []):
231 if rtimer.eit == eit or config.plugins.autotimer.try_guessing.value and getTimeDiff(rtimer, begin, end) > ((duration/10)*8):
234 # Abort if we don't want to modify timers or timer is repeated
235 if config.plugins.autotimer.refresh.value == "none" or rtimer.repeated:
236 print "[AutoTimer] Won't modify existing timer because either no modification allowed or repeated timer"
239 if hasattr(rtimer, "isAutoTimer"):
240 print "[AutoTimer] Modifying existing AutoTimer!"
242 if config.plugins.autotimer.refresh.value != "all":
243 print "[AutoTimer] 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"
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:
261 print "[AutoTimer] We found a timer with same description, skipping event"
266 # Which we don't want to edit
269 # No Timer found yet and we want to search for possible doubles
270 elif newEntry is None and timer.getAvoidDuplicateDescription() == 2:
271 # I thinks thats the fastest way to do this, though it's a little ugly
273 for list in recorddict.values():
275 if rtimer.description == description:
276 raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
277 except AutoTimerIgnoreTimerException, etite:
280 # Event not yet in Timers
282 if timer.checkCounter(timestamp):
285 print "[AutoTimer] Adding an event."
286 newEntry = RecordTimerEntry(ServiceReference(serviceref), begin, end, name, description, eit)
288 # Mark this entry as AutoTimer (only AutoTimers will have this Attribute set)
289 newEntry.isAutoTimer = True
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
304 # XXX: this won't perform a sanity check, but do we actually want to do so?
305 NavigationInstance.instance.RecordTimer.timeChanged(newEntry)
307 conflicts = NavigationInstance.instance.RecordTimer.record(newEntry)
308 if conflicts and config.plugins.autotimer.disabled_on_conflict.value:
309 newEntry.disabled = True
310 # We might want to do the sanity check locally so we don't run it twice - but I consider this workaround a hack anyway
311 conflicts = NavigationInstance.instance.RecordTimer.record(newEntry)
312 if conflicts is None:
313 timer.decrementCounter()
315 if recorddict.has_key(serviceref):
316 recorddict[serviceref].append(newEntry)
318 recorddict[serviceref] = [newEntry]
320 return (total, new, modified, timers)