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