Repository: streamlink/streamlink
Pull request #2888 (2020-04-12 06:34:59)

plugins.zeenews: new plugin for https://zeenews.india.com/live-tv
`streamlink https://zeenews.india.com/live-tv best`

https://en.wikipedia.org/wiki/Zee_News

closes https://github.com/streamlink/streamlink/issues/2566

codecov[bot]: # [Codecov](https://codecov.io/gh/streamlink/streamlink/pull/2888?src=pr&el=h1) Report
> Merging [#2888](https://codecov.io/gh/streamlink/streamlink/pull/2888?src=pr&el=desc) into [master](https://codecov.io/gh/streamlink/streamlink/commit/2007b32102db68b738c655d382976e55d0d686c3&el=desc) will **increase** coverage by `0.01%`.
> The diff coverage is `71.42%`.


```diff
@@            Coverage Diff             @@
##           master    #2888      +/-   ##
==========================================
+ Coverage   52.68%   52.70%   +0.01%     
==========================================
  Files         250      251       +1     
  Lines       15701    15722      +21     
==========================================
+ Hits         8272     8286      +14     
- Misses       7429     7436       +7     
```


Patch:
diff --git a/docs/plugin_matrix.rst b/docs/plugin_matrix.rst
index 53f543bd..e33c51bc 100644
--- a/docs/plugin_matrix.rst
+++ b/docs/plugin_matrix.rst
@@ -299,6 +299,7 @@ zattoo                  - zattoo.com         Yes   Yes
                         - www.vtxtv.ch
                         - www.1und1.tv
 zdf_mediathek           zdf.de               Yes   Yes   Streams may be geo-restricted to Germany.
+zeenews                 zeenews.india.com    Yes   No
 zengatv                 zengatv.com          Yes   No
 zhanqi                  zhanqi.tv            Yes   No
 ======================= ==================== ===== ===== ===========================
diff --git a/src/streamlink/plugins/zattoo.py b/src/streamlink/plugins/zattoo.py
index e04be31b..56404b2e 100644
--- a/src/streamlink/plugins/zattoo.py
+++ b/src/streamlink/plugins/zattoo.py
@@ -50,7 +50,7 @@ class Zattoo(Plugin):
         )/
         (?:
             (?:
-                recordings\?recording=
+                recording(?:s\?recording=|/)
                 |
                 (?:ondemand/)?(?:watch/(?:[^/\s]+)(?:/[^/]+/))
             )(?P<recording_id>\d+)
@@ -155,7 +155,11 @@ class Zattoo(Plugin):
 
         # a new session is required for the app_token
         self.session.http.cookies = cookiejar_from_dict({})
-        res = self.session.http.get(self.base_url)
+        if self.base_url == 'https://zattoo.com':
+            app_token_url = 'https://zattoo.com/int/'
+        else:
+            app_token_url = self.base_url
+        res = self.session.http.get(app_token_url)
         match = self._app_token_re.search(res.text)
 
         app_token = match.group(1)
diff --git a/src/streamlink/plugins/zeenews.py b/src/streamlink/plugins/zeenews.py
new file mode 100644
index 00000000..30acd425
--- /dev/null
+++ b/src/streamlink/plugins/zeenews.py
@@ -0,0 +1,31 @@
+import logging
+import re
+
+from streamlink.plugin import Plugin
+from streamlink.stream import HLSStream
+
+log = logging.getLogger(__name__)
+
+
+class ZeeNews(Plugin):
+    _url_re = re.compile(r'https?://zeenews\.india\.com/live-tv')
+
+    HLS_URL = 'https://z5ams.akamaized.net/zeenews/index.m3u8{0}'
+    TOKEN_URL = 'https://useraction.zee5.com/token/live.php'
+
+    @classmethod
+    def can_handle_url(cls, url):
+        return cls._url_re.match(url) is not None
+
+    def get_title(self):
+        return 'Zee News'
+
+    def _get_streams(self):
+        res = self.session.http.get(self.TOKEN_URL)
+        token = self.session.http.json(res)['video_token']
+        log.debug('video_token: {0}'.format(token))
+        for s in HLSStream.parse_variant_playlist(self.session, self.HLS_URL.format(token)).items():
+            yield s
+
+
+__plugin__ = ZeeNews


Test patch:
diff --git a/tests/plugins/test_zattoo.py b/tests/plugins/test_zattoo.py
index fe0adbab..2af55783 100644
--- a/tests/plugins/test_zattoo.py
+++ b/tests/plugins/test_zattoo.py
@@ -39,15 +39,17 @@ class TestPluginZattoo(unittest.TestCase):
             "https://zattoo.com/ondemand/watch/srf_zwei/110223896-die-schweizermacher/52845783/1455130800000"
             + "/1455137700000/6900000",
             "https://zattoo.com/watch/tve/130920738-viaje-al-centro-de-la-tele/96847859/1508777100000/1508779800000/0",
+            "https://zattoo.com/recording/193074536",
             "https://zattoo.com/recordings?recording=186466965"
         ]
         for url in should_match:
-            self.assertTrue(Zattoo.can_handle_url(url))
+            self.assertTrue(Zattoo.can_handle_url(url), url)
 
+    def test_can_handle_url_negative(self):
         should_not_match = [
             "https://ewe.de",
             "https://netcologne.de",
             "https://zattoo.com"
         ]
         for url in should_not_match:
-            self.assertFalse(Zattoo.can_handle_url(url))
+            self.assertFalse(Zattoo.can_handle_url(url), url)
diff --git a/tests/plugins/test_zeenews.py b/tests/plugins/test_zeenews.py
new file mode 100644
index 00000000..66c411bd
--- /dev/null
+++ b/tests/plugins/test_zeenews.py
@@ -0,0 +1,20 @@
+import unittest
+
+from streamlink.plugins.zeenews import ZeeNews
+
+
+class TestPluginZeeNews(unittest.TestCase):
+    def test_can_handle_url(self):
+        should_match = [
+            'https://zeenews.india.com/live-tv',
+            'https://zeenews.india.com/live-tv/embed',
+        ]
+        for url in should_match:
+            self.assertTrue(ZeeNews.can_handle_url(url), url)
+
+    def test_can_handle_url_negative(self):
+        should_not_match = [
+            'https://example.com/index.html',
+        ]
+        for url in should_not_match:
+            self.assertFalse(ZeeNews.can_handle_url(url), url)