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.
231 for rtimer in recorddict.get(serviceref, []):
232 if rtimer.eit == eit or config.plugins.autotimer.try_guessing.value and getTimeDiff(rtimer, begin, end) > ((duration/10)*8):
235 # Abort if we don't want to modify timers or timer is repeated
236 if config.plugins.autotimer.refresh.value == "none" or newEntry.repeated:
237 raise AutoTimerIgnoreTimerException("Won't modify existing timer because either no modification allowed or repeated timer")
239 if hasattr(newEntry, "isAutoTimer"):
240 print "[AutoTimer] Modifying existing AutoTimer!"
242 if config.plugins.autotimer.refresh.value != "all":
243 raise AutoTimerIgnoreTimerException("Won't modify existing timer because it's no timer set by us")
244 print "[AutoTimer] Warning, we're messing with a timer which might not have been set by us"
248 # Modify values saved in timer
250 newEntry.description = description
251 newEntry.begin = int(begin)
252 newEntry.end = int(end)
253 newEntry.service_ref = ServiceReference(serviceref)
256 elif timer.getAvoidDuplicateDescription() == 1 and rtimer.description == description:
257 raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
258 if newEntry is None and timer.getAvoidDuplicateDescription() == 2:
259 for list in recorddict.values():
261 if rtimer.description == description:
262 raise AutoTimerIgnoreTimerException("We found a timer with same description, skipping event")
264 except AutoTimerIgnoreTimerException, etite:
268 # Event not yet in Timers
270 if timer.checkCounter(timestamp):
275 print "[AutoTimer] Adding an event."
276 newEntry = RecordTimerEntry(ServiceReference(serviceref), begin, end, name, description, eit)
278 # Mark this entry as AutoTimer (only AutoTimers will have this Attribute set)
279 newEntry.isAutoTimer = True
282 if timer.hasAfterEvent():
283 afterEvent = timer.getAfterEventTimespan(localtime(end))
284 if afterEvent is None:
285 afterEvent = timer.getAfterEvent()
286 if afterEvent is not None:
287 newEntry.afterEvent = afterEvent
289 newEntry.dirname = timer.destination
290 newEntry.justplay = timer.justplay
291 newEntry.tags = timer.tags # This needs my enhanced tag support patch to work
294 if NavigationInstance.instance.RecordTimer.record(newEntry) is None:
296 if recorddict.has_key(serviceref):
297 recorddict[serviceref].append(newEntry)
299 recorddict[serviceref] = [newEntry]
301 # XXX: this won't perform a sanity check, but do we actually want to do so?
302 NavigationInstance.instance.RecordTimer.timeChanged(newEntry)
304 return (total, new, modified, timers)