4.2.3r1
[enigma2.git] / usr / lib / enigma2 / python / Plugins / Extensions / HbbTV / HbbTV.py
1 from enigma import eHbbtv, eServiceReference, ePoint, eSize, eRect, getDesktop, eTimer, eDVBVolumecontrol
2 from Plugins.Plugin import PluginDescriptor
3 from Screens.Screen import Screen
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.MessageBox import MessageBox
6 from Screens.LocationBox import MovieLocationBox
7 from Components.config import config, ConfigSubsection, ConfigEnableDisable, ConfigSelection
8 from Components.PluginComponent import plugins
9 from Components.UsageConfig import preferredPath
10 from Components.VideoWindow import VideoWindow
11
12 from Plugins.Extensions.Browser.Browser import Browser
13 from Plugins.Extensions.Browser.Downloads import downloadManager, DownloadJob
14
15 config.plugins.hbbtv = ConfigSubsection()
16 config.plugins.hbbtv.enabled = ConfigEnableDisable(default=True)
17 config.plugins.hbbtv.testsuite = ConfigSelection([("mainmenu", _("Menu")), ("extensions", _("Extensions")), ("plugins", _("Plugin Browser")), ("disabled", _("Disabled"))], default="disabled")
18 config.plugins.hbbtv.text = ConfigEnableDisable(default=True)
19
20 from datetime import datetime
21 from urlparse import urlparse
22
23 class HbbTVVideoWindow(Screen):
24         skin = """
25                 <screen name="HbbTVVideoWindow" flags="wfNoBorder" zPosition="-1" position="0,0" size="1280,720" title="HbbTVVideoWindow" backgroundColor="transparent">
26                         <widget name="video" position="0,0" zPosition="0" size="0,0" backgroundColor="transparent"/>
27                 </screen>
28         """
29
30         def __init__(self, session, point=ePoint(0, 0), size=eSize(0, 0)):
31                 Screen.__init__(self, session)
32                 desktopSize = getDesktop(0).size()
33                 self["video"] = VideoWindow(decoder=0, fb_width=desktopSize.width(), fb_height=desktopSize.height())
34
35                 self.__point = point
36                 self.__size = size
37                 self.__retainedPoint = point
38                 self.__retainedSize = size
39
40                 self.__isFullscreen = False
41                 self.onLayoutFinish.append(self._onLayoutFinished)
42
43         def _onLayoutFinished(self):
44                 self.setRect(self.__point, self.__size, force=True)
45
46         def setRect(self, point, size, retain=True, force=False):
47                 if point.x() != self.__point.x() or point.y() != self.__point.y() or force:
48                         self.instance.move(point)
49                         self.__point = point
50                 if size.width() != self.__size.width() or size.height() != self.__size.height() or force:
51                         self.instance.resize(size)
52                         self.__size = size
53                         self["video"].instance.resize(size)
54
55                 if retain:
56                         self.__retainedPoint = point
57                         self.__retainedSize = size
58
59         def toggleFullscreen(self):
60                 if self.__isFullscreen:
61                         self.setRect(self.__retainedPoint, self.__retainedSize)
62                         self.__isFullscreen = False
63                 else:
64                         point = ePoint(0, 0)
65                         size = getDesktop(0).size()
66                         self.setRect(point, size, retain=False)
67                         self.__isFullscreen = True
68                 return self.__isFullscreen
69
70 class HbbTV(object):
71         instance = None
72         redButtonDescriptor = None
73         textDescriptor = None
74
75         def __init__(self, session):
76                 assert HbbTV.instance is None, "HbbTV is a singleton class and may only be initialized once!"
77                 HbbTV.instance = self
78
79                 self.session = session
80                 self._redButtonApp = None
81                 self._textApp = None
82                 self.eHbbtv = eHbbtv.getInstance()
83                 self.connectCallbacks()
84
85                 self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_STOPPED)
86
87                 from Screens.InfoBar import InfoBar
88                 InfoBar.instance.onServiceListRootChanged.append(self.setCurrentBouquet)
89                 InfoBar.instance.addExtension((self._getExtensionMenuText, self._showApplicationList, lambda: True), key="red")
90
91                 self.onClose = []
92
93                 self.__videoWindow = None
94                 self.__currentStreamRef = None
95                 self.__browser = None
96                 self.__lastService = None
97                 self.__restoreTimer = eTimer()
98                 self.__restoreTimer_conn = self.__restoreTimer.timeout.connect(self._restoreLastService)
99
100         def connectCallbacks(self):
101                 print "[HbbTV] connecting callbacks"
102                 self.conns = [ ]
103                 self.conns.append(self.eHbbtv.playServiceRequest.connect(self.zap))
104                 self.conns.append(self.eHbbtv.playStreamRequest.connect(self.playStream))
105                 self.conns.append(self.eHbbtv.pauseStreamRequest.connect(self.pauseStream))
106                 self.conns.append(self.eHbbtv.seekStreamRequest.connect(self.seekStream))
107                 self.conns.append(self.eHbbtv.stopStreamRequest.connect(self.stopStream))
108                 self.conns.append(self.eHbbtv.nextServiceRequest.connect(self.nextService))
109                 self.conns.append(self.eHbbtv.prevServiceRequest.connect(self.prevService))
110                 self.conns.append(self.eHbbtv.setVolumeRequest.connect(self.setVolume))
111                 self.conns.append(self.eHbbtv.setVideoWindowRequest.connect(self.setVideoWindow))
112                 #AIT
113                 self.eHbbtv.setAitSignalsEnabled(True);
114                 self.conns.append(self.eHbbtv.redButtonAppplicationReady.connect(self.redButtonAppplicationReady))
115                 self.conns.append(self.eHbbtv.textApplicationReady.connect(self.textApplicationReady))
116                 self.conns.append(self.eHbbtv.aitInvalidated.connect(self.aitInvalidated))
117                 self.conns.append(self.eHbbtv.createApplicationRequest.connect(self.startApplicationByUri))
118                 self.conns.append(self.eHbbtv.show.connect(self.showBrowser))
119                 self.conns.append(self.eHbbtv.hide.connect(self.hideBrowser))
120
121         def disconnectCallbacks(self):
122                 print "[HbbTV] disconnecting callbacks"
123                 self.conns = None
124                 for fnc in self.onClose:
125                         fnc()
126
127         def _showVideoIfAvail(self):
128                 if self.__videoWindow != None:
129                         self.__videoWindow.show()
130
131         def _hideVideoIfAvail(self):
132                 if self.__videoWindow != None:
133                         self.__videoWindow.hide()
134
135         def _adjustLimits(self, var, lower, upper):
136                 var = int(var)
137                 var = max(var, lower)
138                 var = min(var, upper)
139                 return var
140
141         def setVideoWindow(self, x, y, w, h):
142                 w = self._adjustLimits(w, 128, 1280)
143                 h = self._adjustLimits(h, 72, 720)
144                 x = self._adjustLimits(x, 0, 1280)
145                 y = self._adjustLimits(y, 0, 720)
146
147                 print "[Hbbtv].setVideoWindow x=%s, y=%s, w=%s, h=%s" % (x, y, w, h)
148                 if self.__browser:
149                         self.__browser.scaleRect(eRect(x, y, w, h), self._doSetVideoWindow)
150
151         def _doSetVideoWindow(self, rect):
152                 print "[Hbbtv]._doSetVideoWindow x=%s, y=%s, w=%s, h=%s" % (rect.x(), rect.y(), rect.width(), rect.height())
153                 if self.__videoWindow == None:
154                         self.__videoWindow = self.session.instantiateDialog(HbbTVVideoWindow, point=rect.topLeft(), size=rect.size())
155                 self.__videoWindow.setRect(rect.topLeft(), rect.size())
156                 self.__videoWindow.show()
157
158         def _unsetVideoWindow(self):
159                 if self.__videoWindow != None:
160                         self.session.deleteDialog(self.__videoWindow)
161                         self.__videoWindow = None
162
163         def _toggleVideoFullscreen(self):
164                 if self.__videoWindow:
165                         if self.__videoWindow.toggleFullscreen():
166                                 if self.__browser:
167                                         self.__browser.hide()
168                         else:
169                                 if self.__browser:
170                                         self.__browser.show()
171
172                         return True
173
174         def _saveStreamToDisk(self):
175                 if self.isStreaming():
176                         title = _("Please selection the location you want to download the current stream to.")
177                         self.session.openWithCallback(self._onSaveStreamToDisk, MovieLocationBox, title, preferredPath("<timer>"))
178                         return True
179                 return False
180
181         def _onSaveStreamToDisk(self, path):
182                 if path is not None:
183                         parsed = urlparse(self.__currentStreamRef.getPath())
184                         file = parsed.path.split("/")[-1].split(".")
185                         host = parsed.netloc.split(":")[0]
186                         datestring = datetime.now().strftime("%Y%m%d_%H%M")
187                         extension = "mp4"
188                         filename = "%s_%s_%s.%s" % (datestring, host, file[0], extension)
189                         path = "%s%s" % (path, filename)
190                         downloadManager.AddJob(DownloadJob(self.__currentStreamRef.getPath(), path, filename))
191                         self.session.open(MessageBox, _("Download started..."), type=MessageBox.TYPE_INFO, timeout=3)
192
193         def _onUrlChanged(self, url):
194                 self.stopStream()
195                 self._unsetVideoWindow()
196
197         def showBrowser(self):
198                 self._showVideoIfAvail()
199 #               if self.__browser:
200                         #self.__browser.show()
201
202         def hideBrowser(self):
203                 self._hideVideoIfAvail()
204 #               if self.__browser:
205                         #self.__browser.hide()
206
207         def _unsetBrowser(self):
208                 self._unsetVideoWindow()
209                 self.stopStream()
210                 self.__browser = None
211
212         def zap(self, sref):
213                 self.session.nav.playService(eServiceReference(sref))
214
215         def isStreaming(self):
216                 if self.__currentStreamRef:
217                         return True
218                 return False
219
220         def playStream(self, sref):
221                 self.__restoreTimer.stop()
222                 self.__currentStreamRef = eServiceReference(sref)
223                 currentService = self.session.nav.getCurrentlyPlayingServiceReference()
224                 if currentService and currentService.valid():
225                         if currentService.toCompareString() != self.__currentStreamRef.toCompareString() and currentService.type == eServiceReference.idDVB:
226                                 self.__lastService = currentService
227                                 self._playStream(sref)
228                         else:
229                                 self._unpauseStream()
230                 else:
231                         self._playStream(sref)
232
233                 self._showVideoIfAvail()
234
235         def _playStream(self, sref):
236                 config.mediaplayer.useAlternateUserAgent.value = False
237                 self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_CONNECTING)
238                 self.session.nav.stopService()
239                 self.session.nav.playService(eServiceReference(sref))
240
241         def actionPause(self):
242                 if self.__browser:
243                         self.__browser.actionPause()
244
245         def _unpauseStream(self):
246                 pausable = self.session.nav.getCurrentService().pause()
247                 pausable.unpause()
248                 self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_PLAYING)
249
250         def pauseStream(self):
251                 if self.isStreaming():
252                         pausable = self.session.nav.getCurrentService().pause()
253                         if pausable is None:
254                                 self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_PLAYING)
255                         else:
256                                 pausable.pause()
257                                 self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_PAUSED)
258
259         def seekStream(self, to):
260                 if not self.isStreaming():
261                         return
262
263                 s = self.session.nav.getCurrentService()
264                 if not s:
265                         return
266
267                 seekable = s.seek()
268                 if seekable is None or not seekable.isCurrentlySeekable():
269                         return
270                 seekable.seekTo(to)
271
272         def actionStop(self):
273                 if self.__browser:
274                         self.__browser.actionStop()
275
276         def stopStream(self):
277                 if self.isStreaming():
278                         self.session.nav.stopService()
279                         self.eHbbtv.setStreamState(eHbbtv.STREAM_STATE_STOPPED)
280                         self.__currentStreamRef = None
281                         self.__restoreTimer.startLongTimer(1)
282
283         def setVolume(self, volume):
284                 vol = eDVBVolumecontrol.getInstance()
285                 vol.setVolume(volume)
286
287         def _restoreLastService(self):
288                 if self.__lastService:
289                         self.session.nav.playService(self.__lastService)
290                         self.__lastService = None
291
292         def nextService(self):
293                 from Screens.InfoBar import InfoBar
294                 ib = InfoBar.instance
295                 ib.zapDown()
296
297         def prevService(self):
298                 from Screens.InfoBar import InfoBar
299                 ib = InfoBar.instance
300                 ib.zapUp()
301
302         def redButtonAppplicationReady(self, appid):
303                 print "[HbbTV].readButtonApplicationReady, appid=%s" % (appid)
304                 self._redButtonApp = appid
305                 app = self.eHbbtv.getApplication(self._redButtonApp)
306                 HbbTV.redButtonDescriptor.name = app.getName()
307                 plugins.addPlugin(HbbTV.redButtonDescriptor)
308
309         def textApplicationReady(self, appid):
310                 print "[HbbTV].textApplicationReady, appid=%s" % (appid)
311                 if config.plugins.hbbtv.text.value:
312                         self._textApp = appid
313                         app = self.eHbbtv.getApplication(self._textApp)
314                         HbbTV.textDescriptor.name = app.getName()
315                         plugins.addPlugin(HbbTV.textDescriptor)
316
317         def aitInvalidated(self):
318                 print "[HbbTV].aitInvalidated"
319                 self._redButtonApp = None
320                 self._textApp = None
321                 if plugins.getPlugins(PluginDescriptor.WHERE_HBBTV).count(HbbTV.redButtonDescriptor) > 0:
322                         plugins.removePlugin(HbbTV.redButtonDescriptor)
323                 if plugins.getPlugins(PluginDescriptor.WHERE_TELETEXT).count(HbbTV.textDescriptor) > 0:
324                         plugins.removePlugin(HbbTV.textDescriptor)
325
326         def isRedButtonAvailable(self):
327                 return self._redButtonApp != None
328
329         def isTextAvailable(self):
330                 return self._textApp != None
331
332         def showRedButtonApplication(self):
333                 print "[HbbTV].HbbTV.showRedButtonApplication"
334                 if self._redButtonApp is not None:
335                         self.startApplicationById(self._redButtonApp)
336
337         def showTextApplication(self):
338                 print "[HbbTV].HbbTV.showTextApplication"
339                 if self._textApp is not None:
340                         self.startApplicationById(self._textApp)
341
342         def startApplicationByUri(self, uri):
343                 if uri.startswith("dvb://"):
344                         uri = self.eHbbtv.resolveApplicationLocator(uri)
345                 if uri != "":
346                         if self.__browser is not None:
347                                 if self.__browser.execing:
348                                         self.__browser.setUrl(uri)
349                                         self.__browser.show()
350                                         return
351
352                         self.__browser = self.session.open(Browser, True, uri, True, hbbtvMenu=self._showApplicationList)
353                         self.__browser.onClose.append(self._unsetBrowser)
354                         self.__browser.onPageLoadFinished.append(self.eHbbtv.pageLoadFinished)
355                         self.__browser.onActionTv.append(self._toggleVideoFullscreen)
356                         self.__browser.onActionRecord.append(self._saveStreamToDisk)
357                         self.__browser.onUrlChanged.append(self._onUrlChanged)
358                         self.__browser.onExecBegin.append(self._showVideoIfAvail)
359                         self.__browser.onExecEnd.append(self._hideVideoIfAvail)
360
361         def startApplicationById(self, appid):
362                 uri = self.eHbbtv.resolveApplicationLocator("dvb://current.ait/%s" % appid)
363                 if uri != "":
364                         self.startApplicationByUri(uri)
365
366         def setCurrentBouquet(self, ref):
367                 self.eHbbtv.setServiceList(ref.toString())
368
369         def _getExtensionMenuText(self):
370                 return _("HbbTV Applications")
371
372         def _showApplicationList(self):
373                 apps = eHbbtv.getInstance().getApplicationIdsAndName()
374                 apps.append(("putpat.tv", "http://www.putpat.tv/device/phupaw9t"))
375                 if len(apps) == 0:
376                         apps.append((_("No HbbTV Application available"), None))
377                 self.session.openWithCallback(self._applicationSelected, ChoiceBox, title=_("Please select an HbbTV application"), list=apps)
378
379         def _applicationSelected(self, appid):
380                 appid = appid and appid[1]
381                 if appid is not None:
382                         if str(appid).startswith("http"):
383                                 self.startApplicationByUri(appid)
384                         else:
385                                 self.startApplicationById(appid)
386
387         @staticmethod
388         def redButton(**kwargs):
389                 hbbtv = HbbTV.instance
390                 if hbbtv is not None:
391                         if hbbtv.isRedButtonAvailable():
392                                 hbbtv.showRedButtonApplication()
393
394         @staticmethod
395         def textButton(**kwargs):
396                 hbbtv = HbbTV.instance
397                 if hbbtv is not None:
398                         if hbbtv.isTextAvailable():
399                                 hbbtv.showTextApplication()
400
401 HbbTV.redButtonDescriptor = PluginDescriptor(name="HbbTV", description=_("Show the current HbbTV Startapplication"), where=[PluginDescriptor.WHERE_HBBTV, ], fnc=HbbTV.redButton, needsRestart=False)
402 HbbTV.textDescriptor = PluginDescriptor(name="HbbTV", description=_("Show the current HbbTV Teletext Application"), where=[PluginDescriptor.WHERE_TELETEXT, ], fnc=HbbTV.textButton, needsRestart=False)
403
404 def start(session, **kwargs):
405         if HbbTV.instance is None:
406                 HbbTV(session)
407
408 def autostart(reason, **kwargs):
409         if reason == 1:
410                 if HbbTV.instance is not None:
411                         HbbTV.instance.disconnectCallbacks()