Exemple #1
0
            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)
Exemple #2
0
    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)
Exemple #3
0
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")
Exemple #4
0
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)
Exemple #5
0
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']))
Exemple #6
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')))
Exemple #7
0
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)
Exemple #8
0
    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()
Exemple #10
0
def setup_livecli():
    livecli_cli.main.livecli = Livecli()
    livecli_cli.main.livecli.load_plugins(PluginPath)
    return livecli_cli.main.livecli
Exemple #11
0
 def setUp(self):
     self.session = Livecli()
     self.session.load_plugins(self.PluginPath)
Exemple #12
0
 def test_check_cmd_cat(self, compat_which):
     s = StreamProcess(Livecli())
     compat_which.return_value = s.cmd = "test"
     self.assertEqual("test", s._check_cmd())
Exemple #13
0
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
Exemple #14
0
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)
Exemple #15
0
 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)
Exemple #16
0
 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()
Exemple #17
0
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")
Exemple #18
0
 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())
Exemple #19
0
 def test_check_cmd_none(self):
     s = StreamProcess(Livecli())
     self.assertRaises(StreamError, s._check_cmd)
Exemple #20
0
def setup_livecli():
    """Creates the Livecli session."""
    global livecli

    livecli = Livecli()
Exemple #21
0
 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())
Exemple #22
0
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"))
Exemple #24
0
 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