Repository: streamlink/streamlink
Pull request #2310 (2019-02-07 18:26:27)

plugins.mitele: plugin update
- plugin cleanup: removed hls url build (Ref #1337),
  the api returns a correct url at the moment and this is not needed.
- better error messages
- added support for new channels

closes https://github.com/streamlink/streamlink/issues/2281


Patch:
diff --git a/src/streamlink/plugins/mitele.py b/src/streamlink/plugins/mitele.py
index 5be5fa10..8e0d62f1 100644
--- a/src/streamlink/plugins/mitele.py
+++ b/src/streamlink/plugins/mitele.py
@@ -1,39 +1,26 @@
-from __future__ import print_function
-
+import logging
 import re
 
-from streamlink import NoStreamsError
-from streamlink.compat import urljoin
 from streamlink.plugin import Plugin
 from streamlink.plugin.api import useragents
 from streamlink.plugin.api import validate
 from streamlink.stream import HLSStream
 from streamlink.utils import parse_json
 
+log = logging.getLogger(__name__)
 
-class Mitele(Plugin):
-    _url_re = re.compile(r"https?://(?:www\.)?mitele\.es/directo/(?P<channel>\w+)")
-    _suffix_re = re.compile(r"""acl=(?P<path>[^"'*]+)""")
-
-    # For more informations see:
-    # https://github.com/streamlink/streamlink/issues/1337
-    livehlsdai = "https://livehlsdai-i.akamaihd.net"
-    mdslivehls = "https://mdslivehls-i.akamaihd.net"
 
-    _channel_domains = {
-        "bemad": mdslivehls,
-        "boing": mdslivehls,
-        "cuatro": livehlsdai,
-        "divinity": mdslivehls,
-        "energy": mdslivehls,
-        "fdf": mdslivehls,
-        "telecinco": livehlsdai,
-    }
+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"
 
-    pdata_schema = validate.Schema(
+    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": [{
@@ -43,81 +30,56 @@ class Mitele(Plugin):
             },
             validate.get("locations"),
             validate.get(0),
+        ),
+        error_schema,
+    ))
+    gate_schema = validate.Schema(
+        validate.transform(parse_json),
+        validate.any(
+            {
+                "mimeType": validate.text,
+                "stream": validate.url(),
+            },
+            error_schema,
         )
     )
 
     def __init__(self, url):
         super(Mitele, self).__init__(url)
-        self.headers = {
+        self.session.http.headers.update({
             "User-Agent": useragents.FIREFOX,
             "Referer": self.url
-        }
+        })
 
     @classmethod
     def can_handle_url(cls, url):
-        m = cls._url_re.match(url)
-        return m and m.group("channel") in cls._channel_domains.keys()
-
-    def get_pdata(self, channel):
-        """
-        Get the params for the post request
-        :param channel: channel name
-        :return: "gcp" and "ogn"
-        """
-        res = self.session.http.get(self.pdata_url.format(channel=channel))
-        return parse_json(res.text, schema=self.pdata_schema)
-
-    def create_hls_url(self, suffix):
-        """
-        creates a valid hls_url
-        :param suffix: url session params
-        :return: hls_url
-        """
-        m = self._suffix_re.search(suffix)
-        if not m:
-            return
-        self.logger.debug("create hls_url from suffix")
-
-        channel = self._url_re.match(self.url).group("channel")
-        domain = self._channel_domains[channel]
-        path = m.group("path")
-        path_suffix = "master.m3u8?{suffix}".format(suffix=suffix)
-
-        hls_url = urljoin(domain, path)
-        hls_url = urljoin(hls_url, path_suffix)
-        return hls_url
-
-    def get_stream_url(self, data):
-        """
-        Get the hls_url from the post request
-        :param data: dict with "gcp" and "ogn"
-        :return: hls_url
-        """
-        try:
-            res = self.session.http.post(self.gate_url, headers=self.headers, data=data)
-        except Exception as e:
-            if "403" in str(e):
-                self.logger.error("This Video is Not Available in Your Country.")
-            raise NoStreamsError(self.url)
-
-        r_data = parse_json(res.text)
-        hls_url = r_data.get("stream")
-        suffix = r_data.get("suffix")
-
-        if hls_url is None and suffix:
-            hls_url = self.create_hls_url(suffix)
-        return hls_url
+        return cls._url_re.match(url) is not None
 
     def _get_streams(self):
         channel = self._url_re.match(self.url).group("channel")
 
-        pdata = self.get_pdata(channel)
-        hls_url = self.get_stream_url(pdata)
+        pdata = self.session.http.get(self.pdata_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"]))
+            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"]))
+            return
 
-        if hls_url:
-            self.logger.debug("HLS URL: {0}".format(hls_url))
-            for s in HLSStream.parse_variant_playlist(self.session, hls_url, headers=self.headers, name_fmt="{pixels}_{bitrate}").items():
-                yield s
+        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
 
 
 __plugin__ = Mitele


Test patch:
diff --git a/tests/plugins/test_mitele.py b/tests/plugins/test_mitele.py
index 502c75a4..7388df89 100644
--- a/tests/plugins/test_mitele.py
+++ b/tests/plugins/test_mitele.py
@@ -13,13 +13,14 @@ class TestPluginMitele(unittest.TestCase):
             "http://www.mitele.es/directo/energy",
             "http://www.mitele.es/directo/fdf",
             "http://www.mitele.es/directo/telecinco",
+            "https://www.mitele.es/directo/gh-duo-24h-senal-1",
+            "https://www.mitele.es/directo/gh-duo-24h-senal-2",
         ]
         for url in should_match:
             self.assertTrue(Mitele.can_handle_url(url))
 
         should_not_match = [
             "http://www.mitele.es",
-            "http://www.mitele.es/directo/random_channel",
         ]
         for url in should_not_match:
             self.assertFalse(Mitele.can_handle_url(url))