Repository: streamlink/streamlink

Issue:
[plugin issue] plugin.vidio.com / can't handle stream URLs anymore
- [x] This is a bug report.
- [ ] This is a feature request.
- [ ] This is a plugin (improvement) request.
- [ ] I have read the contribution guidelines.

### Description
plugin handling of https://www.vidio.com/live  URls not working anymore due to changes at provided stream structure

### Expected / Actual behavior
streamlink -l debug www.vidio.com/live/665-rcti-tv-stream
[cli][debug] OS:         Windows 10
[cli][debug] Python:     3.5.2
[cli][debug] Streamlink: 0.12.1
[cli][debug] Requests(2.18.4), Socks(1.6.7), Websocket(0.47.0)
[cli][info] Found matching plugin vidio for URL www.vidio.com/live/665-rcti-tv-stream
[plugin.vidio][debug] HLS URL: https://kmklive-lh.akamaihd.net/i/rcti_ta_regular@94478/master.m3u8
error: Unable to open URL: https://kmklive-lh.akamaihd.net/i/rcti_ta_regular@94478/master.m3u8 (403 Client Error: Forbidden for url: https://kmklive-lh.akamaihd.net/i/rcti_ta_regular@94478/master.m3u8)



Discussion:
Looks like there are some extra steps required to get the actual stream url. Seems pretty straightforward though :)

Resolving patch:
diff --git a/src/streamlink/plugins/vidio.py b/src/streamlink/plugins/vidio.py
--- a/src/streamlink/plugins/vidio.py
+++ b/src/streamlink/plugins/vidio.py
@@ -1,36 +1,61 @@
-'''
+"""
 Plugin for vidio.com
 - https://www.vidio.com/live/5075-dw-tv-stream
 - https://www.vidio.com/watch/766861-5-rekor-fantastis-zidane-bersama-real-madrid
-'''
+"""
 import re
 
 from streamlink.plugin import Plugin
-from streamlink.plugin.api import http
+from streamlink.plugin.api import http, useragents, validate
 from streamlink.stream import HLSStream
-
-_url_re = re.compile(r"https?://(?:www\.)?vidio\.com/(?:en/)?(?P<type>live|watch)/(?P<id>\d+)-(?P<name>[^/?#&]+)")
-_playlist_re = re.compile(r'''hls-url=["'](?P<url>[^"']+)["']''')
+from streamlink.utils import parse_json
 
 
 class Vidio(Plugin):
+    _url_re = re.compile(r"https?://(?:www\.)?vidio\.com/(?:en/)?(?P<type>live|watch)/(?P<id>\d+)-(?P<name>[^/?#&]+)")
+    _playlist_re = re.compile(r'''hls-url=["'](?P<url>[^"']+)["']''')
+    _data_id_re = re.compile(r'''meta\s+data-id=["'](?P<id>[^"']+)["']''')
+
+    csrf_tokens_url = "https://www.vidio.com/csrf_tokens"
+    tokens_url = "https://www.vidio.com/live/{id}/tokens"
+    token_schema = validate.Schema(validate.transform(parse_json),
+                                   {"token": str},
+                                   validate.get("token"))
+
     @classmethod
     def can_handle_url(cls, url):
-        return _url_re.match(url)
+        return cls._url_re.match(url)
+
+    def get_csrf_tokens(self):
+        return http.get(self.csrf_tokens_url,
+                        schema=self.token_schema)
+
+    def get_url_tokens(self, stream_id):
+        self.logger.debug("Getting stream tokens")
+        csrf_token = self.get_csrf_tokens()
+        return http.post(self.tokens_url.format(id=stream_id),
+                         files={"authenticity_token": (None, csrf_token)},
+                         headers={"User-Agent": useragents.CHROME,
+                                  "Referer": self.url},
+                         schema=self.token_schema)
 
     def _get_streams(self):
         res = http.get(self.url)
 
-        match = _playlist_re.search(res.text)
-        if match is None:
-            return
+        plmatch = self._playlist_re.search(res.text)
+        idmatch = self._data_id_re.search(res.text)
+
+        hls_url = plmatch and plmatch.group("url")
+        stream_id = idmatch and idmatch.group("id")
 
-        url = match.group('url')
+        tokens = self.get_url_tokens(stream_id)
 
-        if url:
-            self.logger.debug('HLS URL: {0}'.format(url))
-            for s in HLSStream.parse_variant_playlist(self.session, url).items():
-                yield s
+        if hls_url:
+            self.logger.debug("HLS URL: {0}".format(hls_url))
+            self.logger.debug("Tokens: {0}".format(tokens))
+            return HLSStream.parse_variant_playlist(self.session, hls_url+"?"+tokens,
+                                                    headers={"User-Agent": useragents.CHROME,
+                                                             "Referer": self.url})
 
 
 __plugin__ = Vidio


Test patch: