Repository: streamlink/streamlink

Issue:
Mitele changed
## Plugin Issue

<!-- Replace [ ] with [x] in order to check the box -->
- [x] This is a plugin issue and I have read the contribution guidelines.

Mitele has changed its code.

### Description

Plugin not able to handle the new configuration.


### Log output

<!--
TEXT LOG OUTPUT IS REQUIRED for a plugin issue!
Use the `--loglevel debug` parameter and avoid using parameters which suppress log output.
https://streamlink.github.io/cli.html#cmdoption-l

Make sure to **remove usernames and passwords**
You can copy the output to https://gist.github.com/ or paste it below.

Don't post screenshots of the log output and instead copy the text from your terminal application.
-->

```
[cli][info] Found matching plugin mitele for URL https://mitele.es/directo/telecinco
error: Unable to open URL: https://gatekeeper.mediaset.es (HTTPSConnectionPool(host='gatekeeper.mediaset.es', port=443): Max retries exceeded with url: / (Caused by NewConnectionError('<urllib3.connection.VerifiedHTTPSConnection object at 0x7ff07c967220>: Failed to establish a new connection: [Errno -2] Name or service not known')))
```
### Additional comments, etc.
My english and knowledge are poor, sorry.


Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/mitele.py b/src/streamlink/plugins/mitele.py
--- a/src/streamlink/plugins/mitele.py
+++ b/src/streamlink/plugins/mitele.py
@@ -4,7 +4,8 @@
 from streamlink.plugin import Plugin
 from streamlink.plugin.api import validate
 from streamlink.stream import HLSStream
-from streamlink.utils import parse_json
+from streamlink.utils import parse_json, parse_qsd
+from streamlink.utils.url import update_qsd
 
 log = logging.getLogger(__name__)
 
@@ -12,40 +13,42 @@
 class Mitele(Plugin):
     _url_re = re.compile(r"https?://(?:www\.)?mitele\.es/directo/(?P<channel>[\w-]+)")
 
-    pdata_url = "https://indalo.mediaset.es/mmc-player/api/mmc/v1/{channel}/live/html5.json"
-    gate_url = "https://gatekeeper.mediaset.es"
+    caronte_url = "https://caronte.mediaset.es/delivery/channel/mmc/{channel}/mtweb"
+    gbx_url = "https://mab.mediaset.es/1.0.0/get?oid=mtmw&eid=%2Fapi%2Fmtmw%2Fv2%2Fgbx%2Fmtweb%2Flive%2Fmmc%2F{channel}"
 
-    error_schema = validate.Schema({
-        "code": validate.any(validate.text, int),
-        "message": validate.text,
-    })
-    pdata_schema = validate.Schema(validate.transform(parse_json), validate.any(
-        validate.all(
-            {
-                "locations": [{
-                    "gcp": validate.text,
-                    "ogn": validate.any(None, validate.text),
-                }],
-            },
-            validate.get("locations"),
-            validate.get(0),
-        ),
+    error_schema = validate.Schema({"code": int})
+    caronte_schema = validate.Schema(validate.transform(parse_json), validate.any(
+        {
+            "cerbero": validate.url(),
+            "bbx": str,
+            "dls": [{
+                "lid": validate.all(int, validate.transform(str)),
+                "format": validate.any("hls", "dash", "smooth"),
+                "stream": validate.url(),
+                validate.optional("assetKey"): str,
+                "drm": bool,
+            }],
+        },
         error_schema,
     ))
-    gate_schema = validate.Schema(
+    gbx_schema = validate.Schema(
+        validate.transform(parse_json),
+        {"gbx": str},
+        validate.get("gbx")
+    )
+    cerbero_schema = validate.Schema(
         validate.transform(parse_json),
         validate.any(
-            {
-                "mimeType": validate.text,
-                "stream": validate.url(),
-            },
+            validate.all(
+                {"tokens": {str: {"cdn": str}}},
+                validate.get("tokens")
+            ),
             error_schema,
         )
     )
-
-    def __init__(self, url):
-        super().__init__(url)
-        self.session.http.headers.update({"Referer": self.url})
+    token_errors = {
+        4038: "User has no privileges"
+    }
 
     @classmethod
     def can_handle_url(cls, url):
@@ -54,28 +57,37 @@ def can_handle_url(cls, url):
     def _get_streams(self):
         channel = self._url_re.match(self.url).group("channel")
 
-        pdata = self.session.http.get(self.pdata_url.format(channel=channel),
+        pdata = self.session.http.get(self.caronte_url.format(channel=channel),
                                       acceptable_status=(200, 403, 404),
-                                      schema=self.pdata_schema)
-        log.trace("{0!r}".format(pdata))
-        if pdata.get("code"):
-            log.error("{0} - {1}".format(pdata["code"], pdata["message"]))
+                                      schema=self.caronte_schema)
+        gbx = self.session.http.get(self.gbx_url.format(channel=channel),
+                                    schema=self.gbx_schema)
+
+        if "code" in pdata:
+            log.error("error getting pdata: {}".format(pdata["code"]))
             return
 
-        gdata = self.session.http.post(self.gate_url,
-                                       acceptable_status=(200, 403, 404),
-                                       data=pdata,
-                                       schema=self.gate_schema)
-        log.trace("{0!r}".format(gdata))
-        if gdata.get("code"):
-            log.error("{0} - {1}".format(gdata["code"], gdata["message"]))
+        tokens = self.session.http.post(pdata["cerbero"],
+                                        acceptable_status=(200, 403, 404),
+                                        json={"bbx": pdata["bbx"], "gbx": gbx},
+                                        headers={"origin": "https://www.mitele.es"},
+                                        schema=self.cerbero_schema)
+
+        if "code" in tokens:
+            log.error("Could not get stream tokens: {} ({})".format(tokens["code"],
+                                                                    self.token_errors.get(tokens["code"], "unknown error")))
             return
 
-        log.debug("Stream: {0} ({1})".format(gdata["stream"], gdata.get("mimeType", "n/a")))
-        for s in HLSStream.parse_variant_playlist(self.session,
-                                                  gdata["stream"],
-                                                  name_fmt="{pixels}_{bitrate}").items():
-            yield s
+        for stream in pdata["dls"]:
+            if stream["drm"]:
+                log.warning("Stream may be protected by DRM")
+            else:
+                sformat = stream.get("format")
+                log.debug("Stream: {} ({})".format(stream["stream"], sformat or "n/a"))
+                cdn_token = tokens.get(stream["lid"], {}).get("cdn", "")
+                qsd = parse_qsd(cdn_token)
+                if sformat == "hls":
+                    yield from HLSStream.parse_variant_playlist(self.session, update_qsd(stream["stream"], qsd)).items()
 
 
 __plugin__ = Mitele


Test patch: