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