[hbbtv] fix crash parsing xml.
[vuplus_dvbapp] / lib / python / Plugins / Extensions / HbbTV / plugin.py
1 from Plugins.Plugin import PluginDescriptor
2 from Screens.Screen import Screen
3 from Screens.InfoBar import InfoBar
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.HelpMenu import HelpableScreen
6 from Screens.MessageBox import MessageBox
7 from Screens.VirtualKeyBoard import VirtualKeyBoard
8 from Components.config import config
9 from Components.ActionMap import ActionMap
10 from Components.Language import language
11 from Components.ServiceEventTracker import ServiceEventTracker
12 from Components.VolumeControl import VolumeControl
13
14 from enigma import eTimer, fbClass, eRCInput, iServiceInformation, iPlayableService
15
16 import os, struct, vbcfg
17
18 from __init__ import _
19 from hbbtv import HbbTVWindow
20 from browser import Browser
21 from youtube import YoutubeTVWindow, YoutubeTVSettings
22 from vbipc import VBController, VBServerThread, VBHandlers
23
24 strIsEmpty = lambda x: x is None or len(x) == 0
25
26 vbcfg.SOCKETFILE = '/tmp/.browser.support'
27 vbcfg.CONTROLFILE = '/tmp/.browser.controller'
28 _OPCODE_LIST = [
29                 'CONTROL_BACK',
30                 'CONTROL_FORWARD',
31                 'CONTROL_STOP',
32                 'CONTROL_RELOAD',
33                 'CONTROL_OPENURL',
34                 'CONTROL_EXIT',
35                 'CONTROL_TITLE',
36                 'CONTROL_OK',
37                 'CONTROL_OUT_OF_MEMORY',
38                 'CONTROL_INVALIDATE',
39                 'CONTROL_GET_FBSIZE',
40                 'CONTROL_GET_VOLUME',
41                 'CONTROL_SET_VOLUME',
42                 'CONTROL_VOLUME_UP',
43                 'CONTROL_VOLUME_DOWN',
44                 'HBBTV_LOADAIT',
45                 'HBBTV_OPENURL',
46                 'YOUTUBETV_OPENURL',
47                 'BROWSER_OPENURL',
48                 'BROWSER_MENU_OPEN',
49                 'BROWSER_MENU_CLOSE',
50                 'BROWSER_VKB_OPEN',
51                 'BROWSER_VKB_CLOSE',
52                 'OOIF_GET_CURRENT_CHANNEL',
53                 'OOIF_BROADCAST_PLAY',
54                 'OOIF_BROADCAST_STOP',
55                 'OOIF_BROADCAST_CHECK',
56                 'CONTROL_RELOAD_KEYMAP',
57                 'OPCODE_END'
58                 ]
59
60 class VBHandler(VBHandlers):
61         def __init__(self, session):
62                 self._session = session
63                 self.current_title = None
64                 self.max_volume = -1
65                 self.soft_volume = -1
66                 self.videobackend_activate = False
67                 self.onSetTitleCB = []
68                 self.onCloseCB = []
69                 VBHandlers.__init__(self, _OPCODE_LIST, '_CB_')
70
71         def set_volume(self, volume):
72                 if self.max_volume < 0:
73                         self.max_volume = VolumeControl.instance.volctrl.getVolume()
74
75                 self.max_volume += volume
76                 if self.max_volume > 100:
77                         self.max_volume = 100
78                 elif self.max_volume < 0:
79                         self.max_volume = 0
80
81                 if self.soft_volume > 0:
82                         v = int((self.max_volume * self.soft_volume) / 100)
83                         VolumeControl.instance.volctrl.setVolume(v, v)
84                 else:
85                         VolumeControl.instance.volctrl.setVolume(self.max_volume, self.max_volume)
86
87         def close_vkb(self, data=""):
88                 fbClass.getInstance().lock()
89                 eRCInput.getInstance().lock()
90
91                 if strIsEmpty(data):
92                         data = ""
93                 VBController.command("BROWSER_VKB_CLOSE", data)
94
95         def _CB_CONTROL_EXIT(self, result, packet):
96                 if self.onCloseCB:
97                         for x in self.onCloseCB:
98                                 try:
99                                         x()
100                                 except Exception:
101                                         if x in self.onCloseCB:
102                                                 self.onCloseCB.remove(x)
103                 if self.videobackend_activate is False:
104                         if vbcfg.g_service is not None:
105                                 self._session.nav.playService(vbcfg.g_service)
106                 return (True, None)
107
108         def _CB_CONTROL_TITLE(self, result, packet):
109                 if packet.startswith('file://') or packet.startswith('http://'):
110                         return (True, None)
111                 for x in self.onSetTitleCB:
112                         try:
113                                 x(packet)
114                                 self.current_title = packet
115                         except Exception:
116                                 if x in self.onSetTitleCB:
117                                         self.onSetTitleCB.remove(x)
118                 return (True, None)
119
120         def _CB_CONTROL_OK(self, result, packet):
121                 if vbcfg.g_browser and packet.startswith('stop'):
122                         vbcfg.g_browser.keyOK()
123                 return (True, None)
124
125         def _CB_CONTROL_OUT_OF_MEMORY(self, result, packet):
126                 vbcfg.need_restart = True;
127                 return (True, None)
128
129         def _CB_CONTROL_INVALIDATE(self, result, packet):
130                 # redraw enigma
131                 from enigma import getDesktop
132                 getDesktop(0).paint()
133                 return (True, None)
134
135         def _CB_CONTROL_GET_FBSIZE(self, result, packet):
136                 from enigma import getDesktop
137                 desktop_size = getDesktop(0).size()
138                 data = "%dx%d" % (desktop_size.width(), desktop_size.height())
139                 return (True, data)
140
141         def _CB_CONTROL_SET_VOLUME(self, result, packet):
142                 if self.max_volume < 0:
143                         self.max_volume = VolumeControl.instance.volctrl.getVolume()
144                 self.soft_volume = int(packet)
145
146                 v = 0
147                 if self.soft_volume > 0 and self.max_volume > 0:
148                         v = int((self.max_volume * self.soft_volume) / 100)
149                 VolumeControl.instance.volctrl.setVolume(v, v)
150                 return (True, None)
151
152         def _CB_CONTROL_VOLUME_UP(self, result, packet):
153                 self.set_volume(5)
154                 return (True, None)
155
156         def _CB_CONTROL_VOLUME_DOWN(self, result, packet):
157                 self.set_volume(-5)
158                 return (True, None)
159
160         def _CB_BROWSER_MENU_OPEN(self, result, packet):
161                 if vbcfg.g_browser and vbcfg.g_browser.is_browser_opened:
162                         vbcfg.setPosition(vbcfg.g_position)
163                         fbClass.getInstance().unlock()
164                         eRCInput.getInstance().unlock()
165
166                         vbcfg.g_browser.toggle_browser(packet, self.current_title)
167                 return (True, None)
168
169         def _CB_BROWSER_VKB_OPEN(self, result, packet):
170                 if vbcfg.g_browser and vbcfg.g_browser.is_browser_opened:
171                         vbcfg.setPosition(vbcfg.g_position)
172                         fbClass.getInstance().unlock()
173                         eRCInput.getInstance().unlock()
174
175                         if strIsEmpty(packet):
176                                 packet = ""
177                         self._session.openWithCallback(self.close_vkb, VirtualKeyBoard, title=("Please enter URL here"), text=str(packet))
178                 return (True, None)
179
180         def _CB_OOIF_GET_CURRENT_CHANNEL(self, result, packet):
181                 if (vbcfg.g_channel_info):
182                         try:
183                                 data = struct.pack('iiii', vbcfg.g_channel_info[0], vbcfg.g_channel_info[1], vbcfg.g_channel_info[2], len(vbcfg.g_channel_info[3])) + vbcfg.g_channel_info[3]
184                         except Exception, err:
185                                 vbcfg.ERR(err)
186                                 return (False, None)
187                 else:
188                         return (False, None)
189                 return (True, data)
190
191         def _CB_OOIF_BROADCAST_PLAY(self, result, packet):
192                 if vbcfg.g_service is not None:
193                         self._session.nav.playService(vbcfg.g_service)
194                 self.videobackend_activate = False
195                 return (True, None)
196
197         def _CB_OOIF_BROADCAST_STOP(self, result, packet):
198                 vbcfg.g_service = self._session.nav.getCurrentlyPlayingServiceReference()
199                 self._session.nav.stopService()
200                 self.videobackend_activate = True
201                 return (True, None)
202
203         def _CB_OOIF_BROADCAST_CHECK(self, result, packet):
204                 if self._session.nav.getCurrentService() is None:
205                         return (False, None)
206                 return (True, None)
207
208 class VBMain(Screen):
209         skin = """<screen name="VBMAIN" position="0,0" size="0,0" backgroundColor="transparent" flags="wfNoBorder" title=" "></screen>"""
210         def __init__(self, session):
211                 Screen.__init__(self, session)
212
213                 self.vbcallback = None
214                 self.vbhandler = VBHandler(session)
215                 self.vbserver = VBServerThread()
216                 self.vbserver.open(1)
217                 self.vbserver.start()
218
219                 # comment for dev
220                 self.restart_browser()
221                 vbcfg.LOG("browser start")
222
223                 self._timer_infobar = eTimer()
224                 self._timer_infobar.callback.append(self._cb_register_infobar)
225                 self._timer_infobar.start(1000)
226
227                 self._event = ServiceEventTracker(screen=self, eventmap={
228                                 iPlayableService.evHBBTVInfo: self._cb_ait_detected,
229                                 iPlayableService.evUpdatedInfo: self._cb_info_updated
230                         })
231                 self._applicationList = None
232                 self._app_info = None
233
234                 try:
235                         from Screens.InfoBarGenerics import gHbbtvApplication
236                         self.m_vuplus = gHbbtvApplication.getUseAit()
237                 except:
238                         self.m_vuplus = False
239
240         def _cb_register_infobar(self):
241                 if InfoBar.instance:
242                         self._timer_infobar.stop()
243                         if self._cb_hbbtv_activated not in InfoBar.instance.onHBBTVActivation:
244                                 InfoBar.instance.onHBBTVActivation.append(self._cb_hbbtv_activated)
245                 vbcfg.DEBUG("registred HbbTV in InfoBar")
246
247         def _cb_hbbtv_activated(self, url=None, app_info=None):
248                 if not self.check_browser():
249                         message = _("HbbTV Browser was not running.\nPlease running browser before start HbbTV Application.")
250                         self.session.open(MessageBox, message, MessageBox.TYPE_INFO)
251                         return
252                 self.start_hbbtv_application(url, app_info)
253
254         def _cb_ait_detected(self):
255                 vbcfg.g_channel_info = None
256                 self._applicationList = None
257                 self._app_info = self.get_autostart_application()
258                 vbcfg.DEBUG("detected AIT")
259
260         def _cb_info_updated(self):
261                 vbcfg.g_service = self.session.nav.getCurrentlyPlayingServiceReference()
262                 vbcfg.DEBUG("updated channel info")
263
264         def start_hbbtv_application(self, url, app_info):
265                 if vbcfg.need_restart:
266                         self.restart_browser()
267                         os.time.sleep(2)
268                         vbcfg.need_restart = False
269
270                 if not app_info:
271                         app_info = self._app_info
272                 self.session.open(HbbTVWindow, url, app_info)
273
274         def menu_toggle_browser(self, callback=None):
275                 mode = []
276                 self.vbcallback = callback
277                 if self.check_browser():
278                         mode.append((_('Stop'), 'Stop'))
279                 else:
280                         mode.append((_('Start'), 'Start'))
281                 self.session.openWithCallback(self.toggle_browser, ChoiceBox, title=_("Please choose one."), list=mode)
282
283         def toggle_browser(self, selected):
284                 if selected is not None:
285                         if self.vbcallback:
286                                 self.vbcallback()
287                         try:
288                                 mode = selected[1]
289                                 if mode == 'Start':
290                                         if not self.check_browser():
291                                                 self.start_browser()
292                                 elif mode == 'Stop':
293                                         self.stop_browser()
294
295                         except Exception, ErrMsg:
296                                 vbcfg.ERR("toggle browser: %s" % ErrMsg)
297
298         def menu_hbbtv_applications(self):
299                 applications = []
300                 if self._applicationList is not None:
301                         for x in self._applicationList:
302                                 applications.append((x["name"], x))
303                 else:
304                         applications.append((_("No detected HbbTV applications."), None))
305                 self.session.openWithCallback(self.start_application_selected, ChoiceBox, title=_("Please choose an HbbTV application."), list=applications)
306
307         def start_application_selected(self, selected):
308                 vbcfg.DEBUG(selected)
309                 try:
310                         if selected[1] is not None:
311                                 self._cb_hbbtv_activated(selected[1]["url"], selected[1])
312                 except Exception, ErrMsg:
313                         vbcfg.ERR(ErrMsg)
314
315         def get_autostart_application(self):
316                 if self._applicationList is None:
317                         service = self.session.nav.getCurrentService()
318                         info = service and service.info()
319                         if info is not None:
320                                 sid = info.getInfo(iServiceInformation.sSID)
321                                 onid = info.getInfo(iServiceInformation.sONID)
322                                 tsid = info.getInfo(iServiceInformation.sTSID)
323                                 name = info.getName()
324                                 vbcfg.g_channel_info = (sid, onid, tsid, name)
325
326                                 pmtid = info.getInfo(iServiceInformation.sPMTPID)
327                                 demux = info.getInfoString(iServiceInformation.sLiveStreamDemuxId)
328                                 vbcfg.DEBUG("demux = %s, pmtid = 0x%x, sid = 0x%x" % (demux, pmtid, sid))
329
330                                 from aitreader import eAITSectionReader
331                                 reader = eAITSectionReader(demux, pmtid, sid)
332                                 if reader.doOpen(info, self.m_vuplus):
333                                         reader.doParseApplications()
334                                         reader.doDump()
335                                 else:
336                                         vbcfg.ERR("no AIT")
337
338                                 try:
339                                         self._applicationList = reader.getApplicationList()
340                                 except:
341                                         pass
342
343                 if self._applicationList is not None:
344                         for app in self._applicationList:
345                                 if app["control"] in (1, -1):
346                                         return app
347                 return None
348
349         def start_browser(self):
350                 if not self.check_browser():
351                         os.system("%s/%s start"%(vbcfg.APPROOT, vbcfg.APP_RUN))
352                 return True
353
354         def stop_browser(self):
355                 VBController.command('CONTROL_EXIT')
356                 return True
357                 try:
358                         os.system("%s/%s stop"%(vbcfg.APPROOT, vbcfg.APP_RUN))
359                 except:
360                         pass
361                 return True
362
363         def check_browser(self):
364                 try:
365                         ret = os.popen('%s/%s check'%(vbcfg.APPROOT, vbcfg.APP_RUN)).read()
366                         return ret.strip() != "0"
367                 except Exception, ErrMsg:
368                         vbcfg.ERR("check browser running: %s" % ErrMsg)
369                 return False
370
371         def restart_browser(self):
372                 try:
373                         os.system("%s/%s restart"%(vbcfg.APPROOT, vbcfg.APP_RUN))
374                 except:
375                         pass
376                 return True
377
378 def HelpableScreen__init__(self):
379         if isinstance(self, HelpableScreen):
380                 HelpableScreen.showManual = showManual
381
382                 self["helpActions"] = ActionMap(["HelpbuttonActions"], {
383                         "help_b" : self.showHelp,
384                         "help_l" : self.showManual,
385                 }, -2)
386
387 def showManual(self):
388         if not os.path.exists(vbcfg.MANUALROOT):
389                 return
390
391         url = 'file://' + vbcfg.MANUALROOT + '/main.html'
392         lang = language.getLanguage()
393         if os.path.exists(vbcfg.MANUALROOT + '/' + lang):
394                 url = 'file://' + vbcfg.MANUALROOT + '/' + lang + '/main.html'
395
396         vbcfg.g_browser = self.session.open(Browser, url)
397
398 def auto_start_main(reason, **kwargs):
399         if reason:
400                 try:
401                         if vbcfg.g_main.vbserver is not None:
402                                 vbcfg.g_main.vbserver.kill()
403                 except: pass
404
405 def session_start_main(session, reason, **kwargs):
406         vbcfg.g_main = session.open(VBMain)
407         HelpableScreen.__init__ = HelpableScreen__init__
408         HelpableScreen.session = session
409
410 def start_youtubetv_main(session, **kwargs):
411         def _cb_youtubetv_close(ret):
412                 if ret:
413                         vbcfg.g_service = session.nav.getCurrentlyPlayingServiceReference()
414                         if vbcfg.g_service is not None:
415                                 session.nav.stopService()
416                         vbcfg.g_browser = session.open(Browser, vbcfg.g_youtubetv_cfg.uri.value, True)
417
418         if config.plugins.youtubetv.showhelp.value == True:
419                 _cb_youtubetv_close(True)
420         else:
421                 session.openWithCallback(_cb_youtubetv_close, YoutubeTVWindow)
422
423
424 def menu_start_youtube(menuid, **kwargs):
425         if menuid == "mainmenu":
426                 return [(_("YouTube TV"), start_youtubetv_main, "youtube_tv", 46)]
427         return []
428
429 def plugin_setting_youtube(session, **kwargs):
430         session.open(YoutubeTVSettings)
431
432 def plugin_start_browser(session, **kwargs):
433         vbcfg.g_browser = session.open(Browser)
434
435 def extension_toggle_browser(session, **kwargs):
436         if vbcfg.g_main is not None:
437                 vbcfg.g_main.menu_toggle_browser()
438
439 def extension_start_application(session, **kwargs):
440         if vbcfg.g_main is not None:
441                 vbcfg.g_main.menu_hbbtv_applications()
442
443 def Plugins(**kwargs):
444         l = []
445         l.append(PluginDescriptor(where=PluginDescriptor.WHERE_AUTOSTART, fnc=auto_start_main))
446         l.append(PluginDescriptor(where=PluginDescriptor.WHERE_SESSIONSTART, needsRestart=True, fnc=session_start_main, weight=-10))
447         l.append(PluginDescriptor(name=_("YouTube TV"), where=PluginDescriptor.WHERE_MENU, fnc=menu_start_youtube))
448         l.append(PluginDescriptor(name=_("YouTube TV Settings"), where=PluginDescriptor.WHERE_PLUGINMENU, fnc=plugin_setting_youtube))
449         l.append(PluginDescriptor(name=_("Browser Start/Stop"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=extension_toggle_browser))
450         l.append(PluginDescriptor(name=_("HbbTV Applications"), where=PluginDescriptor.WHERE_EXTENSIONSMENU, needsRestart=True, fnc=extension_start_application))
451         l.append(PluginDescriptor(name=_("Opera Web Browser"), description=_("start opera web browser"), where=PluginDescriptor.WHERE_PLUGINMENU, needsRestart=True, fnc=plugin_start_browser))
452         return l