- save service names in xml,
[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                 try:
73                         self.readConfiguration()
74                 except Exception, e:
75                         print "[EPGRefresh] Error occured while reading in configuration:", e
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(serviceref))
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(serviceref))
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                 # Try Saving to Flash
144                 file = None
145                 try:
146                         file = open(CONFIG, 'w')
147                         file.writelines(list)
148
149                         file.close()
150                 except Exception, e:
151                         print "[EPGRefresh] Error Saving Service List:", e
152
153         def forceRefresh(self, session = None):
154                 print "[EPGRefresh] Forcing start of EPGRefresh"
155                 if session is not None:
156                         self.session = session
157
158                 self.forcedScan = True
159                 self.prepareRefresh()
160
161         def start(self, session = None):
162                 if session is not None:
163                         self.session = session
164
165                 epgrefreshtimer.setRefreshTimer(self.createWaitTimer)
166
167         def stop(self):
168                 print "[EPGRefresh] Stopping Timer"
169                 epgrefreshtimer.clear()
170
171         def prepareRefresh(self):
172                 print "[EPGRefresh] About to start refreshing EPG"
173
174                 # Keep service
175                 self.previousService =  self.session.nav.getCurrentlyPlayingServiceReference()
176
177                 # Maybe read in configuration
178                 try:
179                         self.readConfiguration()
180                 except Exception, e:
181                         print "[EPGRefresh] Error occured while reading in configuration:", e
182
183                 # Save Services in a dict <transponder data> => serviceref
184                 self.scanServices = []
185                 channelIdList = []
186
187                 # This will hold services which are not explicitely in our servicelist
188                 additionalServices = []
189
190                 serviceHandler = eServiceCenter.getInstance()
191                 for bouquet in self.services[1]:
192                         myref = eServiceReference(str(bouquet))
193                         list = serviceHandler.list(myref)
194                         if list is not None:
195                                 while 1:
196                                         s = list.getNext()
197                                         # TODO: I wonder if its sane to assume we get services here (and not just new lists)
198                                         if s.valid():
199                                                 additionalServices.append(s.toString())
200                                         else:
201                                                 break
202
203                 # See if we are supposed to read in autotimer services
204                 if config.plugins.epgrefresh.inherit_autotimer.value:
205                         try:
206                                 # Import Instance
207                                 from Plugins.Extensions.AutoTimer.plugin import autotimer
208
209                                 # See if instance is empty
210                                 removeInstance = False
211                                 if autotimer is None:
212                                         removeInstance = True
213                                         # Create an instance
214                                         from Plugins.Extensions.AutoTimer.AutoTimer import AutoTimer
215                                         autotimer = AutoTimer()
216
217                                 # Read in configuration
218                                 autotimer.readXml()
219
220                                 # Fetch services
221                                 for timer in autotimer.getEnabledTimerList():
222                                         additionalServices.extend(timer.getServices())
223
224                                 # Remove instance if there wasn't one before
225                                 # we might go into the exception before we reach this line, but we don't care then...
226                                 if removeInstance:
227                                         autotimer = None
228
229                         except Exception, e:
230                                 print "[EPGRefresh] Could not inherit AutoTimer Services:", e
231
232                 # TODO: does this really work?
233                 for serviceref in self.services[0].union(additionalServices):
234                         service = eServiceReference(str(serviceref))
235                         if not service.valid() \
236                                 or (service.flags & (eServiceReference.isMarker|eServiceReference.isDirectory)):
237                                 
238                                 continue
239
240                         channelID = '%08x%04x%04x' % (
241                                 service.getUnsignedData(4), # NAMESPACE
242                                 service.getUnsignedData(2), # TSID
243                                 service.getUnsignedData(3), # ONID
244                         )
245
246                         if channelID not in channelIdList:
247                                 self.scanServices.append(service)
248                                 channelIdList.append(channelID)
249
250                 # Debug
251                 from ServiceReference import ServiceReference
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()