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