- new config file format (see sample xml, old configs are converted),
[enigma2-plugins.git] / epgrefresh / src / EPGRefresh.py
1 # To check if in Standby
2 import Screens.Standby
3
4 # eServiceReference
5 from enigma import eServiceReference, eServiceCenter
6                                                                                                                                                      
7 # Timer
8 from EPGRefreshTimer import epgrefreshtimer, EPGRefreshTimerEntry, checkTimespan
9
10 # To calculate next timer execution
11 from time import time
12
13 # Plugin Config
14 from xml.dom.minidom import parse as minidom_parse
15 from os import path as path
16
17 # We want a list of unique services
18 from sets import Set
19
20 # Configuration
21 from Components.config import config
22
23 # Path to configuration
24 CONFIG = "/etc/enigma2/epgrefresh.xml"
25
26 ####
27 # Support for old configuration
28 # to be removed :-)
29 ####
30 OLD_CONFIG = "/etc/enigma2/epgrefresh.conf"
31 def readOldConfig(myset):
32         # Open file
33         file = open(OLD_CONFIG, 'r')
34
35         # Add References
36         for line in file:
37                 line = line.strip()
38                 if line:
39                         myset.add(line)
40
41         # Close file
42         file.close()
43
44 def getValue(definition, default):
45         # Initialize Output
46         ret = ""
47
48         # Iterate through nodes of last one
49         for node in definition.childNodes:
50                 # Append text if we have a text node
51                 if node.nodeType == node.TEXT_NODE:
52                         ret = ret + node.data
53
54         # Return stripped output or (if empty) default
55         return ret.strip() or default
56
57 class EPGRefresh:
58         """Simple Class to refresh EPGData"""
59
60         def __init__(self):
61                 # Initialize 
62                 self.services = (Set(), Set())
63                 self.previousService = None
64                 self.forcedScan = False
65                 self.session = None
66                 self.beginOfTimespan = 0
67
68                 # Mtime of configuration files
69                 self.configMtime = -1
70
71                 # Read in Configuration
72                 self.readConfiguration()
73
74         def readConfiguration(self):
75                 ####
76                 # Support for old configuration
77                 # to be removed :-)
78                 ####
79                 if path.exists(OLD_CONFIG):
80                         self.services[0].clear()
81                         readOldConfig(self.services[0])
82
83                         # Save new config
84                         self.saveConfiguration()
85
86                         # Delete old config
87                         from os import unlink
88                         unlink(OLD_CONFIG)
89
90                 # Check if file exists
91                 if not path.exists(CONFIG):
92                         return
93
94                 # Check if file did not change
95                 mtime = path.getmtime(CONFIG)
96                 if mtime == self.configMtime:
97                         return
98
99                 # Keep mtime
100                 self.configMtime = mtime
101
102                 # Empty out list
103                 self.services[0].clear()
104                 self.services[1].clear()
105
106                 # Open file
107                 dom = minidom_parse(CONFIG)
108
109                 # Add References
110                 for configuration in dom.getElementsByTagName("epgrefresh"):
111                         for service in configuration.getElementsByTagName("service"):
112                                 value = getValue(service, None)
113                                 if value:
114                                         # strip all after last : (custom name)
115                                         pos = value.rfind(':')
116                                         if pos != -1:
117                                                 value = value[:pos+1]
118
119                                         self.services[0].add(value)
120                         for bouquet in configuration.getElementsByTagName("bouquet"):
121                                 value = getValue(bouquet, None)
122                                 if value:
123                                         self.services[1].add(value)
124
125         def saveConfiguration(self):
126                 # Generate List in RAM
127                 list = ['<?xml version="1.0" ?>\n<epgrefresh>\n\n']
128
129                 for service in self.services[0]:
130                         list.extend([' <service>', service, '</service>\n'])
131                 for bouquet in self.services[1]:
132                         list.extend([' <bouquet>', bouquet, '</bouquet>\n'])
133
134                 list.append('\n</epgrefresh>')
135
136                 # Try Saving to Flash
137                 file = None
138                 try:
139                         file = open(CONFIG, 'w')
140                         file.writelines(list)
141
142                         file.close()
143                 except Exception, e:
144                         print "[EPGRefresh] Error Saving Service List:", e
145
146         def forceRefresh(self, session = None):
147                 print "[EPGRefresh] Forcing start of EPGRefresh"
148                 if session is not None:
149                         self.session = session
150
151                 self.forcedScan = True
152                 self.prepareRefresh()
153
154         def start(self, session = None):
155                 if session is not None:
156                         self.session = session
157
158                 epgrefreshtimer.setRefreshTimer(self.createWaitTimer)
159
160         def stop(self):
161                 print "[EPGRefresh] Stopping Timer"
162                 epgrefreshtimer.clear()
163
164         def prepareRefresh(self):
165                 print "[EPGRefresh] About to start refreshing EPG"
166
167                 # Keep service
168                 self.previousService =  self.session.nav.getCurrentlyPlayingServiceReference()
169
170                 # Maybe read in configuration
171                 try:
172                         self.readConfiguration()
173                 except Exception, e:
174                         print "[EPGRefresh] Error occured while reading in configuration:", e
175
176                 # Save Services in a dict <transponder data> => serviceref
177                 self.scanServices = []
178                 channelIdList = []
179
180                 # This will hold services which are not explicitely in our servicelist
181                 additionalServices = []
182
183                 serviceHandler = eServiceCenter.getInstance()
184                 for bouquet in self.services[1]:
185                         myref = eServiceReference(str(bouquet))
186                         list = serviceHandler.list(myref)
187                         if list is not None:
188                                 while 1:
189                                         s = list.getNext()
190                                         # TODO: I wonder if its sane to assume we get services here (and not just new lists)
191                                         if s.valid():
192                                                 additionalServices.append(s.toString())
193                                         else:
194                                                 break
195
196                 # See if we are supposed to read in autotimer services
197                 if config.plugins.epgrefresh.inherit_autotimer.value:
198                         try:
199                                 # Import Instance
200                                 from Plugins.Extensions.AutoTimer.plugin import autotimer
201
202                                 # See if instance is empty
203                                 removeInstance = False
204                                 if autotimer is None:
205                                         removeInstance = True
206                                         # Create an instance
207                                         from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
208                                         autotimer = AutoTimer()
209
210                                 # Read in configuration
211                                 autotimer.readXml()
212
213                                 # Fetch services
214                                 for timer in autotimer.getEnabledTimerList():
215                                         additionalServices.extend(timer.getServices())
216
217                                 # Remove instance if there wasn't one before
218                                 # we might go into the exception before we reach this line, but we don't care then...
219                                 if removeInstance:
220                                         autotimer = None
221
222                         except Exception, e:
223                                 print "[EPGRefresh] Could not inherit AutoTimer Services:", e
224
225                 # TODO: does this really work?
226                 for serviceref in self.services[0].union(additionalServices):
227                         service = eServiceReference(str(serviceref))
228                         if not service.valid() \
229                                 or (service.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)):
230                                 
231                                 continue
232
233                         channelID = '%08x%04x%04x' % (
234                                 service.getUnsignedData(4), # NAMESPACE
235                                 service.getUnsignedData(2), # TSID
236                                 service.getUnsignedData(3), # ONID
237                         )
238
239                         if channelID not in channelIdList:
240                                 self.scanServices.append(service)
241                                 channelIdList.append(channelID)
242
243                 # Debug
244                 from ServiceReference import ServiceReference
245                 print "[EPGRefresh] Services we're going to scan:", ', '.join([ServiceReference(x).getServiceName().replace('\xc2\x86', '').replace('\xc2\x87', '') for x in self.scanServices])
246
247                 self.refresh()
248
249         def cleanUp(self):
250                 config.plugins.epgrefresh.lastscan.value = int(time())
251                 config.plugins.epgrefresh.lastscan.save()
252
253                 # shutdown if we're supposed to go to deepstandby and not recording
254                 if not self.forcedScan and config.plugins.epgrefresh.afterevent.value \
255                         and not Screens.Standby.inTryQuitMainloop:
256
257                         self.session.open(
258                                 Screens.Standby.TryQuitMainloop,
259                                 1
260                         )
261
262                 self.forcedScan = False
263                 epgrefreshtimer.cleanup()
264
265                 # Zap back
266                 if self.previousService is not None or Screens.Standby.inStandby:
267                         self.session.nav.playService(self.previousService)
268
269         def refresh(self):
270                 if self.forcedScan:
271                         self.nextService()
272                 else:
273                         # Abort if a scan finished later than our begin of timespan
274                         if self.beginOfTimespan < config.plugins.epgrefresh.lastscan.value:
275                                 return
276                         if config.plugins.epgrefresh.force.value \
277                                 or (Screens.Standby.inStandby and \
278                                         not self.session.nav.RecordTimer.isRecording()):
279
280                                 self.nextService()
281                         # We don't follow our rules here - If the Box is still in Standby and not recording we won't reach this line 
282                         else:
283                                 if not checkTimespan(
284                                         config.plugins.epgrefresh.begin.value,
285                                         config.plugins.epgrefresh.end.value):
286
287                                         print "[EPGRefresh] Gone out of timespan while refreshing, sorry!"
288                                         self.cleanUp()
289                                 else:
290                                         print "[EPGRefresh] Box no longer in Standby or Recording started, rescheduling"
291
292                                         # Recheck later
293                                         epgrefreshtimer.add(EPGRefreshTimerEntry(
294                                                         time() + config.plugins.epgrefresh.delay_standby.value*60,
295                                                         self.refresh,
296                                                         nocheck = True)
297                                         )
298
299         def createWaitTimer(self):
300                 self.beginOfTimespan = time()
301
302                 # Add wait timer to epgrefreshtimer
303                 epgrefreshtimer.add(EPGRefreshTimerEntry(time() + 30, self.prepareRefresh))
304
305         def nextService(self):
306                 # DEBUG
307                 print "[EPGRefresh] Maybe zap to next service"
308
309                 try:
310                         # Get next reference
311                         service = self.scanServices.pop(0)
312
313                         # Play next service
314                         self.session.nav.playService(service)
315
316                         # Start Timer
317                         epgrefreshtimer.add(EPGRefreshTimerEntry(
318                                 time() + config.plugins.epgrefresh.interval.value*60,
319                                 self.refresh,
320                                 nocheck = True)
321                         )
322                 except IndexError:
323                         # Debug
324                         print "[EPGRefresh] Done refreshing EPG"
325
326                         # Clean up
327                         self.cleanUp()
328
329 epgrefresh = EPGRefresh()