def test(self, mock_http): self.session = Livecli() self.manager = Logger() self.logger = self.manager.new_module("test") mock_http.get = api.HTTPSession().get mock_http.json = api.HTTPSession().json Resolve.bind(self.session, "test.plugin.resolve") default_iframe = "http://mocked/default/iframe" file_url = _stream_data["url"] self_url = "http://mocked/live" with requests_mock.Mocker() as mock: mock.get(default_iframe, text=text_with_playlist % file_url) mock.get(file_url, text=_stream_data["text"]) mock.get(self_url, text=_website_text) self.session.set_plugin_option("resolve", "whitelist_netloc", ["mocked"]) plugin = Resolve(self_url) streams = plugin._get_streams() self.assertIn(_stream_data["name"], streams)
def __new__(mcs, name, bases, dict): plugin_path = os.path.dirname(livecli.plugins.__file__) plugins = [] for loader, pname, ispkg in pkgutil.iter_modules([plugin_path]): file, pathname, desc = imp.find_module(pname, [plugin_path]) module = imp.load_module(pname, file, pathname, desc) if hasattr(module, "__plugin__"): plugins.append((pname)) session = Livecli() def gentest(pname): def load_plugin_test(self): # Reset file variable to ensure it is still open when doing # load_plugin else python might open the plugin source .py # using ascii encoding instead of utf-8. # See also open() call here: imp._HackedGetData.get_data file, pathname, desc = imp.find_module(pname, [plugin_path]) session.load_plugin(pname, file, pathname, desc) return load_plugin_test for pname in plugins: dict['test_{0}_load'.format(pname)] = gentest(pname) return type.__new__(mcs, name, bases, dict)
class TestPluginAkamaiHDPlugin(unittest.TestCase): def setUp(self): self.session = Livecli() def test_can_handle_url(self): should_match = [ "akamaihd://https://example.com/index.mp3", "akamaihd://https://example.com/index.mp4", ] for url in should_match: self.assertTrue(AkamaiHDPlugin.can_handle_url(url)) should_not_match = [ "https://example.com/index.html", ] for url in should_not_match: self.assertFalse(AkamaiHDPlugin.can_handle_url(url)) def _test_akamaihd(self, surl, url): plugin = self.session.resolve_url(surl) streams = plugin.streams() self.assertTrue("live" in streams) stream = streams["live"] self.assertTrue(isinstance(stream, AkamaiHDStream)) self.assertEqual(stream.url, url) def test_plugin_akamaihd(self): self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se/stream") self._test_akamaihd("akamaihd://hostname.se/stream", "http://hostname.se/stream")
class PluginResolveTestMeta(type): def __new__(mcs, name, bases, dict): def gen_test(_website_text, _stream_data): @patch("livecli.plugins.resolve.http") def test(self, mock_http): self.session = Livecli() self.manager = Logger() self.logger = self.manager.new_module("test") mock_http.get = api.HTTPSession().get mock_http.json = api.HTTPSession().json Resolve.bind(self.session, "test.plugin.resolve") default_iframe = "http://mocked/default/iframe" file_url = _stream_data["url"] self_url = "http://mocked/live" with requests_mock.Mocker() as mock: mock.get(default_iframe, text=text_with_playlist % file_url) mock.get(file_url, text=_stream_data["text"]) mock.get(self_url, text=_website_text) self.session.set_plugin_option("resolve", "whitelist_netloc", ["mocked"]) plugin = Resolve(self_url) streams = plugin._get_streams() self.assertIn(_stream_data["name"], streams) return test for test_dict in data_stream: _website_text = test_dict["website_text"] _stream_data = stream_data[test_dict["stream_type"]] test_name = "test_%s" % test_dict["test_name"] dict[test_name] = gen_test(_website_text, _stream_data) return type.__new__(mcs, name, bases, dict)
class TestPluginRTMPPlugin(unittest.TestCase): def setUp(self): self.session = Livecli() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def test_can_handle_url(self): should_match = [ "rtmp://https://example.com/", "rtmpe://https://example.com/", "rtmps://https://example.com/", "rtmpt://https://example.com/", "rtmpte://https://example.com/", ] for url in should_match: self.assertTrue(RTMPPlugin.can_handle_url(url)) should_not_match = [ "https://example.com/index.html", ] for url in should_not_match: self.assertFalse(RTMPPlugin.can_handle_url(url)) def _test_rtmp(self, surl, url, params): plugin = self.session.resolve_url(surl) streams = plugin.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_rtmp(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) 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_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 conn=['B:1','S:authMe','O:1','NN:code:1.23','NS:flag:ok','O:0']", "rtmp://hostname.se/stream", dict(conn=['B:1', 'S:authMe', 'O:1', 'NN:code:1.23', 'NS:flag:ok', 'O:0']))
class TestPluginHTTPStreamPlugin(unittest.TestCase): def setUp(self): self.session = Livecli() def assertDictHas(self, a, b): for key, value in a.items(): self.assertEqual(b[key], value) def test_can_handle_url(self): should_match = [ "httpstream://https://example.com/index.mp3", "httpstream://https://example.com/index.mp4", ] for url in should_match: self.assertTrue(HTTPStreamPlugin.can_handle_url(url)) should_not_match = [ "https://example.com/index.html", ] for url in should_not_match: self.assertFalse(HTTPStreamPlugin.can_handle_url(url)) def _test_http(self, surl, url, params): plugin = self.session.resolve_url(surl) streams = plugin.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_http(self): 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')))
def main(): if len(sys.argv) < 3: exit("Usage: {0} <url> <quality>".format(sys.argv[0])) # Initialize and check GStreamer version gi.require_version("Gst", "1.0") gobject.threads_init() gst.init(None) # Collect arguments url = sys.argv[1] quality = sys.argv[2] # Create the Livecli session livecli = Livecli() # Enable logging livecli.set_loglevel("info") livecli.set_logoutput(sys.stdout) # Attempt to fetch streams try: streams = livecli.streams(url) except NoPluginError: exit("Livecli is unable to handle the URL '{0}'".format(url)) except PluginError as err: exit("Plugin error: {0}".format(err)) if not streams: 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 = LivecliPlayer() # Blocks until playback is done player.play(stream)
def __new__(mcs, name, bases, dict): plugin_path = os.path.dirname(livecli.plugins.__file__) plugins = [] for loader, pname, ispkg in pkgutil.iter_modules([plugin_path]): file, pathname, desc = imp.find_module(pname, [plugin_path]) module = imp.load_module(pname, file, pathname, desc) if hasattr(module, "__plugin__"): plugins.append((pname, file, pathname, desc)) session = Livecli() def gentest(pname, file, pathname, desc): def load_plugin_test(self): session.load_plugin(pname, file, pathname, desc) return load_plugin_test for pname, file, pathname, desc in plugins: dict['test_{0}_load'.format(pname)] = gentest( pname, file, pathname, desc) return type.__new__(mcs, name, bases, dict)
def setUp(self): self.session = Livecli()
def setup_livecli(): livecli_cli.main.livecli = Livecli() livecli_cli.main.livecli.load_plugins(PluginPath) return livecli_cli.main.livecli
def setUp(self): self.session = Livecli() self.session.load_plugins(self.PluginPath)
def test_check_cmd_cat(self, compat_which): s = StreamProcess(Livecli()) compat_which.return_value = s.cmd = "test" self.assertEqual("test", s._check_cmd())
def _play_stream(HTTPBase, redirect=False): """Creates a livecli session and plays the stream.""" session = Livecli() session.set_logprefix("[ID-{0}]".format(str(int(time()))[4:])) logger = session.logger.new_module("livecli-server") session.set_loglevel("info") logger.info("User-Agent: {0}".format( HTTPBase.headers.get("User-Agent", "???"))) logger.info("Client: {0}".format(HTTPBase.client_address)) logger.info("Address: {0}".format(HTTPBase.address_string())) # Load custom user plugins if os.path.isdir(PLUGINS_DIR): session.load_plugins(PLUGINS_DIR) old_data = parse_qsl(urlparse(HTTPBase.path).query) data = [] for k, v in old_data: data += [(unquote_plus(k), unquote_plus(v))] data_other, session = command_session(session, data) url = data_other.get("url") if not url: HTTPBase._headers(404, "text/html") logger.error("No URL provided.") return quality = (data_other.get("q") or data_other.get("quality") or data_other.get("stream") or data_other.get("default-stream") or "best") try: cache = data_other.get("cache") or 4096 except TypeError: cache = 4096 loglevel = data_other.get("l") or data_other.get("loglevel") or "debug" session.set_loglevel(loglevel) try: if redirect is True: streams = session.streams(url, stream_types=["hls", "http"]) else: streams = session.streams(url) except Exception as e: HTTPBase._headers(404, "text/html") logger.error("No Stream Found!") return if not streams: HTTPBase._headers(404, "text/html") return # XXX: only one quality will work currently try: stream = streams[quality] except KeyError: stream = streams["best"] quality = "best" if isinstance(stream, HTTPStream) is False and isinstance( stream, HDSStream) is False: # allow only http based streams: HDS HLS HTTP # RTMP is not supported HTTPBase._headers(404, "text/html") return if redirect is True: logger.info("301 - URL: {0}".format(stream.url)) HTTPBase.send_response(301) HTTPBase.send_header("Location", stream.url) HTTPBase.end_headers() logger.info("301 - done") return hls_session_reload = data_other.get("hls-session-reload") if hls_session_reload: livecli_cache = Cache(filename="streamdata.json", key_prefix="cache:{0}".format(stream.url)) livecli_cache.set("cache_stream_name", quality, (int(hls_session_reload) + 60)) livecli_cache.set("cache_url", url, (int(hls_session_reload) + 60)) session.set_option("hls-session-reload", int(hls_session_reload)) try: fd = stream.open() except StreamError as err: HTTPBase._headers(404, "text/html") logger.error("Could not open stream: {0}".format(err)) return HTTPBase._headers(200, "video/unknown") try: logger.debug("Pre-buffering {0} bytes".format(cache)) while True: buff = fd.read(cache) if not buff: logger.error("No Data!") break HTTPBase.wfile.write(buff) HTTPBase.wfile.close() except socket.error as e: if isinstance(e.args, tuple): if e.errno == errno.EPIPE: # remote peer disconnected logger.info("Detected remote disconnect") pass else: logger.error(str(e)) else: logger.error(str(e)) fd.close() logger.info("Stream ended") fd = None
class TestSession(unittest.TestCase): PluginPath = os.path.join(os.path.dirname(__file__), "plugins") def setUp(self): self.session = Livecli() self.session.load_plugins(self.PluginPath) def test_exceptions(self): try: # Turn off the resolve.py plugin self.session.set_plugin_option("resolve", "turn_off", True) 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() plugin = self.session.resolve_url("http://test.se/channel") self.assertTrue(isinstance(plugin, Plugin)) self.assertTrue(isinstance(plugin, plugins["testplugin"])) def test_resolve_url_priority(self): from tests.plugins.testplugin import TestPlugin class HighPriority(TestPlugin): @classmethod def priority(cls, url): return HIGH_PRIORITY class LowPriority(TestPlugin): @classmethod def priority(cls, url): return LOW_PRIORITY self.session.plugins = { "test_plugin": TestPlugin, "test_plugin_low": LowPriority, "test_plugin_high": HighPriority, } plugin = self.session.resolve_url_no_redirect("http://test.se/channel") plugins = self.session.get_plugins() self.assertTrue(isinstance(plugin, plugins["test_plugin_high"])) self.assertEqual(HIGH_PRIORITY, plugin.priority(plugin.url)) def test_resolve_url_no_redirect(self): plugins = self.session.get_plugins() plugin = self.session.resolve_url_no_redirect("http://test.se/channel") self.assertTrue(isinstance(plugin, Plugin)) self.assertTrue(isinstance(plugin, 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): plugin = self.session.resolve_url("http://test.se/channel") streams = plugin.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): plugin = self.session.resolve_url("http://test.se/channel") streams = plugin.streams(stream_types=["http", "rtmp"]) self.assertTrue(isinstance(streams["480p"], HTTPStream)) self.assertTrue(isinstance(streams["480p_rtmp"], RTMPStream)) streams = plugin.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): plugin = self.session.resolve_url("http://test.se/channel") streams = plugin.streams(sorting_excludes=["1080p", "3000k"]) self.assertTrue("best" in streams) self.assertTrue("worst" in streams) self.assertTrue(streams["best"] is streams["1500k"]) streams = plugin.streams(sorting_excludes=[">=1080p", ">1500k"]) self.assertTrue(streams["best"] is streams["1500k"]) streams = plugin.streams(sorting_excludes=lambda q: not q.endswith("p")) self.assertTrue(streams["best"] is streams["3000k"]) def test_plugin_support(self): plugin = self.session.resolve_url("http://test.se/channel") streams = plugin.streams() self.assertTrue("support" in streams) self.assertTrue(isinstance(streams["support"], HTTPStream)) def test_version(self): # PEP440 - https://www.python.org/dev/peps/pep-0440/ VERSION_PATTERN = r""" v? (?: (?:(?P<epoch>[0-9]+)!)? # epoch (?P<release>[0-9]+(?:\.[0-9]+)*) # release segment (?P<pre> # pre-release [-_\.]? (?P<pre_l>(a|b|c|rc|alpha|beta|pre|preview)) [-_\.]? (?P<pre_n>[0-9]+)? )? (?P<post> # post release (?:-(?P<post_n1>[0-9]+)) | (?: [-_\.]? (?P<post_l>post|rev|r) [-_\.]? (?P<post_n2>[0-9]+)? ) )? (?P<dev> # dev release [-_\.]? (?P<dev_l>dev) [-_\.]? (?P<dev_n>[0-9]+)? )? ) (?:\+(?P<local>[a-z0-9]+(?:[-_\.][a-z0-9]+)*))? # local version """ _version_re = re.compile( r"^\s*" + VERSION_PATTERN + r"\s*$", re.VERBOSE | re.IGNORECASE, ) self.assertRegexpMatches(self.session.version, _version_re)
def test_check_cmd_nofound(self, compat_which): s = StreamProcess(Livecli()) s.cmd = "test" compat_which.return_value = None self.assertRaises(StreamError, s._check_cmd)
def setUp(self, mock_http): self.res_plugin = Resolve("resolve://https://example.com") self.res_plugin.manager = Logger() self.res_plugin.logger = self.res_plugin.manager.new_module("test") self.session = Livecli()
class TestPluginHLSPlugin(unittest.TestCase): def setUp(self): self.session = Livecli() def test_can_handle_url(self): should_match = [ "https://example.com/index.m3u8", "https://example.com/index.m3u8?test=true", "hls://*****:*****@patch('livecli.stream.HLSStream.parse_variant_playlist') def _test_hls(self, surl, url, mock_parse): mock_parse.return_value = {} plugin = self.session.resolve_url(surl) streams = plugin.streams() self.assertTrue("live" in streams) mock_parse.assert_called_with(self.session, url) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) @patch('livecli.stream.HLSStream.parse_variant_playlist') def _test_hlsvariant(self, surl, url, mock_parse): mock_parse.return_value = {"best": HLSStream(self.session, url)} plugin = self.session.resolve_url(surl) streams = plugin.streams() mock_parse.assert_called_with(self.session, url) self.assertFalse("live" in streams) self.assertTrue("best" in streams) stream = streams["best"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) def test_plugin_hls(self): 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_hlsvariant("hls://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_hlsvariant("hls://https://hostname.se/playlist.m3u8", "https://hostname.se/playlist.m3u8")
def test_check_cmdline(self, compat_which): s = StreamProcess(Livecli(), params=dict(help=True)) compat_which.return_value = s.cmd = "test" self.assertEqual("test --help", s.cmdline())
def test_check_cmd_none(self): s = StreamProcess(Livecli()) self.assertRaises(StreamError, s._check_cmd)
def setup_livecli(): """Creates the Livecli session.""" global livecli livecli = Livecli()
def test_check_cmdline_long(self, compat_which): s = StreamProcess(Livecli(), params=dict(out_file="test file.txt")) compat_which.return_value = s.cmd = "test" self.assertEqual("test --out-file \"test file.txt\"", s.cmdline())
class TestSession(unittest.TestCase): PluginPath = os.path.join(os.path.dirname(__file__), "plugins") def setUp(self): self.session = Livecli() 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_resolve_url_priority(self): from tests.plugins.testplugin import TestPlugin class HighPriority(TestPlugin): @classmethod def priority(cls, url): return HIGH_PRIORITY class LowPriority(TestPlugin): @classmethod def priority(cls, url): return LOW_PRIORITY self.session.plugins = { "test_plugin": TestPlugin, "test_plugin_low": LowPriority, "test_plugin_high": HighPriority, } channel = self.session.resolve_url_no_redirect("http://test.se/channel") plugins = self.session.get_plugins() self.assertTrue(isinstance(channel, plugins["test_plugin_high"])) self.assertEqual(HIGH_PRIORITY, channel.priority(channel.url)) def test_resolve_url_no_redirect(self): plugins = self.session.get_plugins() channel = self.session.resolve_url_no_redirect("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 TestPluginStream(unittest.TestCase): def setUp(self): self.session = Livecli() 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) @patch('livecli.stream.HLSStream.parse_variant_playlist') def _test_hls(self, surl, url, mock_parse): mock_parse.return_value = {} channel = self.session.resolve_url(surl) streams = channel.get_streams() self.assertTrue("live" in streams) mock_parse.assert_called_with(self.session, url) stream = streams["live"] self.assertTrue(isinstance(stream, HLSStream)) self.assertEqual(stream.url, url) @patch('livecli.stream.HLSStream.parse_variant_playlist') def _test_hlsvariant(self, surl, url, mock_parse): mock_parse.return_value = {"best": HLSStream(self.session, url)} channel = self.session.resolve_url(surl) streams = channel.get_streams() mock_parse.assert_called_with(self.session, url) self.assertFalse("live" in streams) self.assertTrue("best" in streams) stream = streams["best"] 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_rtmp(self): self._test_rtmp("rtmp://hostname.se/stream", "rtmp://hostname.se/stream", dict()) 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_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 conn=['B:1','S:authMe','O:1','NN:code:1.23','NS:flag:ok','O:0']", "rtmp://hostname.se/stream", dict(conn=['B:1', 'S:authMe', 'O:1', 'NN:code:1.23', 'NS:flag:ok', 'O:0'])) def test_plugin_hls(self): 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_hlsvariant("hls://hostname.se/playlist.m3u8", "http://hostname.se/playlist.m3u8") self._test_hlsvariant("hls://https://hostname.se/playlist.m3u8", "https://hostname.se/playlist.m3u8") def test_plugin_akamaihd(self): self._test_akamaihd("akamaihd://http://hostname.se/stream", "http://hostname.se/stream") self._test_akamaihd("akamaihd://hostname.se/stream", "http://hostname.se/stream") def test_plugin_http(self): 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'))) def test_parse_params(self): self.assertEqual( dict(verify=False, params=dict(key="a value")), parse_params("""verify=False params={'key': 'a value'}""") ) self.assertEqual( dict(verify=False), parse_params("""verify=False""") ) self.assertEqual( dict(conn=['B:1', 'S:authMe', 'O:1', 'NN:code:1.23', 'NS:flag:ok', 'O:0']), parse_params(""""conn=['B:1', 'S:authMe', 'O:1', 'NN:code:1.23', 'NS:flag:ok', 'O:0']""") ) def test_stream_weight(self): self.assertEqual( (720, "pixels"), stream_weight("720p")) self.assertEqual( (721, "pixels"), stream_weight("720p+")) self.assertEqual( (780, "pixels"), stream_weight("720p60")) self.assertTrue( stream_weight("720p+") > stream_weight("720p")) self.assertTrue( stream_weight("720p") == stream_weight("720p")) self.assertTrue( stream_weight("720p_3000k") > stream_weight("720p_2500k")) self.assertTrue( stream_weight("720p60_3000k") > stream_weight("720p_3000k")) self.assertTrue( stream_weight("720p_3000k") < stream_weight("720p+_3000k")) self.assertTrue( stream_weight("3000k") > stream_weight("2500k"))
def setUp(self): self.session = Livecli() self.manager = Logger() self.logger = self.manager.new_module("test")
def get_session(): s = Livecli() s.load_plugins(PluginPath) return s