Repository: streamlink/streamlink

Issue:
Plugin App17 cannot fetch any stream
## Plugin Issue

<!-- Replace [ ] with [x] in order to check the box -->
- [x] This is a plugin issue and I have read the contribution guidelines.


### Description

`Stream currently unavailable.`
The output of the Streamlink is always the same. Even if the streamer is streaming online.

### Reproduction steps / Explicit stream URLs to test

<!-- How can we reproduce this? Please note the exact steps below using the list format supplied. If you need more steps please add them. -->

Paste any URL (e.g., `https://17.live/live/{any stream ID}`) and execute the command.


### 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.
-->

```
C:\>streamlink https://17.live/live/7000362 -l trace
[22:44:25,408][cli][debug] OS:         Windows 10
[22:44:25,409][cli][debug] Python:     3.6.6
[22:44:25,410][cli][debug] Streamlink: 1.4.1
[22:44:25,410][cli][debug] Requests(2.23.0), Socks(1.7.1), Websocket(0.57.0)
[22:44:25,410][cli][info] Found matching plugin app17 for URL https://17.live/live/7000362
[22:44:25,735][plugin.app17][info] Stream currently unavailable.
error: No playable streams found on this URL: https://17.live/live/7000362
```


### Additional comments, screenshots, etc.

[screenshot](https://imgur.com/MFn7K0y)



Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/app17.py b/src/streamlink/plugins/app17.py
--- a/src/streamlink/plugins/app17.py
+++ b/src/streamlink/plugins/app17.py
@@ -1,35 +1,49 @@
+import logging
 import re
 
 from streamlink.plugin import Plugin
-from streamlink.plugin.api import useragents
+from streamlink.plugin.api import useragents, validate
 from streamlink.stream import HLSStream, RTMPStream, HTTPStream
 
-API_URL = "https://api-dsa.17app.co/api/v1/liveStreams/getLiveStreamInfo"
-
-_url_re = re.compile(r"https://17.live/live/(?P<channel>[^/&?]+)")
-_status_re = re.compile(r'\\"closeBy\\":\\"\\"')
-_rtmp_re = re.compile(r'\\"url\\"\s*:\s*\\"(.+?)\\"')
+log = logging.getLogger(__name__)
 
 
 class App17(Plugin):
+    _url_re = re.compile(r"https://17.live/live/(?P<channel>[^/&?]+)")
+    API_URL = "https://api-dsa.17app.co/api/v1/lives/{0}/viewers/alive"
+
+    _api_schema = validate.Schema(
+        {
+            "rtmpUrls": [{
+                validate.optional("provider"): validate.any(int, None),
+                "url": validate.url(),
+            }],
+        },
+        validate.get("rtmpUrls"),
+    )
+
     @classmethod
     def can_handle_url(cls, url):
-        return _url_re.match(url)
+        return cls._url_re.match(url) is not None
 
     def _get_streams(self):
-        match = _url_re.match(self.url)
+        match = self._url_re.match(self.url)
         channel = match.group("channel")
 
         self.session.http.headers.update({'User-Agent': useragents.CHROME, 'Referer': self.url})
 
-        payload = '{"liveStreamID": "%s"}' % (channel)
-        res = self.session.http.post(API_URL, data=payload)
-        status = _status_re.search(res.text)
-        if not status:
-            self.logger.info("Stream currently unavailable.")
+        data = '{"liveStreamID":"%s"}' % (channel)
+
+        try:
+            res = self.session.http.post(self.API_URL.format(channel), data=data)
+            res_json = self.session.http.json(res, schema=self._api_schema)
+            log.trace("{0!r}".format(res_json))
+            http_url = res_json[0]["url"]
+        except Exception as e:
+            log.info("Stream currently unavailable.")
+            log.debug(str(e))
             return
 
-        http_url = _rtmp_re.search(res.text).group(1)
         https_url = http_url.replace("http:", "https:")
         yield "live", HTTPStream(self.session, https_url)
 
@@ -47,11 +61,16 @@ def _get_streams(self):
         else:
             hls_url = http_url.replace("live-hdl", "live-hls").replace(".flv", ".m3u8")
 
-        s = []
-        for s in HLSStream.parse_variant_playlist(self.session, hls_url).items():
-            yield s
+        s = HLSStream.parse_variant_playlist(self.session, hls_url)
         if not s:
             yield "live", HLSStream(self.session, hls_url)
+        else:
+            if len(s) == 1:
+                for _n, _s in s.items():
+                    yield "live", _s
+            else:
+                for _s in s.items():
+                    yield _s
 
 
 __plugin__ = App17


Test patch: