Repository: streamlink/streamlink

Issue:
plugins.rotana: Plugin is broken
### Checklist

- [X] This is a plugin issue and not a different kind of issue
- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)
- [X] [I have checked the list of open and recently closed plugin issues](https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22plugin+issue%22)
- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)

### Streamlink version

Latest stable release

### Description

The plugin no longer extracts the m3u8

### Debug log

```text
~$ streamlink https://rotana.net/live-clip best --loglevel debug 
[cli][debug] OS:         macOS 12.3.0
[cli][debug] Python:     3.10.2
[cli][debug] Streamlink: 3.2.0
[cli][debug] Requests(2.27.1), Socks(1.7.1), Websocket(1.3.1)
[cli][debug] Arguments:
[cli][debug]  url=https://rotana.net/live-clip
[cli][debug]  stream=['best']
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin rotana for URL https://rotana.net/live-clip
[plugins.rotana][debug] No video URL found.
error: No playable streams found on this URL: https://rotana.net/live-clip
~$
```



Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/hiplayer.py b/src/streamlink/plugins/hiplayer.py
new file mode 100644
--- /dev/null
+++ b/src/streamlink/plugins/hiplayer.py
@@ -0,0 +1,102 @@
+"""
+$description United Arab Emirates CDN hosting live content for various websites in The Middle East.
+$url cnbcarabia.com
+$url media.gov.kw
+$url rotana.net
+$type live
+$region various
+"""
+
+import base64
+import logging
+import re
+
+from streamlink.plugin import Plugin, pluginmatcher
+from streamlink.plugin.api import validate
+from streamlink.stream.hls import HLSStream
+
+log = logging.getLogger(__name__)
+
+
+@pluginmatcher(re.compile(r"""
+    https?://(?:www\.)?
+    (
+        cnbcarabia\.com
+    |
+        media\.gov\.kw
+    |
+        rotana\.net
+    )
+""", re.VERBOSE))
+class HiPlayer(Plugin):
+    DAI_URL = "https://pubads.g.doubleclick.net/ssai/event/{0}/streams"
+    js_url_re = re.compile(r"""['"](https://hiplayer.hibridcdn.net/l/[^'"]+)['"]""")
+    base64_data_re = re.compile(r"i\s*=\s*\[(.*)\]\.join")
+
+    def _get_streams(self):
+        js_url = self.session.http.get(
+            self.url,
+            schema=validate.Schema(
+                validate.parse_html(),
+                validate.xml_xpath_string(".//script[contains(text(), 'https://hiplayer.hibridcdn.net/l/')]/text()"),
+                validate.any(
+                    None,
+                    validate.all(
+                        validate.transform(self.js_url_re.search),
+                        validate.any(None, validate.all(validate.get(1), validate.url())),
+                    ),
+                ),
+            ),
+        )
+
+        if not js_url:
+            return
+
+        log.debug(f"JS URL={js_url}")
+
+        data = self.session.http.get(
+            js_url,
+            schema=validate.Schema(
+                validate.transform(self.base64_data_re.search),
+                validate.any(
+                    None,
+                    validate.all(
+                        validate.get(1),
+                        validate.transform(lambda s: re.sub(r"['\", ]", "", s)),
+                        validate.transform(lambda s: base64.b64decode(s)),
+                        validate.parse_json(),
+                        validate.any(
+                            None,
+                            {
+                                "daiEnabled": bool,
+                                "daiAssetKey": str,
+                                "daiApiKey": str,
+                                "streamUrl": validate.any(validate.url(), ""),
+                            },
+                        ),
+                    ),
+                ),
+            ),
+        )
+
+        hls_url = data["streamUrl"]
+
+        if data["daiEnabled"]:
+            log.debug("daiEnabled=true")
+            hls_url = self.session.http.post(
+                self.DAI_URL.format(data['daiAssetKey']),
+                data={"api-key": data["daiApiKey"]},
+                schema=validate.Schema(
+                    validate.parse_json(),
+                    {
+                        "stream_manifest": validate.url(),
+                    },
+                    validate.get("stream_manifest"),
+                ),
+            )
+
+        if hls_url:
+            return HLSStream.parse_variant_playlist(self.session, hls_url)
+
+
+__plugin__ = HiPlayer


Test patch:
diff --git a/tests/plugins/test_hiplayer.py b/tests/plugins/test_hiplayer.py
new file mode 100644
--- /dev/null
+++ b/tests/plugins/test_hiplayer.py
@@ -0,0 +1,15 @@
+from streamlink.plugins.hiplayer import HiPlayer
+from tests.plugins import PluginCanHandleUrl
+
+
+class TestPluginCanHandleUrlHiPlayer(PluginCanHandleUrl):
+    __plugin__ = HiPlayer
+
+    should_match = [
+        "https://www.cnbcarabia.com/any",
+        "https://www.cnbcarabia.com/any/path",
+        "https://www.media.gov.kw/any",
+        "https://www.media.gov.kw/any/path",
+        "https://rotana.net/any",
+        "https://rotana.net/any/path",
+    ]