Repository: streamlink/streamlink
Pull request #2401 (2019-04-03 22:42:59)

plugins.mediaklikk: update plugin
Things were changed on the site, all the current livestreams work now.


Patch:
diff --git a/src/streamlink/plugins/bbciplayer.py b/src/streamlink/plugins/bbciplayer.py
index dec5978d..a4c4f7da 100644
--- a/src/streamlink/plugins/bbciplayer.py
+++ b/src/streamlink/plugins/bbciplayer.py
@@ -30,7 +30,7 @@ class BBCiPlayer(Plugin):
         )
     """, re.VERBOSE)
     mediator_re = re.compile(
-        r'window\.mediatorDefer\s*=\s*page\([^,]*,\s*({.*?})\);', re.DOTALL)
+        r'window\.__IPLAYER_REDUX_STATE__\s*=\s*({.*?});', re.DOTALL)
     tvip_re = re.compile(r'channel"\s*:\s*{\s*"id"\s*:\s*"(\w+?)"')
     tvip_master_re = re.compile(r'event_master_brand=(\w+?)&')
     account_locals_re = re.compile(r'window.bbcAccount.locals\s*=\s*({.*?});')
@@ -45,20 +45,19 @@ class BBCiPlayer(Plugin):
 
     mediator_schema = validate.Schema(
         {
-            "appStoreState": {
-                "versions": [{"id": validate.text}]
-            }
+            "versions": [{"id": validate.text}]
         },
-        validate.get("appStoreState"), validate.get("versions"), validate.get(0),
+        validate.get("versions"), validate.get(0),
         validate.get("id")
     )
     mediaselector_schema = validate.Schema(
         validate.transform(parse_json),
         {"media": [
-            {"connection": [{
-                validate.optional("href"): validate.url(),
-                validate.optional("transferFormat"): validate.text
-            }],
+            {"connection":
+                validate.all([{
+                    validate.optional("href"): validate.url(),
+                    validate.optional("transferFormat"): validate.text
+                }], validate.filter(lambda c: c.get("href"))),
                 "kind": validate.text}
         ]},
         validate.get("media"),
diff --git a/src/streamlink/plugins/bfmtv.py b/src/streamlink/plugins/bfmtv.py
index 395fb79c..f583f7f0 100644
--- a/src/streamlink/plugins/bfmtv.py
+++ b/src/streamlink/plugins/bfmtv.py
@@ -8,7 +8,7 @@ from streamlink.stream import HLSStream
 class BFMTV(Plugin):
     _url_re = re.compile(r'https://.+\.(?:bfmtv|01net)\.com')
     _brightcove_video_re = re.compile(r'data-holder="video(?P<video_id>[0-9]+)" data-account="(?P<account_id>[0-9]+)"')
-    _brightcove_video_alt_re = re.compile(r'data-account="(?P<account_id>[0-9]+).*?data-video-id="(?P<video_id>[0-9]+)"')
+    _brightcove_video_alt_re = re.compile(r'data-account="(?P<account_id>[0-9]+).*?data-video-id="(?P<video_id>[0-9]+)"', re.DOTALL)
     _embed_video_url_re = re.compile(r"\$YOPLAYER\('liveStitching', {.+?file: '(?P<video_url>[^\"]+?)'.+?}\);", re.DOTALL)
 
     @classmethod
diff --git a/src/streamlink/plugins/idf1.py b/src/streamlink/plugins/idf1.py
index 880ccf63..0a083391 100644
--- a/src/streamlink/plugins/idf1.py
+++ b/src/streamlink/plugins/idf1.py
@@ -13,7 +13,7 @@ class IDF1(Plugin):
 
     _url_re = re.compile(r'http://www\.idf1\.fr/(videos/[^/]+/[^/]+\.html|live\b)')
     _video_id_re = re.compile(r"dacast\('(?P<broadcaster_id>\d+)_(?P<video_type>[a-z]+)_(?P<video_id>\d+)', 'replay_content', data\);")
-    _video_id_alt_re = re.compile(r'<script src="//player.dacast.com/js/player.js" id="(?P<broadcaster_id>\d+)_(?P<video_type>[cf])_(?P<video_id>\d+)"')
+    _video_id_alt_re = re.compile(r'<script src="https://player.dacast.com/js/player.js" id="(?P<broadcaster_id>\d+)_(?P<video_type>[cf])_(?P<video_id>\d+)"')
     _player_url = 'http://ssl.p.jwpcdn.com/player/v/7.12.6/jwplayer.flash.swf'
 
     _api_schema = validate.Schema(
@@ -54,7 +54,11 @@ class IDF1(Plugin):
         video_id = match.group('video_id')
 
         videos = self.session.http.get(self.DACAST_API_URL.format(broadcaster_id, video_type, video_id), schema=self._api_schema)
-        token = self.session.http.get(self.DACAST_TOKEN_URL.format(broadcaster_id, video_type, video_id), schema=self._token_schema)
+        token = self.session.http.get(
+            self.DACAST_TOKEN_URL.format(broadcaster_id, video_type, video_id),
+            schema=self._token_schema,
+            headers={'referer': self.url}
+        )
         parsed = []
 
         for video_url in videos:
diff --git a/src/streamlink/plugins/mediaklikk.py b/src/streamlink/plugins/mediaklikk.py
index 3f91dd73..0fa960f2 100644
--- a/src/streamlink/plugins/mediaklikk.py
+++ b/src/streamlink/plugins/mediaklikk.py
@@ -1,40 +1,45 @@
+import logging
 import re
 
+from streamlink.exceptions import PluginError
 from streamlink.plugin import Plugin
 from streamlink.stream import HLSStream
+from streamlink.utils.url import update_scheme
 
+log = logging.getLogger(__name__)
 
-_stream_url_re = re.compile(r"http(s)?://(www\.)?mediaklikk.hu/([A-Za-z0-9\-]+)/?")
-_id_re = re.compile(r'.*data\-streamid="([a-z0-9]+)".*')
-_file_re = re.compile(r'.*{\'file\': ?\'([a-zA-Z0-9\./\?=:]+)\'}].*')
 
-_stream_player_url = "http://player.mediaklikk.hu/player/player-inside-full3.php?userid=mtva&streamid={0}&flashmajor=21&flashminor=0"
+class Mediaklikk(Plugin):
+    PLAYER_URL = "https://player.mediaklikk.hu/playernew/player.php"
 
+    _url_re = re.compile(r"https?://(?:www\.)?mediaklikk\.hu/[\w\-]+\-elo/?")
+    _id_re = re.compile(r'"streamId":"(\w+)"')
+    _file_re = re.compile(r'"file":\s*"([\w\./\\=:\-\?]+)"')
 
-class Mediaklikk(Plugin):
     @classmethod
     def can_handle_url(cls, url):
-        return _stream_url_re.match(url)
+        return cls._url_re.match(url) is not None
 
-    def _get_playlist_url(self):
-        # get the id
-        content = self.session.http.get(self.url)
-        match = _id_re.match(content.text.replace("\n", ""))
-        if not match:
-            return
+    def _get_streams(self):
+        # get the stream id
+        res = self.session.http.get(self.url)
+        m = self._id_re.search(res.text)
+        if not m:
+            raise PluginError("Stream ID could not be extracted.")
 
         # get the m3u8 file url
-        player_url = _stream_player_url.format(match.group(1))
-        content = self.session.http.get(player_url)
-
-        match = _file_re.match(content.text.replace("\n", ""))
-        if match:
-            return match.group(1)
-
-    @Plugin.broken()
-    def _get_streams(self):
-        playlist = self._get_playlist_url()
-        return HLSStream.parse_variant_playlist(self.session, playlist)
+        params = {
+            "video": m.group(1),
+            "noflash": "yes",
+        }
+        res = self.session.http.get(self.PLAYER_URL, params=params)
+        m = self._file_re.search(res.text)
+        if m:
+            url = update_scheme("https://",
+                                m.group(1).replace("\\/", "/"))
+
+            log.debug("URL={0}".format(url))
+            return HLSStream.parse_variant_playlist(self.session, url)
 
 
 __plugin__ = Mediaklikk
diff --git a/src/streamlink_cli/argparser.py b/src/streamlink_cli/argparser.py
index 3958a085..6351fa00 100644
--- a/src/streamlink_cli/argparser.py
+++ b/src/streamlink_cli/argparser.py
@@ -1,4 +1,5 @@
 import argparse
+import numbers
 import re
 from string import printable
 from textwrap import dedent
@@ -44,6 +45,37 @@ class ArgumentParser(argparse.ArgumentParser):
         elif name:
             yield u"--{0}".format(name)
 
+    def _match_argument(self, action, arg_strings_pattern):
+        # - https://github.com/streamlink/streamlink/issues/971
+        # - https://bugs.python.org/issue9334
+
+        # match the pattern for this action to the arg strings
+        nargs_pattern = self._get_nargs_pattern(action)
+        match = argparse._re.match(nargs_pattern, arg_strings_pattern)
+
+        # if no match, see if we can emulate optparse and return the
+        # required number of arguments regardless of their values
+        if match is None:
+            nargs = action.nargs if action.nargs is not None else 1
+            if isinstance(nargs, numbers.Number) and len(arg_strings_pattern) >= nargs:
+                return nargs
+
+        # raise an exception if we weren't able to find a match
+        if match is None:
+            nargs_errors = {
+                None: argparse._('expected one argument'),
+                argparse.OPTIONAL: argparse._('expected at most one argument'),
+                argparse.ONE_OR_MORE: argparse._('expected at least one argument'),
+            }
+            default = argparse.ngettext('expected %s argument',
+                                        'expected %s arguments',
+                                        action.nargs) % action.nargs
+            msg = nargs_errors.get(action.nargs, default)
+            raise argparse.ArgumentError(action, msg)
+
+        # return the number of arguments matched
+        return len(match.group(1))
+
 
 class HelpFormatter(argparse.RawDescriptionHelpFormatter):
     """A nicer help formatter.


