1 from Plugins.Plugin import PluginDescriptor
3 import time, os, socket, thread, socket
4 from socket import gaierror, error
5 from os import path as os_path, remove as os_remove
8 import gdata.youtube.service
9 from gdata.service import BadAuthentication
11 from twisted.web import client
12 from twisted.internet import reactor
14 from urlparse import parse_qs
15 from urllib import quote, unquote_plus, unquote
16 from urllib2 import Request, URLError, urlopen as urlopen2
17 from httplib import HTTPConnection, CannotSendRequest, BadStatusLine, HTTPException
19 from Components.Button import Button
20 from Components.Label import Label
21 from Components.Pixmap import Pixmap
22 from Components.Sources.List import List
23 from Components.ConfigList import ConfigListScreen
24 from Components.Sources.StaticText import StaticText
25 from Components.ActionMap import NumberActionMap, ActionMap
26 from Components.ServiceEventTracker import ServiceEventTracker
27 from Components.config import config, ConfigSelection, getConfigListEntry
29 from Screens.Screen import Screen
30 from Screens.ChoiceBox import ChoiceBox
31 from Screens.MessageBox import MessageBox
32 from Screens.DefaultWizard import DefaultWizard
33 from Screens.InfoBarGenerics import InfoBarNotifications
35 from enigma import eTimer, eServiceReference, iPlayableService, fbClass, eRCInput, eConsoleAppContainer
37 HTTPConnection.debuglevel = 1
43 fbClass.getInstance().unlock()
47 fbClass.getInstance().lock()
54 class VuPlayer(Screen, InfoBarNotifications):
56 <screen name="VuPlayer" flags="wfNoBorder" position="center,620" size="455,53" title="VuPlayer" backgroundColor="transparent">
57 <ePixmap pixmap="Vu_HD/mp_wb_background.png" position="0,0" zPosition="-1" size="455,53" />
58 <ePixmap pixmap="Vu_HD/icons/mp_wb_buttons.png" position="40,23" size="30,13" alphatest="on" />
60 <widget source="session.CurrentService" render="PositionGauge" position="80,25" size="220,10" zPosition="2" pointer="skin_default/position_pointer.png:540,0" transparent="1" foregroundColor="#20224f">
61 <convert type="ServicePosition">Gauge</convert>
64 <widget source="session.CurrentService" render="Label" position="310,20" size="50,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" >
65 <convert type="ServicePosition">Position</convert>
67 <widget name="sidebar" position="362,20" size="10,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" />
68 <widget source="session.CurrentService" render="Label" position="374,20" size="50,20" font="Regular;18" halign="center" valign="center" backgroundColor="#4e5a74" transparent="1" >
69 <convert type="ServicePosition">Length</convert>
77 def __init__(self, session, service, lastservice):
78 Screen.__init__(self, session)
79 InfoBarNotifications.__init__(self)
81 self.session = session
82 self.service = service
83 self.lastservice = lastservice
84 self["actions"] = ActionMap(["OkCancelActions", "InfobarSeekActions", "MediaPlayerActions", "MovieSelectionActions"],
86 "ok": self.doInfoAction,
87 "cancel": self.doExit,
89 "playpauseService": self.playpauseService,
91 self["sidebar"] = Label(_("/"))
93 self.__event_tracker = ServiceEventTracker(screen = self, eventmap =
95 iPlayableService.evSeekableStatusChanged: self.__seekableStatusChanged,
96 iPlayableService.evStart: self.__serviceStarted,
97 iPlayableService.evEOF: self.__evEOF,
100 self.hidetimer = eTimer()
101 self.hidetimer.timeout.get().append(self.doInfoAction)
103 self.state = self.PLAYER_PLAYING
104 self.lastseekstate = self.PLAYER_PLAYING
105 self.__seekableStatusChanged()
107 self.onClose.append(self.__onClose)
111 self.session.nav.stopService()
113 def __seekableStatusChanged(self):
114 service = self.session.nav.getCurrentService()
115 if service is not None:
116 seek = service.seek()
117 if seek is None or not seek.isCurrentlySeekable():
118 self.setSeekState(self.PLAYER_PLAYING)
120 def __serviceStarted(self):
121 self.state = self.PLAYER_PLAYING
122 self.__seekableStatusChanged()
127 def __setHideTimer(self):
128 self.hidetimer.start(5000)
131 list = ((_("Yes"), "y"), (_("No, but play video again"), "n"),)
132 self.session.openWithCallback(self.cbDoExit, ChoiceBox, title=_("Stop playing this movie?"), list = list)
134 def cbDoExit(self, answer):
135 answer = answer and answer[1]
140 if self.state != self.PLAYER_IDLE:
141 self.session.nav.stopService()
142 self.state = self.PLAYER_IDLE
145 def setSeekState(self, wantstate):
146 service = self.session.nav.getCurrentService()
148 print "No Service found"
151 pauseable = service.pause()
152 if pauseable is not None:
153 if wantstate == self.PLAYER_PAUSED:
155 self.state = self.PLAYER_PAUSED
157 self.hidetimer.stop()
159 elif wantstate == self.PLAYER_PLAYING:
161 self.state = self.PLAYER_PLAYING
163 self.__setHideTimer()
165 self.state = self.PLAYER_PLAYING
167 def doInfoAction(self):
170 self.hidetimer.stop()
173 if self.state == self.PLAYER_PLAYING:
174 self.__setHideTimer()
177 if self.state == self.PLAYER_PAUSED:
179 self.__setHideTimer()
180 self.state = self.PLAYER_PLAYING
181 self.session.nav.playService(self.service)
183 self.__setHideTimer()
185 def playpauseService(self):
186 if self.state == self.PLAYER_PLAYING:
187 self.setSeekState(self.PLAYER_PAUSED)
188 elif self.state == self.PLAYER_PAUSED:
189 self.setSeekState(self.PLAYER_PLAYING)
191 VIDEO_FMT_PRIORITY_MAP = {
192 '38' : 1, #MP4 Original (HD)
193 '37' : 2, #MP4 1080p (HD)
194 '22' : 3, #MP4 720p (HD)
200 'User-Agent': 'Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.6) Gecko/20100627 Firefox/3.6.6',
201 'Accept-Charset': 'ISO-8859-1,utf-8;q=0.7,*;q=0.7',
202 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
203 'Accept-Language': 'en-us,en;q=0.5',
206 class VuPlayerLauncher:
207 def getVideoUrl(self, video_id):
210 if video_id is None or video_id == "":
213 # Getting video webpage
214 watch_url = 'http://www.youtube.com/watch?v=%s&gl=US&hl=en' % video_id
215 watchrequest = Request(watch_url, None, std_headers)
217 #print "trying to find out if a HD Stream is available",watch_url
218 watchvideopage = urlopen2(watchrequest).read()
219 except (URLError, HTTPException, socket.error), err:
220 print "Error: Unable to retrieve watchpage - Error code: ", str(err)
224 for el in ['&el=embedded', '&el=detailpage', '&el=vevo', '']:
225 info_url = ('http://www.youtube.com/get_video_info?&video_id=%s%s&ps=default&eurl=&gl=US&hl=en' % (video_id, el))
226 request = Request(info_url, None, std_headers)
228 infopage = urlopen2(request).read()
229 videoinfo = parse_qs(infopage)
230 if ('url_encoded_fmt_stream_map' or 'fmt_url_map') in videoinfo:
232 except (URLError, HTTPException, socket.error), err:
233 print "Error: unable to download video infopage",str(err)
236 if ('url_encoded_fmt_stream_map' or 'fmt_url_map') not in videoinfo:
237 if 'reason' not in videoinfo:
238 print 'Error: unable to extract "fmt_url_map" or "url_encoded_fmt_stream_map" parameter for unknown reason'
240 reason = unquote_plus(videoinfo['reason'][0])
241 print 'Error: YouTube said: %s' % reason.decode('utf-8')
246 if videoinfo.has_key('url_encoded_fmt_stream_map'):
247 tmp_fmtUrlDATA = videoinfo['url_encoded_fmt_stream_map'][0].split(',url=')
249 tmp_fmtUrlDATA = videoinfo['fmt_url_map'][0].split(',')
250 for fmtstring in tmp_fmtUrlDATA:
251 if videoinfo.has_key('url_encoded_fmt_stream_map'):
252 (fmturl, fmtid) = fmtstring.split('&itag=')
253 if fmturl.find("url=") !=-1:
254 fmturl = fmturl.replace("url=","")
256 (fmtid,fmturl) = fmtstring.split('|')
257 if VIDEO_FMT_PRIORITY_MAP.has_key(fmtid):
258 video_fmt_map[VIDEO_FMT_PRIORITY_MAP[fmtid]] = { 'fmtid': fmtid, 'fmturl': unquote_plus(fmturl) }
259 fmt_infomap[int(fmtid)] = unquote_plus(fmturl)
260 print "got",sorted(fmt_infomap.iterkeys())
261 if video_fmt_map and len(video_fmt_map):
262 video_url = video_fmt_map[sorted(video_fmt_map.iterkeys())[0]]['fmturl'].split(';')[0]
263 #print "found best available video format:",video_fmt_map[sorted(video_fmt_map.iterkeys())[0]]['fmtid']
264 #print "found best available video url:",video_url
267 def run(self, tubeid, session, service):
269 myurl = self.getVideoUrl(tubeid)
270 print "Playing URL", myurl
272 session.open(MessageBox, _("Sorry, video is not available!"), MessageBox.TYPE_INFO)
276 myreference = eServiceReference(4097, 0, myurl)
277 session.open(VuPlayer, myreference, service)
278 except Exception, msg:
280 print "Error >>", msg
282 class VuPlayerService:
283 def __init__(self, session):
285 self.socket_timeout = 0
286 self.max_buffer_size = 1024
287 self.uds_file = "/tmp/vuplus.tmp"
288 self.session = session
290 os.remove(self.uds_file)
294 def start(self, timeout = 1):
295 self.socket_timeout = timeout
296 thread.start_new_thread(self.run, (True,))
304 def run(self, e = True):
307 print "VuPlayerService start!!"
309 self.sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
310 self.sock.settimeout(self.socket_timeout)
311 self.sock.bind(self.uds_file)
315 conn, addr = self.sock.accept()
316 self.parseHandle(conn, addr)
317 except socket.timeout:
318 #print "[socket timeout]"
320 print "VuPlayerService stop!!"
322 def parseHandle(self, conn, addr):
323 # [http://www.youtube.com/watch?v=BpThu778qB4&feature=related]
324 data = conn.recv(self.max_buffer_size)
325 print "[%s]" % (data)
326 if data.startswith("http://www.youtube.com"):
327 tmp = data.split("?")
328 print tmp # ['http://www.youtube.com/watch', 'v=BpThu778qB4&feature=related']
329 service = self.session.nav.getCurrentlyPlayingServiceReference()
330 if len(tmp) == 2 and tmp[0] == "http://www.youtube.com/watch":
331 tmp = tmp[1].split("&")
332 print tmp # ['v=BpThu778qB4', 'feature=related']
334 tmp = tmp[0].split("=")
335 print tmp # ['v', 'BpThu778qB4']
336 if len(tmp) == 2 and tmp[0] == "v":
337 player = VuPlayerLauncher()
338 player.run(tmp[1], self.session, service)
341 self.session.nav.playService(service)
344 data = "nok$parsing fail"
346 data = "nok$parsing fail"
348 data = "nok$parsing fail"
349 self.sendResponse(conn, data)
351 def sendResponse(self, conn, data):
355 class BrowserLauncher(ConfigListScreen, Screen):
357 <screen name="BrowserLauncher" position="center,center" size="309,458" title="Web Browser">
358 <ePixmap pixmap="Vu_HD/buttons/red.png" position="4,0" size="40,40" alphatest="on" />
359 <ePixmap pixmap="Vu_HD/buttons/green.png" position="100,0" size="40,40" alphatest="on" />
360 <ePixmap pixmap="Vu_HD/buttons/button_off.png" position="200,0" size="40,40" alphatest="on" />
361 <widget source="key_red" render="Label" position="15,0" zPosition="1" size="50,30" font="Regular;20" halign="right" valign="center" transparent="1" />
362 <widget source="key_green" render="Label" position="120,0" zPosition="1" size="50,30" font="Regular;20" halign="right" valign="center" transparent="1" />
363 <widget name="config" position="0,50" size="309,60" scrollbarMode="showOnDemand" />
364 <ePixmap pixmap="Vu_HD/rc_wb_desc.png" position="0,110" size="309,296" alphatest="on" />
365 <widget name="info" position="0,415" size="309,50" font="Regular;18" halign="center" foregroundColor="blue" transparent="1" />
369 def __init__(self, session):
370 Screen.__init__(self, session)
371 self.session = session
373 self.browser_root = "/usr/bin"
374 self.browser_name = "arora"
375 self.mouse_cond = "/proc/stb/fp/mouse"
376 self["actions"] = ActionMap(["OkCancelActions", "ShortcutActions", "WizardActions", "ColorActions", "SetupActions", ],
377 { "red": self.keyCancel,
379 "cancel": self.keyExit,
381 self.info = Label(_("If you want to quit the Browser,\nPress RED and EXIT."))
382 self["info"] = self.info
383 self["key_red"] = StaticText(_("Exit"))
384 self["key_green"] = StaticText(_("Start"))
387 ConfigListScreen.__init__(self, self.list)
389 self.devices_string = ""
390 self.mouse_choice_list = []
391 self.mouse_device_list = []
392 self.keyboard_choice_list = []
393 self.keyboard_device_list = []
398 self.vu_service = VuPlayerService(self.session)
399 self.vu_service.start(timeout=5)
401 self.exit_wait_cond = False
402 self.timer_exit_cond = eTimer()
403 self.timer_exit_cond.callback.append(self.resetExitCond)
405 def enableRCMouse(self, mode): #mode=[0|1]|[False|True]
406 if os.path.exists(self.mouse_cond):
407 self.cmd("echo %d > %s" % (mode, self.mouse_cond))
410 print "prepared cmd:", cmd
417 self.vu_service.stop()
418 self.cmd("killall -9 %s"%(self.browser_name))
419 self.cmd("echo 60 > /proc/sys/vm/swappiness")
420 if self.mouse.value == 0:
421 self.enableRCMouse(False) #rc-mouse off
422 fbClass.getInstance().unlock()
423 #eRCInput.getInstance().unlock()
427 if self.exit_wait_cond:
429 if self.isProcessRunable() == False:
433 if self.isProcessRunable() == False:
435 self.exit_wait_cond = True
436 self.timer_exit_cond.start(5000)
438 def resetExitCond(self):
439 self.timer_exit_cond.stop()
440 self.exit_wait_cond = False
442 def isProcessRunable(self):
443 cmd = "/bin/ps -ef | grep %s | grep -v grep | awk \'{print $5}\'"%(self.browser_name)
444 for line in os.popen(cmd).readlines():
448 def makeConfig(self):
449 self.devices = eConsoleAppContainer()
450 self.devices.dataAvail.append(self.callbackDevicesDataAvail)
451 self.devices.appClosed.append(self.callbakcDevicesAppClose)
452 self.devices.execute(_("cat /proc/bus/input/devices"))
454 def callbackDevicesDataAvail(self, ret_data):
455 self.devices_string = self.devices_string + ret_data
457 def callbakcDevicesAppClose(self, retval):
458 self.parseDeviceData(self.devices_string)
459 self.makeHandlerList()
461 # none : -1, rc : 0, usb : 1
462 self.mouse_choice_list.append((2, _("None")))
463 self.keyboard_choice_list.append((2, _("None")))
465 print self.mouse_choice_list
466 print self.keyboard_choice_list
467 print self.mouse_device_list
468 print self.keyboard_device_list
470 self.mouse = ConfigSelection(default = self.mouse_choice_list[0][0], choices = self.mouse_choice_list)
471 self.keyboard = ConfigSelection(default = self.mouse_choice_list[0][0], choices = self.keyboard_choice_list)
473 self.list.append(getConfigListEntry(_('Mouse'), self.mouse))
474 self.list.append(getConfigListEntry(_('Keyboard'), self.keyboard))
475 self["config"].list = self.list
476 self["config"].l.setList(self.list)
478 def parseDeviceData(self, data):
483 lines=data.split('\n')
485 if line == None or line == "":
486 if h != None and len(h) != 0:
487 print "find driver >> name[%s], phys[%s], handler[%s]" % (n, p, h)
488 self.devices.append([n, p, h])
498 h = line[12:].strip()
500 def makeHandlerList(self):
501 if self.devices == None or self.devices == []:
508 for dev in self.devices:
512 if p.startswith("usb-ohci-brcm"):
513 if h.rfind("mouse") >= 0:
514 mouse_pc_h = [(1, _("USB Mouse")), self.getHandlerName(h, "mouse")]
516 if len(keyboard_pc_h) == 0:
517 keyboard_pc_h = [(1, _("USB Keyboard")), self.getHandlerName(h, "event")]
519 if n[1:].startswith("dreambox") and os.path.exists(self.mouse_cond) :
520 mouse_rc_h = [(0, _("RemoteControl")), self.getHandlerName(h, "event")]
521 keyboard_rc_h = [(0, _("RemoteControl")), self.getHandlerName(h, "event")]
522 if len(mouse_rc_h) > 0:
523 self.mouse_choice_list.append(mouse_rc_h[0])
524 self.mouse_device_list.append(mouse_rc_h[1])
525 if len(mouse_pc_h) > 0:
526 self.mouse_choice_list.append(mouse_pc_h[0])
527 self.mouse_device_list.append(mouse_pc_h[1])
529 if len(keyboard_rc_h) > 0:
530 self.keyboard_choice_list.append(keyboard_rc_h[0])
531 self.keyboard_device_list.append(keyboard_rc_h[1])
532 if len(keyboard_pc_h) > 0:
533 self.keyboard_choice_list.append(keyboard_pc_h[0])
534 self.keyboard_device_list.append(keyboard_pc_h[1])
537 def getHandlerName(self, h, s):
538 if h is None or len(h) == 0:
542 #print "handles >> ", handles
543 for tmp_h in handles:
544 #print "handle_item >> ", tmp_h
545 if tmp_h.startswith(s):
546 #print "detected : [%s]" % tmp_h
550 def startBrowser(self):
551 self.timer_start.stop()
554 self.cmd("killall -9 %s"%(self.browser_name))
555 self.cmd("echo 0 > /proc/sys/vm/swappiness")
560 browser_cmd = "%s/%s -qws" % (self.browser_root, self.browser_name)
562 fbClass.getInstance().lock()
563 #eRCInput.getInstance().lock()
565 if self.mouse.value == 0:
566 self.enableRCMouse(True) #rc-mouse on
567 idx = self.getListIndex(self.mouse_choice_list, 0)
568 mouse_cmd = "export QWS_MOUSE_PROTO=LinuxInput:/dev/input/%s; " % (self.mouse_device_list[idx])
569 elif self.mouse.value == 1:
571 #mouse_cmd = "export QWS_MOUSE_PROTO=Auto:/dev/input/%s; " % (m)
572 elif self.mouse.value == 2:
573 mouse_cmd = "export QWS_MOUSE_PROTO=None; "
575 if self.keyboard.value == 0:
576 idx = self.getListIndex(self.keyboard_choice_list, 0)
577 kbd_cmd = "export QWS_KEYBOARD=LinuxInput:/dev/input/%s; " % (self.keyboard_device_list[idx])
578 elif self.keyboard.value == 1:
579 idx = self.getListIndex(self.keyboard_choice_list, 1)
580 kbd_cmd = "export QWS_KEYBOARD=LinuxInput:/dev/input/%s; " % (self.keyboard_device_list[idx])
581 elif self.keyboard.value == 2:
583 print "mouse cmd >>", mouse_cmd, " >> ", self.mouse.value
584 print "keyboard cmd >>", kbd_cmd, " >> ", self.keyboard.value
586 cmd = "%s%s%s%s" % (extra_cmd, kbd_cmd, mouse_cmd, browser_cmd)
587 print "prepared command : [%s]" % cmd
589 self.launcher = eConsoleAppContainer()
590 self.launcher.appClosed.append(self.callbackLauncherAppClosed)
591 self.launcher.dataAvail.append(self.callbackLauncherDataAvail)
592 self.launcher.execute(cmd)
593 print "started browser..."
596 self.info.setText("Starting Webbrowser. Please wait...")
597 if self.lock == False:
598 self.timer_start = eTimer()
599 self.timer_start.callback.append(self.startBrowser)
600 self.timer_start.start(10)
602 def getListIndex(self, l, v):
610 def callbackLauncherDataAvail(self, ret_data):
612 if ret_data.startswith("--done--"):
616 def callbackLauncherAppClosed(self, retval = 1):
619 def sessionstart(session, **kwargs):
620 if os.path.exists("/proc/stb/fp/mouse"):
621 os.system("echo 0 > /proc/stb/fp/mouse")
623 def main(session, **kwargs):
624 session.open(BrowserLauncher)
626 def Plugins(**kwargs):
627 return [PluginDescriptor(where = PluginDescriptor.WHERE_SESSIONSTART, needsRestart = False, fnc=sessionstart),
628 PluginDescriptor(name=_("Web Browser"), description="start web browser", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=main)]