class TestPluginStream(unittest.TestCase): def setUp(self): self.session = Livestreamer() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def _test_akamaihd(self, surl, host, streamname): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, AkamaiHDStream)) self.assertEqual(stream.host, host) self.assertEqual(stream.streamname, streamname) def _test_hls(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) def _test_rtmp(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, RTMPStream)) self.assertEqual(stream.params["rtmp"], url) self.assertDictHas(params, stream.params) def test_plugin(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) self._test_rtmp("rtmp://hostname.se/stream live=1 num=47", "rtmp://hostname.se/stream", dict(live=True, num=47)) self._test_rtmp( "rtmp://hostname.se/stream live=1 qarg='a \'string' noq=test", "rtmp://hostname.se/stream", dict(live=True, qarg='a \'string', noq="test")) self._test_hls("hls://http://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se", "stream")
class TestSession(unittest.TestCase): PluginPath = os.path.join(os.path.dirname(__file__), "plugins") def setUp(self): self.session = Livestreamer() self.session.load_plugins(self.PluginPath) def test_exceptions(self): try: self.session.resolve_url("invalid url") self.assertTrue(False) except NoPluginError: self.assertTrue(True) def test_load_plugins(self): plugins = self.session.get_plugins() self.assertTrue(plugins["testplugin"]) def test_builtin_plugins(self): plugins = self.session.get_plugins() self.assertTrue("justintv" in plugins) def test_resolve_url(self): plugins = self.session.get_plugins() channel = self.session.resolve_url("http://test.se/channel") self.assertTrue(isinstance(channel, Plugin)) self.assertTrue(isinstance(channel, plugins["testplugin"])) def test_options(self): self.session.set_option("test_option", "option") self.assertEqual(self.session.get_option("test_option"), "option") self.assertEqual(self.session.get_option("non_existing"), None) self.assertEqual( self.session.get_plugin_option("testplugin", "a_option"), "default") self.session.set_plugin_option("testplugin", "another_option", "test") self.assertEqual( self.session.get_plugin_option("testplugin", "another_option"), "test") self.assertEqual( self.session.get_plugin_option("non_existing", "non_existing"), None) self.assertEqual( self.session.get_plugin_option("testplugin", "non_existing"), None) def test_plugin(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams() self.assertTrue("best" in streams) self.assertTrue(streams["best"] is streams["1080p"]) self.assertTrue(isinstance(streams["rtmp"], RTMPStream)) self.assertTrue(isinstance(streams["http"], HTTPStream)) self.assertTrue(isinstance(streams["hls"], HLSStream)) self.assertTrue(isinstance(streams["akamaihd"], AkamaiHDStream))
class TestPluginStream(unittest.TestCase): def setUp(self): self.session = Livestreamer() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def _test_akamaihd(self, surl, host, streamname): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, AkamaiHDStream)) self.assertEqual(stream.host, host) self.assertEqual(stream.streamname, streamname) def _test_hls(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) def _test_rtmp(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, RTMPStream)) self.assertEqual(stream.params["rtmp"], url) self.assertDictHas(params, stream.params) def test_plugin(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) self._test_rtmp("rtmp://hostname.se/stream live=1 num=47", "rtmp://hostname.se/stream", dict(live=True, num=47)) self._test_rtmp("rtmp://hostname.se/stream live=1 qarg='a \'string' noq=test", "rtmp://hostname.se/stream", dict(live=True, qarg='a \'string', noq="test")) self._test_hls("hls://http://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se", "stream")
class TestSession(unittest.TestCase): PluginPath = os.path.join(os.path.dirname(__file__), "plugins") def setUp(self): self.session = Livestreamer() self.session.load_plugins(self.PluginPath) def test_exceptions(self): try: self.session.resolve_url("invalid url") self.assertTrue(False) except NoPluginError: self.assertTrue(True) def test_load_plugins(self): plugins = self.session.get_plugins() self.assertTrue(plugins["testplugin"]) def test_builtin_plugins(self): plugins = self.session.get_plugins() self.assertTrue("justintv" in plugins) def test_resolve_url(self): plugins = self.session.get_plugins() channel = self.session.resolve_url("http://test.se/channel") self.assertTrue(isinstance(channel, Plugin)) self.assertTrue(isinstance(channel, plugins["testplugin"])) def test_options(self): self.session.set_option("test_option", "option") self.assertEqual(self.session.get_option("test_option"), "option") self.assertEqual(self.session.get_option("non_existing"), None) self.assertEqual(self.session.get_plugin_option("testplugin", "a_option"), "default") self.session.set_plugin_option("testplugin", "another_option", "test") self.assertEqual(self.session.get_plugin_option("testplugin", "another_option"), "test") self.assertEqual(self.session.get_plugin_option("non_existing", "non_existing"), None) self.assertEqual(self.session.get_plugin_option("testplugin", "non_existing"), None) def test_plugin(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams() self.assertTrue("best" in streams) self.assertTrue(streams["best"] is streams["1080p"]) self.assertTrue(isinstance(streams["rtmp"], RTMPStream)) self.assertTrue(isinstance(streams["http"], HTTPStream)) self.assertTrue(isinstance(streams["hls"], HLSStream)) self.assertTrue(isinstance(streams["akamaihd"], AkamaiHDStream))
def GetYoutubeFullLink(url): from livestreamer import Livestreamer livestr = Livestreamer() channel = livestr.resolve_url(url) streams = channel.get_streams() stream = streams["best"] return stream.url
def face_detect(x, y, width, height, stream_url): x = x*426/651 y = y*240/398 width = width*426/651 height = height*240/398 cascade_fn = "haarcascade_frontalface_alt.xml" nested_fn = "haarcascade_eye.xml" cascade = cv2.CascadeClassifier(cascade_fn) nested = cv2.CascadeClassifier(nested_fn) FFMPEG_BIN = 'C:/ffmpeg/bin/ffmpeg.exe' livestreamer = Livestreamer() plugin = livestreamer.resolve_url(stream_url) streams = plugin.get_streams() stream = streams.get("best") VIDEO_URL = stream.url print VIDEO_URL pipe = sp.Popen([FFMPEG_BIN, "-i", VIDEO_URL, "-loglevel", "quiet", # no text output "-an", # disable audio "-f", "image2pipe", "-pix_fmt", "bgr24", "-vcodec", "rawvideo", "-"], stdin=sp.PIPE, stdout=sp.PIPE) interval = 0 while True: raw_image = pipe.stdout.read(426 * 240 * 3) # read 432*240*3 bytes (= 1 frame) img = np.fromstring(raw_image, dtype='uint8').reshape((240, 426, 3)) img = img[y:(y + height), x:(x + width)] gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) gray = cv2.equalizeHist(gray) rects = detect(gray, cascade) vis = img.copy() if rects: interval += 1 draw_rects(vis, rects, (0, 255, 0)) for x1, y1, x2, y2 in rects: roi = gray[y1:y2, x1:x2] vis_roi = vis[y1:y2, x1:x2] subrects = detect(roi.copy(), nested) draw_rects(vis_roi, subrects, (255, 0, 0)) cv2.imwrite('./media/face', vis) if cv2.waitKey(5) == 27: break cv2.destroyAllWindows()
def serveFile(self, fURL, sendData): if (sendData): fURL, quality = player.GetStreamUrl(unquote(fURL)) session = Livestreamer() if '|' in fURL: sp = fURL.split('|') fURL = sp[0] headers = dict(urlparse.parse_qsl(sp[1])) session.set_option("http-headers", headers) session.set_option("http-ssl-verify", False) session.set_option("hls-segment-threads", 3) session.set_option("stream-segment-threads", 3) try: #streams = session.streams(fURL) channel = session.resolve_url(fURL) streams = channel.get_streams() except Exception as ex: traceback.print_exc(file=sys.stdout) self.send_response(403) self.send_response(200) #print "XBMCLocalProxy: Sending headers..." self.end_headers() #print "XBMCLocalProxy: Sending data..." fileout = self.wfile try: stream = streams[quality] try: response = stream.open() buf = 'INIT' while (buf != None and len(buf) > 0): buf = response.read(200 * 1024) fileout.write(buf) fileout.flush() response.close() fileout.close() #print time.asctime(), "Closing connection" except socket.error, e: #print time.asctime(), "Client Closed the connection." try: response.close() fileout.close() except Exception, e: return except Exception, e: traceback.print_exc(file=sys.stdout) response.close() fileout.close()
def serveFile(self, fURL, sendData): if (sendData): fURL, quality = player.GetStreamUrl(unquote(fURL)) session = Livestreamer() if '|' in fURL: sp = fURL.split('|') fURL = sp[0] headers = dict(urlparse.parse_qsl(sp[1])) session.set_option("http-headers", headers) session.set_option("http-ssl-verify",False) session.set_option("hls-segment-threads",3) session.set_option("stream-segment-threads",3) try: #streams = session.streams(fURL) channel = session.resolve_url(fURL) streams = channel.get_streams() except Exception as ex: traceback.print_exc(file=sys.stdout) self.send_response(403) self.send_response(200) #print "XBMCLocalProxy: Sending headers..." self.end_headers() #print "XBMCLocalProxy: Sending data..." fileout = self.wfile try: stream = streams[quality] try: response = stream.open() buf = 'INIT' while (buf != None and len(buf) > 0): buf = response.read(200 * 1024) fileout.write(buf) fileout.flush() response.close() fileout.close() #print time.asctime(), "Closing connection" except socket.error, e: #print time.asctime(), "Client Closed the connection." try: response.close() fileout.close() except Exception, e: return except Exception, e: traceback.print_exc(file=sys.stdout) response.close() fileout.close()
def get_streams(self): live = Livestreamer() print self.url live.set_option("http-ssl-verify", False) streams = None live.load_plugins(os.path.join(os.getcwd(), "plugins")) try: plugin = live.resolve_url(self.url) streams = plugin.get_streams() self.play_url = stream_to_url(streams.get("best")) except NoPluginError: print("No plugin can handle URL") except PluginError as err: print("{0}", err)
def get_stream(stream_url): # change to a stream that is actually online livestreamer = Livestreamer() stream = None try: plugin = livestreamer.resolve_url("http://www.twitch.tv/" + stream_url) plugin.set_option('oauth_token', 'xtlhyl6uapy6znsvuhy4zfk0jbt086') streams = plugin.get_streams() # It seems best isn't necessarily the best, twitch doesn't seem to consider 60 # streams, so we should search for those first. if '1080p60' in streams: stream = streams['1080p60'] elif '720p60' in streams: stream = streams['720p60'] else: stream = streams['best'] except Exception: pass return stream
def main(): if len(sys.argv) < 3: exit("Usage: {0} <url> <quality>".format(sys.argv[0])) # Collect arguments url = sys.argv[1] quality = sys.argv[2] # Create the Livestreamer session livestreamer = Livestreamer() # Enable logging livestreamer.set_loglevel("info") livestreamer.set_logoutput(sys.stdout) # Attempt to find a plugin for this URL try: plugin = livestreamer.resolve_url(url) except NoPluginError: exit("Livestreamer is unable to handle the URL '{0}'".format(url)) # Attempt to fetch streams try: streams = plugin.get_streams() except PluginError as err: exit("Plugin error: {0}".format(err)) if len(streams) == 0: exit("No streams found on URL '{0}'".format(url)) # Look for specified stream if quality not in streams: exit("Unable to find '{0}' stream on URL '{1}'".format(quality, url)) # We found the stream stream = streams[quality] # Create the player and start playback player = LivestreamerPlayer() # Blocks until playback is done player.play(stream)
class GreekStreamTVList(Screen): skin = '\n \t\t<screen name="GreekStreamTVList" position="center,center" size="800,400" title="GreekStreamTV List (Livestreamer) v3.2">\n\t\t\t<widget name="streamlist" position="0,0" size="800,360" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />\n\t\t\t<widget name="info" position="0,365" zPosition="2" size="800,35" font="Regular;22" foregroundColor="#ffffff" transparent="1" halign="center" valign="center" />\n\t\t</screen>\n ' def __init__(self, session, streamFile=None): self.session = session Screen.__init__(self, session) self['info'] = Label('...') self['actions'] = ActionMap( [ 'OkCancelActions', 'ShortcutActions', 'WizardActions', 'ColorActions', 'SetupActions', 'NumberActions', 'MenuActions' ], { 'ok': self.keyOK, 'cancel': self.keyCancel, 'up': self.keyUp, 'down': self.keyDown, 'left': self.keyLeft, 'right': self.keyRight }, -1) self.streamBin = '/usr/bin/rtmpdump' self.streamPipe = '/tmp/greekstreamtv.avi' if not streamFile: self.streamFile = resolveFilename( SCOPE_PLUGINS, 'Extensions/GreekStreamTV/stream.xml') else: self.streamFile = streamFile self.lvstreamer = Livestreamer() self.streamList = [] self.makeStreamList() self.streamMenuList = MenuList([], enableWrapAround=True, content=eListboxPythonMultiContent) self.streamMenuList.l.setFont(0, gFont('Regular', 22)) self.streamMenuList.l.setFont(1, gFont('Regular', 18)) self.streamMenuList.l.setItemHeight(37) self['streamlist'] = self.streamMenuList self.streamMenuList.setList(map(streamListEntry, self.streamList)) self.onLayoutFinish.append(self.layoutFinished) self.beforeService = None self.currentService = None self.playerStoped = False self.keyLocked = False self.pd = None self.qsel = None return def layoutFinished(self): os.system('killall -9 rtmpdump') self.showName() def keyLeft(self): if self.keyLocked: return self['streamlist'].pageUp() self.showName() def keyRight(self): if self.keyLocked: return self['streamlist'].pageDown() self.showName() def keyUp(self): if self.keyLocked: return self['streamlist'].up() self.showName() def keyDown(self): if self.keyLocked: return self['streamlist'].down() self.showName() def keyCancel(self): self.LivestreamerStop() if '/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV' in path: path.remove( '/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV') self.close() def showName(self): try: tmpName = self['streamlist'].getCurrent()[0][1].get('name') except: tmpName = '...' self['info'].setText(tmpName) def keyOK(self): print '[GreekStreamTVList::keyOK]' if self.keyLocked: return uriName = self['streamlist'].getCurrent()[0][1].get('name') self['info'].setText('Starting %s Please Wait...' % uriName) self.timer = eTimer() self.timer.callback.append(self.StartStream) self.timer.start(100, 1) def StartStream(self): self.timer.stop() self.keyLocked = True self.beforeService = None self.currentService = None self.playerStoped = False self.pd = None streamInfo = self['streamlist'].getCurrent()[0][1] uriInfo = streamInfo.get('uri') typeInfo = streamInfo.get('type').split(':') protocol = typeInfo[0] serviceType = typeInfo[1] bufferSize = typeInfo[2] url = uriInfo.get('URL') if protocol == 'rtmp': url += ' ' url += ' '.join([ '%s=%s' % (key, value) for key, value in uriInfo.items() if key != 'URL' ]) url = ' '.join(url.split()) print '[GreekStreamTVList::keyOK] URL is ', url, ' URI is ', uriInfo self.doStreamAction(url, serviceType, bufferSize) elif protocol in ('rtsp', 'http'): self.doStreamAction(url, serviceType, bufferSize) elif protocol == 'livestreamer': channel = None streams = None try: url += ' ' url += ' '.join([ '%s=%s' % (key, value) for key, value in uriInfo.items() if key != 'URL' ]) url = ' '.join(url.split()) print '[GreekStreamTVList::keyOK] URL is ', url, ' URI is ', uriInfo channel = self.lvstreamer.resolve_url(url) streams = channel.get_streams() print '[GreekStreamTVList::keyOK] Streams: ', streams.keys() print '[GreekStreamTVList::keyOK] Streams: ', streams.items() if len(streams ) == 3 and 'best' in streams and 'worst' in streams: self.streamPreBuffer(streams['best']) elif len(streams) == 0: raise Exception('No Streams Found') else: self.qsel = self.session.openWithCallback( self.QualitySelClosed, SelectQuality, streams, self.streamPreBuffer) except Exception as err: print '[GreekStreamTVList::keyOK::Exception] Error: ', err tmpMessage = 'An Error Occured: ' + str(err)[:200] + '...' self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=20) else: print '[GreekStreamTVList::keyOK] Unknown Protocol: ', protocol tmpMessage = 'Unknown Protocol: ' + protocol self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_WARNING, timeout=20) return def QualitySelClosed(self, recursive): if self.qsel: self.qsel.close() self.qsel = None self.stopPlayer() return def streamPreBuffer(self, stream): fd = None try: fd = stream.open() prebuffer = fd.read(1049088) if len(prebuffer) == 0: raise Exception('No Data Received From Stream Server') start_new_thread(self.streamCopy, (fd, prebuffer)) sleep(1.5) self.doStreamAction(self.streamPipe) except Exception as err: if fd and hasattr(fd, 'close'): fd.close() print '[GreekStreamTVList::streamPreBuffer::Exception] Error: ', err tmpMessage = 'An Error Occured while buffering: ' + str( err)[:200] + '...' self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=20) return def streamCopy(self, fd, prebuffer): print '[GreekStreamTVList::streamCopy]' if os.access(self.streamPipe, os.F_OK): os.remove(self.streamPipe) os.mkfifo(self.streamPipe) self.pd = open(self.streamPipe, 'wb') try: self.pd.write(prebuffer) while self is not None and self.session is not None and not self.playerStoped: data = fd.read(8192) if len(data) == 0: break self.pd.write(data) print '[GreekStreamTVList:streamCopy] playerStoped' self.pd.close() if hasattr(fd, 'close'): fd.close() fd = None except Exception as err: print '[GreekStreamTVList::streamCopy] Exception: ', err finally: self.playerStoped = True if fd and hasattr(fd, 'close'): fd.close() return def LivestreamerStop(self): print '[GreekStreamTVList::LivestreamStop]' self['info'].setText('...') self.keyLocked = False self.playerStoped = True os.system('killall -9 rtmpdump') sleep(0.5) if self.pd: try: self.pd.close() except: sleep(0.5) try: self.pd.close() except: pass if self.qsel is not None: self.qsel.close(False) self.pd = None self.qsel = None return def doStreamAction(self, url=None, serviceType=4097, bufferSize=None): if url is None: url = self.streamPipe self.streamPlayerTimer.stop() try: serviceType = int(serviceType) except: serviceType = 4097 try: bufferSize = int(bufferSize) except: bufferSize = None service = eServiceReference(serviceType, 0, url) streamInfo = self['streamlist'].getCurrent()[0][1] service.setName(str(streamInfo.get('name'))) uriInfo = streamInfo.get('uri') self.beforeService = self.session.nav.getCurrentlyPlayingServiceReference( ) self.currentService = self.session.openWithCallback( self.onStreamFinished, GreekStreamTVPlayer, service, stopPlayer=self.stopPlayer, chName=str(streamInfo.get('name')), chURL=str(uriInfo.get('URL')), chIcon=str(streamInfo.get('icon'))) return def stopPlayer(self, params=None): print '[GreekStreamTV::stopPlayer]' if params is None or isinstance(params, bool): self.playerStoped = True self.LivestreamerStop() return else: return def onStreamFinished(self): print '[GreekStreamTV::onStreamFinished]' self.LivestreamerStop() self.session.nav.playService(self.beforeService) print '[GreekStreamTV::onStreamFinished] player done!!' def makeStreamList(self): try: streamDB = StreamURIParser(self.streamFile).parseStreamList() except Exception as err: print '[GreekStreamTV::makeStreamList] Error: ', err streamDB = [] self.streamList = [(x.get('name'), x) for x in streamDB]
class Main: def __init__(self): self.gchoice = -1 self.cchoice = -1 self.exit_now = False self.state = 'none' self.keybingings = { ord('q'): self.quit, ord('f'): self.get_favorites, ord('s'): self.get_fav_games, ord('g'): self.get_games, ord('n'): self.get_next, ord('r'): self.refresh, ord('p'): self.get_previous } self.games = [] self.favs = [] self.channels = [] self.twitch = Twitch(config.get('settings', 'twitchapiurl'), config.get('settings', 'channel'), config.get('settings', 'game')) self.livestreamer = Livestreamer() try: self.run() except Exception as e: print e.message def run(self): while True: self.display_message() if self.exit_now: return def quit(self, c): self.exit_now = True def display_message(self): if self.state == 'none': clear_screen() self.handle_user_input('Escoge una opcion : Favoritos(F), Juegos(G), Salir(Q)') if self.state == 'favs': clear_screen() print 'Mostrando transmisiones favoritas en linea :' print '-' * 40 if(len(self.favs) > 0): self.show_content(self.favs) self.handle_user_input('Escoge un canal por numero (r para refrescar, g para enlistar juegos y q para salir', range(len(self.favs) + 1)) clear_screen() else: self.handle_user_input('No hay canales favoritos en linea (r para refrescar, g para enlistar juegos y q para salir', range(len(self.favs) + 1)) clear_screen() if self.state == 'games': clear_screen() print 'Mostrando %d juegos destacados:' % config.getint('settings', 'game') print '-' * 40 if(len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input('Escoge un juego por numero (r para refrescar, f para revisar tus canales favoritos y q para salir', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'favgames': clear_screen() print 'Mostrando juegos favoritos:' print '-' * 40 if(len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input('Escoge un juego por numero (r para refrescar, f para revisar tus canales favoritos y q para salir', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'channels': clear_screen() print 'Mostrando %d canales destacados para %s:' % (config.getint('settings', 'channel'), self.games[self.gchoice - 1]) print '-' * 40 self.get_channels(self.gchoice) if(len(self.channels) > 0): self.show_content(self.channels) self.cchoice = self.handle_user_input('Escoge un canal por numero (r para refrescar, f para revisar tus canales favoritos, g para enlistar juegos y q para salir', range(len(self.channels) + 1)) if self.cchoice != -1: self.play_stream(self.channels[self.cchoice - 1]) self.state = 'channels' clear_screen() def play_stream(self, channel): clear_screen() try: plugin = self.livestreamer.resolve_url(("twitch.tv/{0}").format(channel)) except Exception as e: print e.message try: streams = plugin.get_streams() except PluginError as err: exit("Plugin error: {0}".format(err)) player = config.get('settings', 'player') quality = config.get('settings', 'quality') if quality not in streams: quality = "best" print "No se puede abrirla transmision con la calidad solicitada ({0}), abriendo la de mejor calidad".format(config.get('settings', 'quality')) channel = transform_spaces(channel) if os.name == 'nt': #os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) os.system('livestreamer -p "%s" twitch.tv/%s %s' % (player, channel, quality)) else: #os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) os.system('livestreamer -np "%s" twitch.tv/%s %s' % (player, channel, quality)) def show_content(self, content): for i in range(len(content)): if i < 9: print '', if i < 99: print '', print '%d %s' % (i + 1, content[i]) def handle_user_input(self, message, valid = None): self.state = 'none' validinput = False while not validinput: input = raw_input('%s\n ' % message) input = input.strip().lower() if input.isdigit(): input = int(input) if input in valid: validinput = True return input elif len(input) == 1: c = ord(input) f = self.keybingings.get(c, None) if f: f(c) validinput = True return -1 def get_favorites(self, c): self.state = 'favs' del self.favs[:] try: response = self.twitch.get_favorites_streams_status(config.get('settings', 'favorites')) receivedcount = len(response['streams']) for i in range(receivedcount): self.favs.append('%s Reproduciendo: %s' % (response['streams'][i]['channel']['name'], response['streams'][i]['game'])) except Exception as e: print 'Error obteniendo transmisiones favoritas!\n' print e.message return 0 def get_games(self, c): self.state = 'games' del self.games[:] try: response = self.twitch.get_game_list() receivedcount = len(response['top']) for i in range(receivedcount): self.games.append(response['top'][i]['game']['name']) except Exception as e: print 'Error obteniendo juegos !\n' print e.message return 0 def get_fav_games(self, c): self.state = 'favgames' del self.games[:] favgames = config.get('settings', 'favgames') if len(favgames) > 0: self.games.extend(favgames.split(', ')) def get_channels(self, choice): self.state = 'channels' del self.channels[:] try: response = self.twitch.get_channel_for_game(transform_spaces(self.games[self.gchoice - 1])) receivedcount = len(response['streams']) for i in range(receivedcount): self.channels.append('%s (%s)' % (response['streams'][i]['channel']['name'], response['streams'][i]['viewers'])) except Exception as e: print 'Error obteniendo canales !\n' print e.message return 0 def refresh(self, c): print 'tmp' def get_next(self, c): print 'tmp' def get_previous(self, c): print 'tmp'
class StreamAnalysis( Thread ): def __init__( self, timeList, eventList, worldmap ): Thread.__init__( self ) self._timeList = timeList self._eventList = eventList self._timeZero = 1392254560 # set up templates as private variables for this class self._templatesTime = pickle.load( open('timeValues.data', 'rb') ) self._templatesRed = pickle.load( open('redTemplates.data', 'rb') ) self._templatesEvent = pickle.load( open('eventTemplates.data', 'rb') ) self._worldmap = cv2.cvtColor(worldmap.copy(), cv2.COLOR_BGR2GRAY) def initStream( self ): self._livestreamer = Livestreamer() self._plugin = self._livestreamer.resolve_url('http://twitch.tv/twitchplayspokemon') def fetchStream( self ): streams = self._plugin.get_streams() if 'source' in streams: return streams.get('source') return False def run( self ): self.initStream() stream = self.fetchStream() while stream == False: print 'STREAM' time.sleep(60) print 'rechecking if stream is available' stream = self.fetchStream() #cap = cv2.VideoCapture( 'http://store22.media22.justin.tv/archives/2014-2-17/live_user_twitchplayspokemon_1392633446.flv' ) cap = cv2.VideoCapture( stream.url ) tmpTimeValues = [] last_position = (-1, -1) while True: if not overridePosition == (-1, -1) and last_position == (-1, -1): last_position = overridePosition flag, frame = cap.read() if not flag: stream = self.fetchStream() cap = cv2.VideoCapture( stream.url ) flag, frame = cap.read() if not flag: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) timeValues = self.getTimeValues( gray[81:119, 526:830] ) if timeValues == tmpTimeValues: continue tmpTimeValues = timeValues date = self.getDateFromTime( timeValues ) if not 'day' in date or not 'hour' in date or not 'minute' in date or not 'second' in date: print 'error parsing date' continue timeStamp = self._timeZero + int(date['day']) * 24 * 60 * 60 + int(date['hour']) * 60 * 60 + int(date['minute']) * 60 + int(date['second']) # crop to gameboy area crop = gray[24:457, 24:504] # find red (if not found with enough confidence it's "undefined") currentDirection = self.getRedDirection( crop[182:230, 194:233] ) if currentDirection == 'undefined': #self.newEntry(timeStamp, date, last_position) continue # check if there is currently an event open events = self.detectEvents( crop ) if len(events) > 0 and not last_position == (-1, -1): #self.newEntry(timeStamp, date, last_position) self._eventList.append(events[0]) continue # detect position on map # scale to world-map ratio # 480px -> 160px crop = cv2.resize(crop, (160, 144)) # crop the worldmap image to a reasonable size, so we do not have to search so excessively # we can only do this if we have a starting position validationImage = self._worldmap left_corner = (0, 0) #cv2.imshow('crop', crop) #cv2.imshow('img', validationImage) #cv2.waitKey(0) if not last_position == (-1, -1): size = (500, 500) left_corner = (last_position[0] - size[0] / 2, last_position[1] - size[1] / 2) validationImage = self._worldmap[left_corner[1]:left_corner[1] + size[1], left_corner[0]:left_corner[0] + size[0]] #cv2.imshow('crop', crop) #cv2.imshow('img', validationImage) #cv2.waitKey(0) # this should generally not happen, but if it does, we do not know where we are # so we're defaulting to the whole worldmap # TODO: THIS SHOULD BE REPLACED WITH -> DEFAULTING TO INDOOR MAPS! if validationImage.shape < crop.shape: validationImage = self._worldmap left_corner = (0, 0) res = cv2.matchTemplate(validationImage, crop, cv2.TM_CCOEFF_NORMED) w, h = crop.shape[::-1] min_val, max_val, min_loc, max_loc = cv2.minMaxLoc( res ) # if we don't find something we're confident in, use the last position #if max_val < 0.5 and not last_position == (-1, -1): # self.newEntry(timeStamp, date, last_position) # continue # retry until we find a good first match if max_val < 0.8: validationImage = self._worldmap left_corner = (0, 0) res = cv2.matchTemplate(validationImage, crop, cv2.TM_CCOEFF_NORMED) w, h = crop.shape[::-1] min_val, max_val, min_loc, max_loc = cv2.minMaxLoc( res ) print max_val if max_val < 0.7: print 'hit low' continue top_left = max_loc top_left = (top_left[0] + left_corner[0], top_left[1] + left_corner[1]) center = (top_left[0] + w / 2, top_left[1] + h / 2) bottom_right = (top_left[0] + w, top_left[1] + h) last_position = center self.newEntry(timeStamp, date, last_position) if len(self._timeList) > 20: self._timeList = [] def getTimeValues( self, timeCrop ): timeValues = [] for key in self._templatesTime: template = self._templatesTime[key] w, h = template.shape[::-1] res = cv2.matchTemplate(timeCrop, template, cv2.TM_CCOEFF_NORMED) threshold = 0.9 loc = numpy.where( res >= threshold ) for pt in zip(*loc[::-1]): timeValues.append((pt[0], pt[1], key)) timeValues.sort() return timeValues def getDateFromTime( self, timeValues ): date = {} tmp = '' for timeValue in timeValues: key = timeValue[2] if key == 'd': date['day'] = tmp.zfill(2) tmp = '' elif key == 'h': date['hour'] = tmp.zfill(2) tmp = '' elif key == 'm': date['minute'] = tmp.zfill(2) tmp = '' elif key == 's': date['second'] = tmp.zfill(2) tmp = '' else: tmp = '{}{}'.format(tmp, key) return date def getRedDirection( self, redCrop ): currentDirection = 'undefined' redCrop = cv2.resize(redCrop, (10, 10)) for direction in self._templatesRed: template = self._templatesRed[direction] template = cv2.resize(template, (10, 10)) res = cv2.matchTemplate(redCrop, template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc( res ) if max_val > 0.55: currentDirection = direction break return currentDirection def detectEvents( self, crop ): eventValues = [] detectionAreas = {} detectionAreas['moonstone'] = crop.copy() # moonstone detectionAreas['dialogue'] = crop[293:435, 0:480] # dialogue detectionAreas['optionsMenu'] = crop[3:388, 240:480] # optionsMenu detectionAreas['naming'] = crop[98:360, 0:480] # naming for key in self._templatesEvent: template = self._templatesEvent[key] area = detectionAreas[key] w, h = template.shape[::-1] if area.shape < template.shape: break res = cv2.matchTemplate(area, template, cv2.TM_CCOEFF_NORMED) threshold = 0.95 loc = numpy.where( res >= threshold ) for pt in zip(*loc[::-1]): _tuple = (pt[0], pt[1], key) if not _tuple in eventValues: eventValues.append(_tuple) # currently there can only be one event at any given timespace if len(eventValues) > 0: break return eventValues def newEntry( self, timeStamp, date, position ): _tuple = (timeStamp, date, position) # we are in a room without outsideworld reference # this could only happen, if we start recording inside a building right now if position == (-1, -1): print 'WHERE ARE WE?\r' return if not _tuple in self._timeList: self._timeList.append(_tuple) print '{}\t{},{}\r'.format(str(timeStamp), position[0], position[1]), with open('positionData.csv', 'a') as entryFile: line = '{};{};{};{};{};{};{}\n'.format(timeStamp, \ date['day'], date['hour'], date['minute'], date['second'], \ position[0], position[1]) entryFile.write(line) with open( 'www/currentPosition', 'w' ) as _file: _file.write('{} {}'.format(position[0], position[1])) with open( 'www/currentTime', 'w' ) as _file: _file.write('{} {} {} {}'.format(date['day'], date['hour'], date['minute'], date['second']))
Test Livestreamer Script for enigma2 Test commands: cd /usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV python testme.py """ import sys sys.path.append('/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV') import os import requests from livestreamer import Livestreamer url = 'http://www.dailymotion.com/video/xqjey2' livestreamer = Livestreamer() livestreamer.set_loglevel('debug') channel = livestreamer.resolve_url(url) streams = channel.get_streams() print 'Streams:', streams.keys() stream = streams['best'] print stream fd = stream.open() while True: data = fd.read(1024) if len(data) == 0: break else: print 'Got Data! Livestreamer Works!' break if hasattr(fd, 'close'): fd.close()
class TestPluginStream(unittest.TestCase): def setUp(self): self.session = Livestreamer() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def _test_akamaihd(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, AkamaiHDStream)) self.assertEqual(stream.url, url) def _test_hls(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) def _test_rtmp(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, RTMPStream)) self.assertEqual(stream.params["rtmp"], url) self.assertDictHas(params, stream.params) def _test_http(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HTTPStream)) self.assertEqual(stream.url, url) self.assertDictHas(params, stream.args) def test_plugin(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) self._test_rtmp("rtmp://hostname.se/stream live=1 num=47", "rtmp://hostname.se/stream", dict(live=True, num=47)) self._test_rtmp( "rtmp://hostname.se/stream live=1 qarg='a \\'string' noq=test", "rtmp://hostname.se/stream", dict(live=True, qarg='a \'string', noq="test")) self._test_hls("hls://https://hostname.se/playlist.m3u8", "https://hostname.se/playlist.m3u8") self._test_hls("hls://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se/stream") self._test_akamaihd("akamaihd://hostname.se/stream", "http://hostname.se/stream") self._test_http( "httpstream://http://hostname.se/auth.php auth=('test','test2')", "http://hostname.se/auth.php", dict(auth=("test", "test2"))) self._test_http( "httpstream://hostname.se/auth.php auth=('test','test2')", "http://hostname.se/auth.php", dict(auth=("test", "test2"))) self._test_http( "httpstream://https://hostname.se/auth.php verify=False params={'key': 'a value'}", "https://hostname.se/auth.php?key=a+value", dict(verify=False, params=dict(key='a value')))
class Main: def __init__(self): self.gchoice = -1 self.cchoice = -1 self.exit_now = False self.state = 'none' self.keybingings = { ord('q'): self.quit, ord('f'): self.get_favorites, ord('s'): self.get_fav_games, ord('g'): self.get_games, ord('n'): self.get_next, ord('r'): self.refresh, ord('p'): self.get_previous } self.games = [] self.favs = [] self.channels = [] self.twitch = Twitch(config.get('settings', 'twitchapiurl'), config.get('settings', 'channel'), config.get('settings', 'game')) self.livestreamer = Livestreamer() try: self.run() except Exception as e: print e.message def run(self): while True: self.display_message() if self.exit_now: return def quit(self, c): self.exit_now = True def display_message(self): if self.state == 'none': clear_screen() self.handle_user_input( 'Escoge una opcion : Favoritos(F), Juegos(G), Salir(Q)') if self.state == 'favs': clear_screen() print 'Mostrando transmisiones favoritas en linea :' print '-' * 40 if (len(self.favs) > 0): self.show_content(self.favs) self.handle_user_input( 'Escoge un canal por numero (r para refrescar, g para enlistar juegos y q para salir', range(len(self.favs) + 1)) clear_screen() else: self.handle_user_input( 'No hay canales favoritos en linea (r para refrescar, g para enlistar juegos y q para salir', range(len(self.favs) + 1)) clear_screen() if self.state == 'games': clear_screen() print 'Mostrando %d juegos destacados:' % config.getint( 'settings', 'game') print '-' * 40 if (len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input( 'Escoge un juego por numero (r para refrescar, f para revisar tus canales favoritos y q para salir', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'favgames': clear_screen() print 'Mostrando juegos favoritos:' print '-' * 40 if (len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input( 'Escoge un juego por numero (r para refrescar, f para revisar tus canales favoritos y q para salir', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'channels': clear_screen() print 'Mostrando %d canales destacados para %s:' % (config.getint( 'settings', 'channel'), self.games[self.gchoice - 1]) print '-' * 40 self.get_channels(self.gchoice) if (len(self.channels) > 0): self.show_content(self.channels) self.cchoice = self.handle_user_input( 'Escoge un canal por numero (r para refrescar, f para revisar tus canales favoritos, g para enlistar juegos y q para salir', range(len(self.channels) + 1)) if self.cchoice != -1: self.play_stream(self.channels[self.cchoice - 1]) self.state = 'channels' clear_screen() def play_stream(self, channel): clear_screen() try: plugin = self.livestreamer.resolve_url( ("twitch.tv/{0}").format(channel)) except Exception as e: print e.message try: streams = plugin.get_streams() except PluginError as err: exit("Plugin error: {0}".format(err)) player = config.get('settings', 'player') quality = config.get('settings', 'quality') if quality not in streams: quality = "best" print "No se puede abrirla transmision con la calidad solicitada ({0}), abriendo la de mejor calidad".format( config.get('settings', 'quality')) channel = transform_spaces(channel) if os.name == 'nt': #os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) os.system('livestreamer -p "%s" twitch.tv/%s %s' % (player, channel, quality)) else: #os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) os.system('livestreamer -np "%s" twitch.tv/%s %s' % (player, channel, quality)) def show_content(self, content): for i in range(len(content)): if i < 9: print '', if i < 99: print '', print '%d %s' % (i + 1, content[i]) def handle_user_input(self, message, valid=None): self.state = 'none' validinput = False while not validinput: input = raw_input('%s\n ' % message) input = input.strip().lower() if input.isdigit(): input = int(input) if input in valid: validinput = True return input elif len(input) == 1: c = ord(input) f = self.keybingings.get(c, None) if f: f(c) validinput = True return -1 def get_favorites(self, c): self.state = 'favs' del self.favs[:] try: response = self.twitch.get_favorites_streams_status( config.get('settings', 'favorites')) receivedcount = len(response['streams']) for i in range(receivedcount): self.favs.append('%s Reproduciendo: %s' % (response['streams'][i]['channel']['name'], response['streams'][i]['game'])) except Exception as e: print 'Error obteniendo transmisiones favoritas!\n' print e.message return 0 def get_games(self, c): self.state = 'games' del self.games[:] try: response = self.twitch.get_game_list() receivedcount = len(response['top']) for i in range(receivedcount): self.games.append(response['top'][i]['game']['name']) except Exception as e: print 'Error obteniendo juegos !\n' print e.message return 0 def get_fav_games(self, c): self.state = 'favgames' del self.games[:] favgames = config.get('settings', 'favgames') if len(favgames) > 0: self.games.extend(favgames.split(', ')) def get_channels(self, choice): self.state = 'channels' del self.channels[:] try: response = self.twitch.get_channel_for_game( transform_spaces(self.games[self.gchoice - 1])) receivedcount = len(response['streams']) for i in range(receivedcount): self.channels.append( '%s (%s)' % (response['streams'][i]['channel']['name'], response['streams'][i]['viewers'])) except Exception as e: print 'Error obteniendo canales !\n' print e.message return 0 def refresh(self, c): print 'tmp' def get_next(self, c): print 'tmp' def get_previous(self, c): print 'tmp'
add, delete = previous[j]+1, current[j-1]+1 change = previous[j-1] if a[j-1] != b[i-1]: change = change + 1 current[j] = min(add, delete, change) return current[n] start_time = time.time() conn = pg8000.connect(user='******', password='******', database='twitchplayspokemonbot') # change to a stream that is actually online livestreamer = Livestreamer() plugin = livestreamer.resolve_url("http://www.twitch.tv/twitchplayspokemon") streams = plugin.get_streams() stream = streams['high'] # download enough data to make sure the first frame is there fd = stream.open() data = '' while len(data) < 3e5: data += fd.read(10245) time.sleep(0.1) fd.close() fname = 'C:\\Users\\derp\\workspace\\TPPBot\\images\\stream.bin' fileHandle = open(fname, 'wb') fileHandle.write(data) fileHandle.close()
from livestreamer import Livestreamer import cv2 import subprocess as sp FFMPEG_BIN = 'C:/ffmpeg/bin/ffmpeg.exe' import numpy livestreamer = Livestreamer() plugin = livestreamer.resolve_url("http://www.ustream.tv/channel/jamthehype") streams = plugin.get_streams() print streams stream = streams.get("best") cv2.namedWindow("GoPro",cv2.CV_WINDOW_AUTOSIZE) VIDEO_URL = stream.url print VIDEO_URL pipe = sp.Popen([FFMPEG_BIN, "-i", VIDEO_URL, "-loglevel", "quiet", # no text output "-an", # disable audio "-f", "image2pipe", "-pix_fmt", "bgr24", "-vcodec", "rawvideo", "-"], stdin = sp.PIPE, stdout = sp.PIPE) while True: raw_image = pipe.stdout.read(426*240*3) # read 432*240*3 bytes (= 1 frame) image = numpy.fromstring(raw_image, dtype='uint8').reshape((240,426,3)) cv2.imshow("GoPro",image) if cv2.waitKey(5) == 27: break cv2.destroyAllWindows()
print help_message args, video_src = getopt.getopt(sys.argv[1:], '', ['cascade=', 'nested-cascade=']) try: video_src = video_src[0] except: video_src = 0 args = dict(args) cascade_fn = args.get('--cascade', "haarcascade_frontalface_alt.xml") nested_fn = args.get('--nested-cascade', "haarcascade_eye.xml") cascade = cv2.CascadeClassifier(cascade_fn) nested = cv2.CascadeClassifier(nested_fn) FFMPEG_BIN = 'C:/ffmpeg/bin/ffmpeg.exe' livestreamer = Livestreamer() plugin = livestreamer.resolve_url("http://www.ustream.tv/channel/personal-cam1") streams = plugin.get_streams() stream = streams.get("best") VIDEO_URL = stream.url print VIDEO_URL pipe = sp.Popen([FFMPEG_BIN, "-i", VIDEO_URL, "-loglevel", "quiet", # no text output "-an", # disable audio "-f", "image2pipe", "-pix_fmt", "bgr24", "-vcodec", "rawvideo", "-"], stdin = sp.PIPE, stdout = sp.PIPE) while True: raw_image = pipe.stdout.read(426*240*3) # read 432*240*3 bytes (= 1 frame) img = np.fromstring(raw_image, dtype='uint8').reshape((240,426,3))
class StreamList(object): def __init__(self, filename, rc_module): """ Init and try to load a stream list, nothing about curses yet """ self.db_was_read = False # Open the storage (create it if necessary try: f = shelve.open(filename, 'c') except Exception: raise ShelveError( 'Database could not be opened, another livestreamer-curses instance might be already running. ' 'Please note that a database created with Python 2.x cannot be used with Python 3.x and vice versa.' ) self.max_id = 0 # Sort streams by view count try: self.streams = sorted(f['streams'], key=lambda s:s['seen'], reverse=True) for s in self.streams: # Max id, needed when adding a new stream self.max_id = max(self.max_id, s['id']) s['online'] = 2 except: self.streams = [] self.db_was_read = True self.filtered_streams = list(self.streams) self.filter = '' self.all_streams_offline = None self.show_offline_streams = False self.rc_module = rc_module if 'LIVESTREAMER_COMMANDS' in dir(self.rc_module): self.cmd_list = list(map(shlex.split, self.rc_module.LIVESTREAMER_COMMANDS)) else: self.cmd_list = [['livestreamer']] self.cmd_index = 0 self.cmd = self.cmd_list[self.cmd_index] if 'DEFAULT_RESOLUTION' in dir(self.rc_module): self.default_res = self.rc_module.DEFAULT_RESOLUTION else: self.default_res = DEFAULT_RESOLUTION_HARD self.store = f self.store.sync() self.no_streams = self.streams == [] self.no_stream_shown = self.no_streams self.q = ProcessList(StreamPlayer().play) self.livestreamer = Livestreamer() def __del__(self): """ Stop playing streams and sync storage """ try: self.q.terminate() if self.db_was_read: self.store['cmd'] = self.cmd self.store['streams'] = self.streams self.store.close() except: pass def __call__(self, s): # Terminal initialization self.init(s) # Main event loop self.run() def init(self, s): """ Initialize the text interface """ # Hide cursor curses.curs_set(0) self.s = s self.s.keypad(1) self.set_screen_size() self.pads = {} self.offsets = {} self.init_help() self.init_streams_pad() self.current_pad = 'streams' self.set_title(TITLE_STRING) self.got_g = False signal.signal(28, self.resize) if 'CHECK_ONLINE_ON_START' in dir(self.rc_module) and self.rc_module.CHECK_ONLINE_ON_START: self.check_online_streams() self.set_status('Ready') def getheightwidth(self): """ getwidth() -> (int, int) Return the height and width of the console in characters https://groups.google.com/forum/#!msg/comp.lang.python/CpUszNNXUQM/QADpl11Z-nAJ""" try: return int(os.environ["LINES"]), int(os.environ["COLUMNS"]) except KeyError: height, width = struct.unpack( "hhhh", ioctl(0, termios.TIOCGWINSZ ,"\000"*8))[0:2] if not height: return 25, 80 return height, width def resize(self, signum, obj): """ handler for SIGWINCH """ self.s.clear() stream_cursor = self.pads['streams'].getyx()[0] for pad in self.pads.values(): pad.clear() self.s.refresh() self.set_screen_size() self.set_title(TITLE_STRING) self.init_help() self.init_streams_pad() self.move(stream_cursor, absolute=True, pad_name='streams', refresh=False) self.s.refresh() self.show() def run(self): """ Main event loop """ # Show stream list self.show_streams() while True: self.s.refresh() # See if any stream has ended self.check_stopped_streams() # Wait on stdin or on the streams output souts = self.q.get_stdouts() souts.append(sys.stdin) try: (r, w, x) = select.select(souts, [], [], 1) except select.error: continue for fd in r: if fd != sys.stdin: # Set the new status line only if non-empty msg = fd.readline() if msg: self.set_status(msg[:-1]) else: # Main event loop c = self.pads[self.current_pad].getch() if c == curses.KEY_UP or c == ord('k'): self.move(-1) elif c == curses.KEY_DOWN or c == ord('j'): self.move(1) elif c == ord('f'): if self.current_pad == 'streams': self.filter_streams() elif c == ord('F'): if self.current_pad == 'streams': self.clear_filter() elif c == ord('g'): if self.got_g: self.move(0, absolute=True) self.got_g = False continue self.got_g = True elif c == ord('G'): self.move(len(self.filtered_streams)-1, absolute=True) elif c == ord('q'): if self.current_pad == 'streams': self.q.terminate() return else: self.show_streams() elif c == 27: # ESC if self.current_pad != 'streams': self.show_streams() if self.current_pad == 'help': continue elif c == 10: self.play_stream() elif c == ord('s'): self.stop_stream() elif c == ord('c'): self.reset_stream() elif c == ord('n'): self.edit_stream('name') elif c == ord('r'): self.edit_stream('res') elif c == ord('u'): self.edit_stream('url') elif c == ord('l'): self.show_commandline() elif c == ord('L'): self.shift_commandline() elif c == ord('a'): self.prompt_new_stream() elif c == ord('d'): self.delete_stream() elif c == ord('o'): self.show_offline_streams ^= True self.refilter_streams() elif c == ord('O'): self.check_online_streams() elif c == ord('h') or c == ord('?'): self.show_help() def set_screen_size(self): """ Setup screen size and padding We have need 2 free lines at the top and 2 free lines at the bottom """ height, width = self.getheightwidth() curses.resizeterm(height, width) self.pad_x = 0 self.max_y, self.max_x = (height-1, width-1) self.pad_h = height-3 self.pad_w = width-2*self.pad_x def overwrite_line(self, msg, attr=curses.A_NORMAL): self.s.clrtoeol() self.s.addstr(msg, attr) self.s.chgat(attr) def set_title(self, msg): """ Set first header line text """ self.s.move(0, 0) self.overwrite_line(msg, curses.A_REVERSE) def set_header(self, msg): """ Set second head line text """ self.s.move(1, 0) self.overwrite_line(msg, attr=curses.A_NORMAL) def set_footer(self, msg, reverse=True): """ Set first footer line text """ self.s.move(self.max_y-1, 0) if reverse: self.overwrite_line(msg, attr=curses.A_REVERSE) else: self.overwrite_line(msg, attr=curses.A_NORMAL) def clear_footer(self): self.s.move(self.max_y-1, 0) self.overwrite_line('') def init_help(self): help_pad_length = 27 # there should be a neater way to do this h = curses.newpad(help_pad_length, self.pad_w) h.keypad(1) h.addstr( 0, 0, 'STREAM MANAGEMENT', curses.A_BOLD) h.addstr( 2, 0, ' Enter : start stream') h.addstr( 3, 0, ' s : stop stream') h.addstr( 4, 0, ' r : change stream resolution') h.addstr( 5, 0, ' n : change stream name') h.addstr( 6, 0, ' u : change stream URL') h.addstr( 7, 0, ' c : reset stream view count') h.addstr( 8, 0, ' a : add stream') h.addstr( 9, 0, ' d : delete stream') h.addstr(11, 0, ' l : show command line') h.addstr(12, 0, ' L : cycle command line') h.addstr(15, 0, 'NAVIGATION', curses.A_BOLD) h.addstr(17, 0, ' j/up : up one line') h.addstr(18, 0, ' k/down: down one line') h.addstr(19, 0, ' f : filter streams') h.addstr(20, 0, ' F : clear filter') h.addstr(21, 0, ' o : toggle offline streams') h.addstr(22, 0, ' O : check for online streams') h.addstr(23, 0, ' gg : go to top') h.addstr(24, 0, ' G : go to bottom') h.addstr(25, 0, ' h/? : show this help') h.addstr(26, 0, ' q : quit') self.pads['help'] = h self.offsets['help'] = 0 def show(self): funcs = { 'streams' : self.show_streams, 'help' : self.show_help } funcs[self.current_pad]() def show_help(self): """ Redraw Help screen and wait for any input to leave """ self.s.move(1,0) self.s.clrtobot() self.set_header('Help'.center(self.pad_w)) self.set_footer(' ESC or \'q\' to return to main menu') self.s.refresh() self.current_pad = 'help' self.refresh_current_pad() def init_streams_pad(self, start_row=0): """ Create a curses pad and populate it with a line by stream """ y = 0 pad = curses.newpad(max(1,len(self.filtered_streams)), self.pad_w) pad.keypad(1) for s in self.filtered_streams: pad.addstr(y, 0, self.format_stream_line(s)) y+=1 self.offsets['streams'] = 0 pad.move(start_row, 0) if not self.no_stream_shown: pad.chgat(curses.A_REVERSE) self.pads['streams'] = pad def show_streams(self): self.s.move(1,0) self.s.clrtobot() self.current_pad = 'streams' if self.no_stream_shown: self.hide_streams_pad() if self.no_streams: self.s.addstr(5, 5, 'It seems you don\'t have any stream yet') self.s.addstr(6, 5, 'Hit \'a\' to add a new one') self.s.addstr(8, 5, 'Hit \'?\' for help') elif self.all_streams_offline and not self.show_offline_streams: self.s.addstr(5, 5, 'All streams are currently offline') self.s.addstr(6, 5, 'Hit \'o\' to show offline streams') self.s.addstr(7, 5, 'Hit \'O\' to refresh') self.s.addstr(9, 5, 'Hit \'?\' for help') else: self.s.addstr(5, 5, 'No stream matches your filter') self.s.addstr(6, 5, 'Hit \'f\' to change filter') self.s.addstr(7, 5, 'Hit \'F\' to clear') self.s.addstr(8, 5, 'Hit \'o\' to show offline streams') self.s.addstr(10, 5, 'Hit \'?\' for help') else: idf = 'ID'.center(ID_FIELD_WIDTH) name = 'Name'.center(NAME_FIELD_WIDTH) res = 'Resolution'.center(RES_FIELD_WIDTH) views = 'Views'.center(VIEWS_FIELD_WIDTH) self.set_header('{0} {1} {2} {3} Status'.format(idf, name, res, views)) self.redraw_stream_footer() self.redraw_status() self.s.refresh() if not self.no_stream_shown: self.refresh_current_pad() def hide_streams_pad(self): pad = self.pads.get('streams') if pad: pad.refresh(0, 0, 2, 0, 2, 0) def refresh_current_pad(self): pad = self.pads[self.current_pad] pad.refresh(self.offsets[self.current_pad], 0, 2, self.pad_x, self.pad_h, self.pad_w) def move(self, direction, absolute=False, pad_name=None, refresh=True): """ Scroll the current pad direction : (int) move by one in the given direction -1 is up, 1 is down. If absolute is True, go to position direction. Behaviour is affected by cursor_line and scroll_only below absolute : (bool) """ # pad in this lists have the current line highlighted cursor_line = [ 'streams' ] # pads in this list will be moved screen-wise as opposed to line-wise # if absolute is set, will go all the way top or all the way down depending # on direction scroll_only = [ 'help' ] if not pad_name: pad_name = self.current_pad pad = self.pads[pad_name] if pad_name == 'streams' and self.no_streams: return (row, col) = pad.getyx() new_row = row offset = self.offsets[pad_name] new_offset = offset if pad_name in scroll_only: if absolute: if direction > 0: new_offset = pad.getmaxyx()[0] - self.pad_h + 1 else: new_offset = 0 else: if direction > 0: new_offset = min(pad.getmaxyx()[0] - self.pad_h + 1, offset + self.pad_h) elif offset > 0: new_offset = max(0, offset - self.pad_h) else: if absolute and direction >= 0 and direction < pad.getmaxyx()[0]: if direction < offset: new_offset = direction elif direction > offset + self.pad_h - 2: new_offset = direction - self.pad_h + 2 new_row = direction else: if direction == -1 and row > 0: if row == offset: new_offset -= 1 new_row = row-1 elif direction == 1 and row < len(self.filtered_streams)-1: if row == offset + self.pad_h - 2: new_offset += 1 new_row = row+1 if pad_name in cursor_line: pad.move(row, 0) pad.chgat(curses.A_NORMAL) self.offsets[pad_name] = new_offset pad.move(new_row, 0) if pad_name in cursor_line: pad.chgat(curses.A_REVERSE) if pad_name == 'streams': self.redraw_stream_footer() if refresh: self.refresh_current_pad() def format_stream_line(self, stream): idf = '{0} '.format(stream['id']).rjust(ID_FIELD_WIDTH) name = ' {0}'.format(stream['name'][:NAME_FIELD_WIDTH-2]).ljust(NAME_FIELD_WIDTH) res = ' {0}'.format(stream['res'][:RES_FIELD_WIDTH-2]).ljust(RES_FIELD_WIDTH) views = '{0} '.format(stream['seen']).rjust(VIEWS_FIELD_WIDTH) p = self.q.get_process(stream['id']) != None if p: indicator = '[>>>]' else: indicator = INDICATORS[stream['online']] return '{0} {1} {2} {3} {4}'.format(idf, name, res, views, indicator) def redraw_current_line(self): """ Redraw the highlighted line """ if self.no_streams: return row = self.pads[self.current_pad].getyx()[0] s = self.filtered_streams[row] pad = self.pads['streams'] pad.move(row, 0) pad.clrtoeol() pad.addstr(row, 0, self.format_stream_line(s), curses.A_REVERSE) pad.chgat(curses.A_REVERSE) pad.move(row, 0) self.refresh_current_pad() def set_status(self, status): self.status = status self.redraw_status() def redraw_status(self): self.s.move(self.max_y, 0) self.overwrite_line(self.status[:self.max_x], curses.A_NORMAL) self.s.refresh() def redraw_stream_footer(self): if not self.no_stream_shown: row = self.pads[self.current_pad].getyx()[0] s = self.filtered_streams[row] self.set_footer('{0}/{1} {2} {3}'.format(row+1, len(self.filtered_streams), s['url'], s['res'])) self.s.refresh() def check_stopped_streams(self): finished = self.q.get_finished() for f in finished: for s in self.streams: try: i = self.filtered_streams.index(s) except ValueError: continue if f == s['id']: self.set_footer('Stream {0} has stopped'.format(s['name'])) if i == self.pads[self.current_pad].getyx()[0]: attr = curses.A_REVERSE else: attr = curses.A_NORMAL self.pads['streams'].addstr(i, PLAYING_FIELD_OFFSET, INDICATORS[s['online']], attr) self.refresh_current_pad() def _check_stream(self, url): try: plugin = self.livestreamer.resolve_url(url) avail_streams = plugin.get_streams() if avail_streams: return 1 return 0 except: return 3 def check_online_streams(self): self.all_streams_offline = True self.set_status(' Checking online streams...') done_queue = queue.Queue() def check_stream_managed(args): url, queue = args status = self._check_stream(url) done_queue.put(url) return status pool = Pool(CHECK_ONLINE_THREADS) args = [(s['url'], done_queue) for s in self.streams] statuses = pool.map_async(check_stream_managed, args) n_streams = len(self.streams) while not statuses.ready(): sleep(0.1) self.set_status(' Checked {0}/{1} streams...'.format(done_queue.qsize(), n_streams)) self.s.refresh() statuses = statuses.get() for i, s in enumerate(self.streams): s['online'] = statuses[i] if s['online']: self.all_streams_offline = False self.refilter_streams() def prompt_input(self, prompt=''): self.s.move(self.max_y, 0) self.s.clrtoeol() self.s.addstr(prompt) curses.curs_set(1) curses.echo() r = self.s.getstr().decode() curses.noecho() curses.curs_set(0) self.s.move(self.max_y, 0) self.s.clrtoeol() return r def prompt_confirmation(self, prompt='', def_yes=False): self.s.move(self.max_y-1, 0) self.s.clrtoeol() if def_yes: hint = '[y]/n' else: hint = 'y/[n]' self.s.addstr('{0} {1} '.format(prompt, hint)) curses.curs_set(1) curses.echo() r = self.s.getch() curses.noecho() curses.curs_set(0) self.s.move(self.max_y-1, 0) self.s.clrtoeol() if r == ord('y'): return True elif r == ord('n'): return False else: return def_yes def sync_store(self): self.store['streams'] = self.streams self.store.sync() def bump_stream(self, stream, throttle=False): t = int(time()) # only bump if stream was last started some time ago if throttle and t - stream['last_seen'] < 60*1: return stream['seen'] += 1 stream['last_seen'] = t self.sync_store() def find_stream(self, sel, key='id'): for s in self.streams: if s[key] == sel: return s return None def clear_filter(self): self.filter = '' self.refilter_streams() def filter_streams(self): self.filter = self.prompt_input('Filter: ').lower() self.refilter_streams() def refilter_streams(self, quiet=False): self.filtered_streams = [] for s in self.streams: if ((self.show_offline_streams or s['online'] in [1,2]) and (self.filter in s['name'].lower() or self.filter in s['url'].lower())): self.filtered_streams.append(s) self.filtered_streams.sort(key=lambda s:s['seen'], reverse=True) self.no_stream_shown = len(self.filtered_streams) == 0 if not quiet: self.status = ' Filter: {0} ({1}/{2} matches, {3} showing offline streams)'.format( self.filter or '<empty>', len(self.filtered_streams), len(self.streams), '' if self.show_offline_streams else 'NOT') self.init_streams_pad() self.redraw_stream_footer() self.show_streams() self.redraw_status() def add_stream(self, name, url, res=None, bump=False): ex_stream = self.find_stream(url, key='url') if ex_stream: if bump: self.bump_stream(ex_stream) else: if bump: seen = 1 last_seen = int(time()) else: seen = last_seen = 0 if not self.streams: idf = 1 else: self.max_id += 1 idf = self.max_id s_res = res or self.default_res if type(s_res) == str: actual_res = s_res elif type(s_res) == dict: actual_res = DEFAULT_RESOLUTION_HARD for k,v in s_res.items(): if k in url: actual_res = v break elif callable(s_res): actual_res = s_res(url) or DEFAULT_RESOLUTION_HARD else: actual_res = DEFAULT_RESOLUTION_HARD self.set_status(' Checking if new stream is online...') self.s.refresh() online = self._check_stream(url) new_stream = { 'id' : idf, 'name' : name, 'seen' : seen, 'last_seen' : last_seen, 'res' : actual_res, 'url' : url, 'online' : online } self.streams.append(new_stream) self.no_streams = False self.refilter_streams() self.sync_store() def delete_stream(self): if self.no_streams: return pad = self.pads[self.current_pad] s = self.filtered_streams[pad.getyx()[0]] if not self.prompt_confirmation('Delete stream {0}?'.format(s['name'])): return self.filtered_streams.remove(s) self.streams.remove(s) pad.deleteln() self.sync_store() if not self.streams: self.no_streams = True if not self.filtered_streams: self.no_stream_shown = True if pad.getyx()[0] == len(self.filtered_streams) and not self.no_stream_shown: self.move(-1, refresh=False) pad.chgat(curses.A_REVERSE) self.redraw_current_line() self.show_streams() def reset_stream(self): if self.no_stream_shown: return pad = self.pads[self.current_pad] s = self.filtered_streams[pad.getyx()[0]] if not self.prompt_confirmation('Reset stream {0}?'.format(s['name'])): return s['seen'] = 0 s['last_seen'] = 0 self.redraw_current_line() self.sync_store() def edit_stream(self, attr): prompt_info = { 'name' : 'Name', 'url' : 'URL', 'res' : 'Resolution' } if self.no_streams: return pad = self.pads[self.current_pad] s = self.filtered_streams[pad.getyx()[0]] new_val = self.prompt_input('{0} (empty to cancel): '.format(prompt_info[attr])) if new_val != '': s[attr] = new_val self.redraw_current_line() self.redraw_status() self.redraw_stream_footer() def show_commandline(self): self.set_footer('{0}/{1} {2}'.format(self.cmd_index+1, len(self.cmd_list), ' '.join(self.cmd))) def shift_commandline(self): self.cmd_index += 1 if self.cmd_index == len(self.cmd_list): self.cmd_index = 0 self.cmd = self.cmd_list[self.cmd_index] self.show_commandline() def prompt_new_stream(self): url = self.prompt_input('New stream URL (empty to cancel): ') name = url.split('/')[-1] if name: self.add_stream(name, url) self.move(len(self.filtered_streams)-1, absolute=True, refresh=False) self.show_streams() def play_stream(self): if self.no_stream_shown: return pad = self.pads[self.current_pad] s = self.filtered_streams[pad.getyx()[0]] try: self.q.put(s['id'], s['url'], s['res'], self.cmd) self.bump_stream(s, throttle=True) self.redraw_current_line() self.refresh_current_pad() except Exception as e: if type(e) == QueueDuplicate: self.set_footer('This stream is already playing') elif type(e) == OSError: self.set_footer('/!\ Faulty command line: {0}'.format(e.strerror)) else: raise e def stop_stream(self): if self.no_stream_shown: return pad = self.pads[self.current_pad] s = self.filtered_streams[pad.getyx()[0]] p = self.q.terminate_process(s['id']) if p: self.redraw_current_line() self.redraw_stream_footer() self.redraw_status()
class TestPluginStream(unittest.TestCase): def setUp(self): self.session = Livestreamer() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def _test_akamaihd(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, AkamaiHDStream)) self.assertEqual(stream.url, url) def _test_hls(self, surl, url): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) def _test_rtmp(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, RTMPStream)) self.assertEqual(stream.params["rtmp"], url) self.assertDictHas(params, stream.params) def _test_http(self, surl, url, params): channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, HTTPStream)) self.assertEqual(stream.url, url) self.assertDictHas(params, stream.args) def test_plugin(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) self._test_rtmp("rtmp://hostname.se/stream live=1 num=47", "rtmp://hostname.se/stream", dict(live=True, num=47)) self._test_rtmp("rtmp://hostname.se/stream live=1 qarg='a \\'string' noq=test", "rtmp://hostname.se/stream", dict(live=True, qarg='a \'string', noq="test")) self._test_hls("hls://https://hostname.se/playlist.m3u8", "https://hostname.se/playlist.m3u8") self._test_hls("hls://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se/stream") self._test_akamaihd("akamaihd://hostname.se/stream", "http://hostname.se/stream") self._test_http("httpstream://http://hostname.se/auth.php auth=('test','test2')", "http://hostname.se/auth.php", dict(auth=("test", "test2"))) self._test_http("httpstream://hostname.se/auth.php auth=('test','test2')", "http://hostname.se/auth.php", dict(auth=("test", "test2"))) self._test_http("httpstream://https://hostname.se/auth.php verify=False params={'key': 'a value'}", "https://hostname.se/auth.php?key=a+value", dict(verify=False, params=dict(key='a value')))
class GreekStreamTVList(Screen): skin = '\n \t\t<screen name="GreekStreamTVList" position="center,center" size="800,400" title="GreekStreamTV List (Livestreamer) v3.2">\n\t\t\t<widget name="streamlist" position="0,0" size="800,360" backgroundColor="#000000" zPosition="10" scrollbarMode="showOnDemand" />\n\t\t\t<widget name="info" position="0,365" zPosition="2" size="800,35" font="Regular;22" foregroundColor="#ffffff" transparent="1" halign="center" valign="center" />\n\t\t</screen>\n ' def __init__(self, session, streamFile = None): self.session = session Screen.__init__(self, session) self['info'] = Label('...') self['actions'] = ActionMap(['OkCancelActions', 'ShortcutActions', 'WizardActions', 'ColorActions', 'SetupActions', 'NumberActions', 'MenuActions'], {'ok': self.keyOK, 'cancel': self.keyCancel, 'up': self.keyUp, 'down': self.keyDown, 'left': self.keyLeft, 'right': self.keyRight}, -1) self.streamBin = '/usr/bin/rtmpdump' self.streamPipe = '/tmp/greekstreamtv.avi' if not streamFile: self.streamFile = resolveFilename(SCOPE_PLUGINS, 'Extensions/GreekStreamTV/stream.xml') else: self.streamFile = streamFile self.lvstreamer = Livestreamer() self.streamList = [] self.makeStreamList() self.streamMenuList = MenuList([], enableWrapAround=True, content=eListboxPythonMultiContent) self.streamMenuList.l.setFont(0, gFont('Regular', 22)) self.streamMenuList.l.setFont(1, gFont('Regular', 18)) self.streamMenuList.l.setItemHeight(37) self['streamlist'] = self.streamMenuList self.streamMenuList.setList(map(streamListEntry, self.streamList)) self.onLayoutFinish.append(self.layoutFinished) self.beforeService = None self.currentService = None self.playerStoped = False self.keyLocked = False self.pd = None self.qsel = None return def layoutFinished(self): os.system('killall -9 rtmpdump') self.showName() def keyLeft(self): if self.keyLocked: return self['streamlist'].pageUp() self.showName() def keyRight(self): if self.keyLocked: return self['streamlist'].pageDown() self.showName() def keyUp(self): if self.keyLocked: return self['streamlist'].up() self.showName() def keyDown(self): if self.keyLocked: return self['streamlist'].down() self.showName() def keyCancel(self): self.LivestreamerStop() if '/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV' in path: path.remove('/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV') self.close() def showName(self): try: tmpName = self['streamlist'].getCurrent()[0][1].get('name') except: tmpName = '...' self['info'].setText(tmpName) def keyOK(self): print '[GreekStreamTVList::keyOK]' if self.keyLocked: return uriName = self['streamlist'].getCurrent()[0][1].get('name') self['info'].setText('Starting %s Please Wait...' % uriName) self.timer = eTimer() self.timer.callback.append(self.StartStream) self.timer.start(100, 1) def StartStream(self): self.timer.stop() self.keyLocked = True self.beforeService = None self.currentService = None self.playerStoped = False self.pd = None streamInfo = self['streamlist'].getCurrent()[0][1] uriInfo = streamInfo.get('uri') typeInfo = streamInfo.get('type').split(':') protocol = typeInfo[0] serviceType = typeInfo[1] bufferSize = typeInfo[2] url = uriInfo.get('URL') if protocol == 'rtmp': url += ' ' url += ' '.join([ '%s=%s' % (key, value) for key, value in uriInfo.items() if key != 'URL' ]) url = ' '.join(url.split()) print '[GreekStreamTVList::keyOK] URL is ', url, ' URI is ', uriInfo self.doStreamAction(url, serviceType, bufferSize) elif protocol in ('rtsp', 'http'): self.doStreamAction(url, serviceType, bufferSize) elif protocol == 'livestreamer': channel = None streams = None try: url += ' ' url += ' '.join([ '%s=%s' % (key, value) for key, value in uriInfo.items() if key != 'URL' ]) url = ' '.join(url.split()) print '[GreekStreamTVList::keyOK] URL is ', url, ' URI is ', uriInfo channel = self.lvstreamer.resolve_url(url) streams = channel.get_streams() print '[GreekStreamTVList::keyOK] Streams: ', streams.keys() print '[GreekStreamTVList::keyOK] Streams: ', streams.items() if len(streams) == 3 and 'best' in streams and 'worst' in streams: self.streamPreBuffer(streams['best']) elif len(streams) == 0: raise Exception('No Streams Found') else: self.qsel = self.session.openWithCallback(self.QualitySelClosed, SelectQuality, streams, self.streamPreBuffer) except Exception as err: print '[GreekStreamTVList::keyOK::Exception] Error: ', err tmpMessage = 'An Error Occured: ' + str(err)[:200] + '...' self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=20) else: print '[GreekStreamTVList::keyOK] Unknown Protocol: ', protocol tmpMessage = 'Unknown Protocol: ' + protocol self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_WARNING, timeout=20) return def QualitySelClosed(self, recursive): if self.qsel: self.qsel.close() self.qsel = None self.stopPlayer() return def streamPreBuffer(self, stream): fd = None try: fd = stream.open() prebuffer = fd.read(1049088) if len(prebuffer) == 0: raise Exception('No Data Received From Stream Server') start_new_thread(self.streamCopy, (fd, prebuffer)) sleep(1.5) self.doStreamAction(self.streamPipe) except Exception as err: if fd and hasattr(fd, 'close'): fd.close() print '[GreekStreamTVList::streamPreBuffer::Exception] Error: ', err tmpMessage = 'An Error Occured while buffering: ' + str(err)[:200] + '...' self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=20) return def streamCopy(self, fd, prebuffer): print '[GreekStreamTVList::streamCopy]' if os.access(self.streamPipe, os.F_OK): os.remove(self.streamPipe) os.mkfifo(self.streamPipe) self.pd = open(self.streamPipe, 'wb') try: self.pd.write(prebuffer) while self is not None and self.session is not None and not self.playerStoped: data = fd.read(8192) if len(data) == 0: break self.pd.write(data) print '[GreekStreamTVList:streamCopy] playerStoped' self.pd.close() if hasattr(fd, 'close'): fd.close() fd = None except Exception as err: print '[GreekStreamTVList::streamCopy] Exception: ', err finally: self.playerStoped = True if fd and hasattr(fd, 'close'): fd.close() return def LivestreamerStop(self): print '[GreekStreamTVList::LivestreamStop]' self['info'].setText('...') self.keyLocked = False self.playerStoped = True os.system('killall -9 rtmpdump') sleep(0.5) if self.pd: try: self.pd.close() except: sleep(0.5) try: self.pd.close() except: pass if self.qsel is not None: self.qsel.close(False) self.pd = None self.qsel = None return def doStreamAction(self, url = None, serviceType = 4097, bufferSize = None): if url is None: url = self.streamPipe self.streamPlayerTimer.stop() try: serviceType = int(serviceType) except: serviceType = 4097 try: bufferSize = int(bufferSize) except: bufferSize = None service = eServiceReference(serviceType, 0, url) streamInfo = self['streamlist'].getCurrent()[0][1] service.setName(str(streamInfo.get('name'))) uriInfo = streamInfo.get('uri') self.beforeService = self.session.nav.getCurrentlyPlayingServiceReference() self.currentService = self.session.openWithCallback(self.onStreamFinished, GreekStreamTVPlayer, service, stopPlayer=self.stopPlayer, chName=str(streamInfo.get('name')), chURL=str(uriInfo.get('URL')), chIcon=str(streamInfo.get('icon'))) return def stopPlayer(self, params = None): print '[GreekStreamTV::stopPlayer]' if params is None or isinstance(params, bool): self.playerStoped = True self.LivestreamerStop() return else: return def onStreamFinished(self): print '[GreekStreamTV::onStreamFinished]' self.LivestreamerStop() self.session.nav.playService(self.beforeService) print '[GreekStreamTV::onStreamFinished] player done!!' def makeStreamList(self): try: streamDB = StreamURIParser(self.streamFile).parseStreamList() except Exception as err: print '[GreekStreamTV::makeStreamList] Error: ', err streamDB = [] self.streamList = [ (x.get('name'), x) for x in streamDB ]
class TestSession(unittest.TestCase): PluginPath = os.path.join(os.path.dirname(__file__), "plugins") def setUp(self): self.session = Livestreamer() self.session.load_plugins(self.PluginPath) def test_exceptions(self): try: self.session.resolve_url("invalid url") self.assertTrue(False) except NoPluginError: self.assertTrue(True) def test_load_plugins(self): plugins = self.session.get_plugins() self.assertTrue(plugins["testplugin"]) def test_builtin_plugins(self): plugins = self.session.get_plugins() self.assertTrue("twitch" in plugins) def test_resolve_url(self): plugins = self.session.get_plugins() channel = self.session.resolve_url("http://test.se/channel") self.assertTrue(isinstance(channel, Plugin)) self.assertTrue(isinstance(channel, plugins["testplugin"])) def test_options(self): self.session.set_option("test_option", "option") self.assertEqual(self.session.get_option("test_option"), "option") self.assertEqual(self.session.get_option("non_existing"), None) self.assertEqual(self.session.get_plugin_option("testplugin", "a_option"), "default") self.session.set_plugin_option("testplugin", "another_option", "test") self.assertEqual(self.session.get_plugin_option("testplugin", "another_option"), "test") self.assertEqual(self.session.get_plugin_option("non_existing", "non_existing"), None) self.assertEqual(self.session.get_plugin_option("testplugin", "non_existing"), None) def test_plugin(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams() self.assertTrue("best" in streams) self.assertTrue("worst" in streams) self.assertTrue(streams["best"] is streams["1080p"]) self.assertTrue(streams["worst"] is streams["350k"]) self.assertTrue(isinstance(streams["rtmp"], RTMPStream)) self.assertTrue(isinstance(streams["http"], HTTPStream)) self.assertTrue(isinstance(streams["hls"], HLSStream)) self.assertTrue(isinstance(streams["akamaihd"], AkamaiHDStream)) def test_plugin_stream_types(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams(stream_types=["http", "rtmp"]) self.assertTrue(isinstance(streams["480p"], HTTPStream)) self.assertTrue(isinstance(streams["480p_rtmp"], RTMPStream)) streams = channel.get_streams(stream_types=["rtmp", "http"]) self.assertTrue(isinstance(streams["480p"], RTMPStream)) self.assertTrue(isinstance(streams["480p_http"], HTTPStream)) def test_plugin_stream_sorted_excludes(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams(sorting_excludes=["1080p", "3000k"]) self.assertTrue("best" in streams) self.assertTrue("worst" in streams) self.assertTrue(streams["best"] is streams["1500k"]) streams = channel.get_streams(sorting_excludes=[">=1080p", ">1500k"]) self.assertTrue(streams["best"] is streams["1500k"]) streams = channel.get_streams(sorting_excludes=lambda q: not q.endswith("p")) self.assertTrue(streams["best"] is streams["3000k"]) def test_plugin_support(self): channel = self.session.resolve_url("http://test.se/channel") streams = channel.get_streams() self.assertTrue("support" in streams) self.assertTrue(isinstance(streams["support"], HTTPStream))
class GreekStreamTVList(Screen): skin = """ <screen name="GreekStreamTVList" position="center,center" size="560,430" title="GreekStreamTV list"> <ePixmap pixmap="buttons/red.png" position="0,0" size="140,40" alphatest="on"/> <ePixmap pixmap="buttons/green.png" position="140,0" size="140,40" alphatest="on"/> <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1"/> <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1"/> <widget name="streamlist" position="10,50" size="540,320" zPosition="10" scrollbarMode="showOnDemand"/> <widget name="info" position="10,380" zPosition="2" size="540,35" font="Regular;22" transparent="1" halign="center" valign="center"/> </screen>""" def __init__(self, session, streamFile=None): Screen.__init__(self, session) self.setTitle(_("GreekStreamTV list")) self["info"] = Label("...") self["key_red"] = StaticText(_("Cancel")) self["key_green"] = StaticText(_("Play")) self["actions"] = ActionMap(["OkCancelActions", "WizardActions", "ColorActions"], { "ok" : self.keyOK, "green" : self.keyOK, "cancel": self.keyCancel, "red" : self.keyCancel, "up" : self.keyUp, "down" : self.keyDown, "left" : self.keyLeft, "right" : self.keyRight, }, -1) self.streamBin = "/usr/bin/rtmpdump" self.streamPipe = "/tmp/greekstreamtv.avi" if not streamFile: self.streamFile = resolveFilename(SCOPE_PLUGINS, "Extensions/GreekStreamTV/stream.xml") else: self.streamFile = streamFile self.lvstreamer = Livestreamer() self.streamList = [] self.makeStreamList() self["streamlist"] = StreamList(self.streamList) self.onLayoutFinish.append(self.layoutFinished) self.beforeService = None self.currentService = None self.playerStoped = False self.keyLocked = False self.pd = None self.qsel = None def layoutFinished(self): os.system("killall -9 rtmpdump") self.showName() def keyLeft(self): if self.keyLocked: return self["streamlist"].pageUp() self.showName() def keyRight(self): if self.keyLocked: return self["streamlist"].pageDown() self.showName() def keyUp(self): if self.keyLocked: return self["streamlist"].up() self.showName() def keyDown(self): if self.keyLocked: return self["streamlist"].down() self.showName() def keyCancel(self): self.LivestreamerStop() if "/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV" in path: path.remove("/usr/lib/enigma2/python/Plugins/Extensions/GreekStreamTV") self.close() def showName(self): try: tmpName = self["streamlist"].getCurrent()[1].get("name") except: tmpName = "..." self["info"].setText(tmpName) def keyOK(self): print "[GreekStreamTVList::keyOK]" if self.keyLocked: return uriName = self["streamlist"].getCurrent()[1].get("name") self["info"].setText(_("Starting %s\n\nPlease wait...") % uriName) self.timer = eTimer() self.timer.callback.append(self.StartStream) self.timer.start(100, 1) def StartStream(self): self.timer.stop() self.keyLocked = True self.beforeService = None self.currentService = None self.playerStoped = False self.pd = None streamInfo = self["streamlist"].getCurrent()[1] uriInfo = streamInfo.get("uri") typeInfo = streamInfo.get("type").split(":") protocol = typeInfo[0] serviceType = typeInfo[1] bufferSize = typeInfo[2] url = uriInfo.get("URL") if protocol == "rtmp": url += " " url += " ".join(["%s=%s" % (key, value) for (key, value) in uriInfo.items() if key != "URL"]) url = " ".join(url.split()) print "[GreekStreamTVList::keyOK] URL is ", url, " URI is ", uriInfo self.doStreamAction(url, serviceType, bufferSize) elif protocol in ("rtsp", "http"): self.doStreamAction(url, serviceType, bufferSize) elif protocol == "livestreamer": channel = None streams = None try: url += " " url += " ".join(["%s=%s" % (key, value) for (key, value) in uriInfo.items() if key != "URL"]) url = " ".join(url.split()) print "[GreekStreamTVList::keyOK] URL is ", url, " URI is ", uriInfo channel = self.lvstreamer.resolve_url(url) streams = channel.get_streams() print "[GreekStreamTVList::keyOK] Streams: ", streams.keys() print "[GreekStreamTVList::keyOK] Streams: ", streams.items() if len(streams) == 3 and "best" in streams and "worst" in streams: self.streamPreBuffer(streams["best"]) elif len(streams) == 0: raise Exception("No Streams Found") else: self.qsel = self.session.openWithCallback(self.QualitySelClosed, SelectQuality, streams, self.streamPreBuffer) except Exception as err: print "[GreekStreamTVList::keyOK::Exception] Error: ", err tmpMessage = _("An error occured: ") + str(err)[:200] + "..." self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=10) else: print "[GreekStreamTVList::keyOK] Unknown Protocol: ", protocol tmpMessage = _("Unknown protocol: ") + protocol self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_WARNING, timeout=10) def QualitySelClosed(self, recursive): if self.qsel: self.qsel.close() self.qsel = None self.stopPlayer() def streamPreBuffer(self, stream): fd = None try: fd = stream.open() prebuffer = fd.read(8196 * 128) #PREBUFFER if len(prebuffer) == 0: raise Exception("No Data Received From Stream Server") start_new_thread(self.streamCopy, (fd,prebuffer)) sleep(1.5) self.doStreamAction(self.streamPipe) except Exception as err: if fd and hasattr(fd, "close"): fd.close() print "[GreekStreamTVList::streamPreBuffer::Exception] Error: ", err tmpMessage = _("An error occured while buffering: ") + str(err)[:200] + "..." self.session.openWithCallback(self.stopPlayer, MessageBox, tmpMessage, type=MessageBox.TYPE_ERROR, timeout=10) def streamCopy(self, fd, prebuffer): print "[GreekStreamTVList::streamCopy]" if os.access(self.streamPipe, os.F_OK): os.remove(self.streamPipe) os.mkfifo(self.streamPipe) self.pd = open(self.streamPipe, "wb") try: self.pd.write(prebuffer) while self is not None and self.session is not None and not self.playerStoped: data = fd.read(8192) if len(data) == 0: break self.pd.write(data) print "[GreekStreamTVList:streamCopy] playerStoped" self.pd.close() if hasattr(fd, "close"): fd.close() fd = None except Exception as err: print "[GreekStreamTVList::streamCopy] Exception: ", err finally: self.playerStoped = True if fd and hasattr(fd, "close"): fd.close() def LivestreamerStop(self): print "[GreekStreamTVList::LivestreamStop]" self.showName() self.keyLocked = False self.playerStoped = True os.system("killall -9 rtmpdump") sleep(0.5) if self.pd: try: self.pd.close() except: sleep(0.5) try: self.pd.close() except: pass if self.qsel is not None: self.qsel.close(False) self.pd = None self.qsel = None def doStreamAction(self, url=None, serviceType=4097, bufferSize=None): if url is None: url=self.streamPipe self.streamPlayerTimer.stop() try: serviceType = int(serviceType) except: serviceType = 4097 try: bufferSize = int(bufferSize) except: bufferSize = None service = eServiceReference(serviceType, 0, url) #if bufferSize is not None: # service.setData(2, bufferSize*1024) streamInfo = self["streamlist"].getCurrent()[1] service.setName(str(streamInfo.get("name"))) uriInfo = streamInfo.get("uri") self.beforeService = self.session.nav.getCurrentlyPlayingServiceReference() self.currentService = self.session.openWithCallback(self.onStreamFinished, GreekStreamTVPlayer, service, stopPlayer=self.stopPlayer, chName=str(streamInfo.get("name")), chURL =str(uriInfo.get("URL")), chIcon=str(streamInfo.get("icon"))) def stopPlayer(self, params=None): print "[GreekStreamTV::stopPlayer]" if params is None or isinstance(params, bool): self.playerStoped = True self.LivestreamerStop() return def onStreamFinished(self): print "[GreekStreamTV::onStreamFinished]" self.LivestreamerStop() self.session.nav.playService(self.beforeService) print "[GreekStreamTV::onStreamFinished] player done!!" def makeStreamList(self): try: streamDB = StreamURIParser(self.streamFile).parseStreamList() except Exception as err: print "[GreekStreamTV::makeStreamList] Error: ", err streamDB = [] self.streamList = [ (x.get("name"), x) for x in streamDB ]
class StreamAnalysis(Thread): def __init__(self, timeList, eventList, worldmap): Thread.__init__(self) self._timeList = timeList self._eventList = eventList self._timeZero = 1392254560 # set up templates as private variables for this class self._templatesTime = pickle.load(open('timeValues.data', 'rb')) self._templatesRed = pickle.load(open('redTemplates.data', 'rb')) self._templatesEvent = pickle.load(open('eventTemplates.data', 'rb')) self._worldmap = cv2.cvtColor(worldmap.copy(), cv2.COLOR_BGR2GRAY) def initStream(self): self._livestreamer = Livestreamer() self._plugin = self._livestreamer.resolve_url( 'http://twitch.tv/twitchplayspokemon') def fetchStream(self): streams = self._plugin.get_streams() if 'source' in streams: return streams.get('source') return False def run(self): self.initStream() stream = self.fetchStream() while stream == False: print 'STREAM' time.sleep(60) print 'rechecking if stream is available' stream = self.fetchStream() #cap = cv2.VideoCapture( 'http://store22.media22.justin.tv/archives/2014-2-17/live_user_twitchplayspokemon_1392633446.flv' ) cap = cv2.VideoCapture(stream.url) tmpTimeValues = [] last_position = (-1, -1) while True: if not overridePosition == (-1, -1) and last_position == (-1, -1): last_position = overridePosition flag, frame = cap.read() if not flag: stream = self.fetchStream() cap = cv2.VideoCapture(stream.url) flag, frame = cap.read() if not flag: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) timeValues = self.getTimeValues(gray[81:119, 526:830]) if timeValues == tmpTimeValues: continue tmpTimeValues = timeValues date = self.getDateFromTime(timeValues) if not 'day' in date or not 'hour' in date or not 'minute' in date or not 'second' in date: print 'error parsing date' continue timeStamp = self._timeZero + int(date['day']) * 24 * 60 * 60 + int( date['hour']) * 60 * 60 + int(date['minute']) * 60 + int( date['second']) # crop to gameboy area crop = gray[24:457, 24:504] # find red (if not found with enough confidence it's "undefined") currentDirection = self.getRedDirection(crop[182:230, 194:233]) if currentDirection == 'undefined': #self.newEntry(timeStamp, date, last_position) continue # check if there is currently an event open events = self.detectEvents(crop) if len(events) > 0 and not last_position == (-1, -1): #self.newEntry(timeStamp, date, last_position) self._eventList.append(events[0]) continue # detect position on map # scale to world-map ratio # 480px -> 160px crop = cv2.resize(crop, (160, 144)) # crop the worldmap image to a reasonable size, so we do not have to search so excessively # we can only do this if we have a starting position validationImage = self._worldmap left_corner = (0, 0) #cv2.imshow('crop', crop) #cv2.imshow('img', validationImage) #cv2.waitKey(0) if not last_position == (-1, -1): size = (500, 500) left_corner = (last_position[0] - size[0] / 2, last_position[1] - size[1] / 2) validationImage = self._worldmap[ left_corner[1]:left_corner[1] + size[1], left_corner[0]:left_corner[0] + size[0]] #cv2.imshow('crop', crop) #cv2.imshow('img', validationImage) #cv2.waitKey(0) # this should generally not happen, but if it does, we do not know where we are # so we're defaulting to the whole worldmap # TODO: THIS SHOULD BE REPLACED WITH -> DEFAULTING TO INDOOR MAPS! if validationImage.shape < crop.shape: validationImage = self._worldmap left_corner = (0, 0) res = cv2.matchTemplate(validationImage, crop, cv2.TM_CCOEFF_NORMED) w, h = crop.shape[::-1] min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) # if we don't find something we're confident in, use the last position #if max_val < 0.5 and not last_position == (-1, -1): # self.newEntry(timeStamp, date, last_position) # continue # retry until we find a good first match if max_val < 0.8: validationImage = self._worldmap left_corner = (0, 0) res = cv2.matchTemplate(validationImage, crop, cv2.TM_CCOEFF_NORMED) w, h = crop.shape[::-1] min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) print max_val if max_val < 0.7: print 'hit low' continue top_left = max_loc top_left = (top_left[0] + left_corner[0], top_left[1] + left_corner[1]) center = (top_left[0] + w / 2, top_left[1] + h / 2) bottom_right = (top_left[0] + w, top_left[1] + h) last_position = center self.newEntry(timeStamp, date, last_position) if len(self._timeList) > 20: self._timeList = [] def getTimeValues(self, timeCrop): timeValues = [] for key in self._templatesTime: template = self._templatesTime[key] w, h = template.shape[::-1] res = cv2.matchTemplate(timeCrop, template, cv2.TM_CCOEFF_NORMED) threshold = 0.9 loc = numpy.where(res >= threshold) for pt in zip(*loc[::-1]): timeValues.append((pt[0], pt[1], key)) timeValues.sort() return timeValues def getDateFromTime(self, timeValues): date = {} tmp = '' for timeValue in timeValues: key = timeValue[2] if key == 'd': date['day'] = tmp.zfill(2) tmp = '' elif key == 'h': date['hour'] = tmp.zfill(2) tmp = '' elif key == 'm': date['minute'] = tmp.zfill(2) tmp = '' elif key == 's': date['second'] = tmp.zfill(2) tmp = '' else: tmp = '{}{}'.format(tmp, key) return date def getRedDirection(self, redCrop): currentDirection = 'undefined' redCrop = cv2.resize(redCrop, (10, 10)) for direction in self._templatesRed: template = self._templatesRed[direction] template = cv2.resize(template, (10, 10)) res = cv2.matchTemplate(redCrop, template, cv2.TM_CCOEFF_NORMED) min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(res) if max_val > 0.55: currentDirection = direction break return currentDirection def detectEvents(self, crop): eventValues = [] detectionAreas = {} detectionAreas['moonstone'] = crop.copy() # moonstone detectionAreas['dialogue'] = crop[293:435, 0:480] # dialogue detectionAreas['optionsMenu'] = crop[3:388, 240:480] # optionsMenu detectionAreas['naming'] = crop[98:360, 0:480] # naming for key in self._templatesEvent: template = self._templatesEvent[key] area = detectionAreas[key] w, h = template.shape[::-1] if area.shape < template.shape: break res = cv2.matchTemplate(area, template, cv2.TM_CCOEFF_NORMED) threshold = 0.95 loc = numpy.where(res >= threshold) for pt in zip(*loc[::-1]): _tuple = (pt[0], pt[1], key) if not _tuple in eventValues: eventValues.append(_tuple) # currently there can only be one event at any given timespace if len(eventValues) > 0: break return eventValues def newEntry(self, timeStamp, date, position): _tuple = (timeStamp, date, position) # we are in a room without outsideworld reference # this could only happen, if we start recording inside a building right now if position == (-1, -1): print 'WHERE ARE WE?\r' return if not _tuple in self._timeList: self._timeList.append(_tuple) print '{}\t{},{}\r'.format(str(timeStamp), position[0], position[1]), with open('positionData.csv', 'a') as entryFile: line = '{};{};{};{};{};{};{}\n'.format(timeStamp, \ date['day'], date['hour'], date['minute'], date['second'], \ position[0], position[1]) entryFile.write(line) with open('www/currentPosition', 'w') as _file: _file.write('{} {}'.format(position[0], position[1])) with open('www/currentTime', 'w') as _file: _file.write('{} {} {} {}'.format(date['day'], date['hour'], date['minute'], date['second']))
def play_url(): # this only plays http urls for now, torrents soon. global title url = request.args.get('url') # grab url from /play?url=* if not url.startswith('http'): # in case the user forgot it log('url missing http/wrong protocol') url = 'http://' + url # let's assume it's http, not https log('received url %s' % url) log('requesting headers from %s...' % url) req = Request(url) req.get_method = lambda: 'HEAD' # only request headers, no content response = urlopen(req) ctype = response.headers['content-type'] ctype_split = ctype.split('/') # split into 2 parts log('headers received. content type is %s' % ctype) try: if ctype_split[0] == 'audio' or ctype_split[0] == 'video': log('url was raw media file, playing! :)') title = url # i guess this works? :T play_omxplayer(url) elif ctype_split[1] == 'x-bittorrent': log('loading torrents not implemented.') # this isn't implemented yet. elif ctype_split[0] == 'text': # here we check if it's a livestream, and if so get the RTMP url log('checking if url is a livestream...') live = Livestreamer() try: if "youtube" in url: raise RuntimeError( "youtube is f****d up w/ streaming, falling back to youtube-dl" ) plugin = live.resolve_url(url) streams = plugin.get_streams() stream = streams.get( "best") # fingers crossed for best quality stream_url_types = ['rtmp', 'url' ] # things that livestreamer can have :D for stream_type in stream_url_types: if hasattr(stream, stream_type): log('url is livestream!') title = "%s (livestream)" % url play_omxplayer(getattr(stream, stream_type)) return '', 204 except (PluginError, RuntimeError ) as e: # therefore url is not (supported) livestream pass # continue and let youtube-dl try. log('loading youtube-dl for further processing') ydl = YoutubeDL({ 'outtmpl': '%(id)s%(ext)s', 'restrictfilenames': True }) ydl.add_default_info_extractors() result = ydl.extract_info(url, download=False) if 'entries' in result: # if video is a playlist video = result['entries'][ 0] # play the 1st video in the playlist else: video = result play_omxplayer(video['url']) title = video['title'] else: raise DownloadError('Invalid filetype: not audio, video, or text.') return '', 204 # success w/ no response! except (UnicodeDecodeError, DownloadError) as e: return _ANSI_ESCAPE_REXP.sub('', str(e)), 400 # send error message
class Main: def __init__(self): self.gchoice = -1 self.cchoice = -1 self.exit_now = False self.state = 'none' self.keybingings = { ord('q'): self.quit, ord('f'): self.get_favorites, ord('s'): self.get_fav_games, ord('g'): self.get_games, ord('n'): self.get_next, ord('r'): self.refresh, ord('p'): self.get_previous } self.games = [] self.favs = [] self.channels = [] self.twitch = Twitch(config.get('settings', 'twitchapiurl'), config.get('settings', 'channel'), config.get('settings', 'game')) self.livestreamer = Livestreamer() try: self.run() except Exception as e: print e.message def run(self): while True: self.display_message() if self.exit_now: return def quit(self, c): self.exit_now = True def display_message(self): if self.state == 'none': clear_screen() self.handle_user_input('Choose an option : (F)avorites, (G)ame, (Q)uit') if self.state == 'favs': clear_screen() print 'Showing online favorites stream :' print '-' * 40 if(len(self.favs) > 0): self.show_content(self.favs) self.handle_user_input('Choose a channel by number (r to refresh, g to list by games and q to quit', range(len(self.favs) + 1)) clear_screen() else: self.handle_user_input('No favorites channel online (r to refresh, g to list by games and q to quit', range(len(self.favs) + 1)) clear_screen() if self.state == 'games': clear_screen() print 'Showing top %d games:' % config.getint('settings', 'game') print '-' * 40 if(len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input('Choose a game by number (r to refresh, f to check your favorite channels and q to quit', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'favgames': clear_screen() print 'Showing favorites games:' print '-' * 40 if(len(self.games) > 0): self.show_content(self.games) self.gchoice = self.handle_user_input('Choose a game by number (r to refresh, f to check your favorite channels and q to quit', range(len(self.games) + 1)) if self.gchoice != -1: self.state = 'channels' clear_screen() if self.state == 'channels': clear_screen() print 'Showing top %d channel for %s:' % (config.getint('settings', 'channel'), self.games[self.gchoice - 1]) print '-' * 40 self.get_channels(self.gchoice) if(len(self.channels) > 0): self.show_content(self.channels) self.cchoice = self.handle_user_input('Choose a channel by number (r to refresh, f to check your favorite channels, g to reload game list and q to quit', range(len(self.channels) + 1)) if self.cchoice != -1: self.play_stream(self.channels[self.cchoice - 1]) self.state = 'channels' clear_screen() def play_stream(self, channel): clear_screen() try: plugin = self.livestreamer.resolve_url(("twitch.tv/{0}").format(channel)) except Exception as e: print e.message try: streams = plugin.get_streams() except PluginError as err: exit("Plugin error: {0}".format(err)) quality = config.get('settings', 'quality') if quality not in streams: quality = "Source" print "Can't open streams with quality requested ({0}), opening best one".format(config.get('settings', 'quality')) channel = transform_spaces(channel) if os.name == 'nt': os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) #os.system('livestreamer twitch.tv/%s best -p "%s"' % (channel, config.get('settings', 'player'))) else: os.system('livestreamer twitch.tv/%s %s' % (channel, quality)) #os.system('livestreamer twitch.tv/%s best -np "%s"' % (channel, config.get('settings', 'player'))) def show_content(self, content): for i in range(len(content)): if i < 9: print '', if i < 99: print '', print '%d %s' % (i + 1, content[i]) def handle_user_input(self, message, valid = None): self.state = 'none' validinput = False while not validinput: input = raw_input('%s\n ' % message) input = input.strip().lower() if input.isdigit(): input = int(input) if input in valid: validinput = True return input elif len(input) == 1: c = ord(input) f = self.keybingings.get(c, None) if f: f(c) validinput = True return -1 def get_favorites(self, c): self.state = 'favs' del self.favs[:] try: response = self.twitch.get_favorites_streams_status(config.get('settings', 'favorites')) receivedcount = len(response['streams']) for i in range(receivedcount): self.favs.append('%s playing: %s' % (response['streams'][i]['channel']['name'], response['streams'][i]['game'])) except Exception as e: print 'Error getting favs streams!\n' print e.message return 0 def get_games(self, c): self.state = 'games' del self.games[:] try: response = self.twitch.get_game_list() receivedcount = len(response['top']) for i in range(receivedcount): self.games.append(response['top'][i]['game']['name']) except Exception as e: print 'Error getting games !\n' print e.message return 0 def get_fav_games(self, c): self.state = 'favgames' del self.games[:] favgames = config.get('settings', 'favgames') if len(favgames) > 0: self.games.extend(favgames.split(', ')) def get_channels(self, choice): self.state = 'channels' del self.channels[:] try: response = self.twitch.get_channel_for_game(transform_spaces(self.games[self.gchoice - 1])) receivedcount = len(response['streams']) for i in range(receivedcount): self.channels.append('%s (%s)' % (response['streams'][i]['channel']['name'], response['streams'][i]['viewers'])) except Exception as e: print 'Error getting games !\n' print e.message return 0 def refresh(self, c): print 'tmp' def get_next(self, c): print 'tmp' def get_previous(self, c): print 'tmp'