Test patch:
diff --git a/tests/test_cmdline.py b/tests/test_cmdline.py
index 8f829e59..cb8ce253 100644
--- a/tests/test_cmdline.py
+++ b/tests/test_cmdline.py
@@ -1,4 +1,3 @@
-import sys
 import os.path
 import unittest
 
@@ -83,6 +82,13 @@ class TestCommandLinePOSIX(CommandLineTestCase):
                         ["/usr/bin/player", "--input-title-format", 'Poker "Stars"', "rtmp://test.se"],
                         passthrough=True)
 
+    def test_single_hyphen_extra_player_args_971(self):
+        """single hyphen params at the beginning of --player-args
+           - https://github.com/streamlink/streamlink/issues/971 """
+        self._test_args(["streamlink", "-p", "/usr/bin/player", "-a", "-v {filename}",
+                         "http://test.se", "test"],
+                        ["/usr/bin/player", "-v", "-"])
+
 
 @unittest.skipIf(not is_win32, "test only applicable on Windows")
 class TestCommandLineWindows(CommandLineTestCase):
@@ -117,6 +123,9 @@ class TestCommandLineWindows(CommandLineTestCase):
                         '''c:\\Program Files\\Player\\player.exe --input-title-format "Poker \\"Stars\\"" \"rtmp://test.se\"''',
                         passthrough=True)
 
-
-if __name__ == "__main__":
-    unittest.main()
+    def test_single_hyphen_extra_player_args_971(self):
+        """single hyphen params at the beginning of --player-args
+           - https://github.com/streamlink/streamlink/issues/971 """
+        self._test_args(["streamlink", "-p", "c:\\Program Files\\Player\\player.exe",
+                         "-a", "-v {filename}", "http://test.se", "test"],
+                        "c:\\Program Files\\Player\\player.exe -v -")