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