Repository: streamlink/streamlink

Issue:
vtvgo plugin issue
<!--
Thanks for reporting a plugin issue!
USE THE TEMPLATE. Otherwise your plugin issue may be rejected.

First, see the contribution guidelines:
https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink

Also check the list of open and closed plugin issues:
https://github.com/streamlink/streamlink/issues?q=is%3Aissue+label%3A%22plugin+issue%22

Please see the text preview to avoid unnecessary formatting errors.
-->


## Plugin Issue

<!-- Replace the space character between the square brackets with an x in order to check the boxes -->
- [x] This is a plugin issue and I have read the contribution guidelines.
- [x] I am using the latest development version from the master branch.

### Description

<!-- Explain the plugin issue as thoroughly as you can. -->
I use this command `streamlink -l trace https://vtvgo.vn/xem-truc-tuyen-kenh-vtv1-1.html best`

And stops with this error

```
[09:47:36.311010][cli][debug] OS:         macOS 10.15.7
[09:47:36.311282][cli][debug] Python:     3.9.1
[09:47:36.311364][cli][debug] Streamlink: 2.0.0
[09:47:36.311431][cli][debug] Requests(2.25.1), Socks(1.7.1), Websocket(0.57.0)
[09:47:36.311548][cli][info] Found matching plugin vtvgo for URL https://vtvgo.vn/xem-truc-tuyen-kenh-vtv1-1.html
[09:47:37.476177][plugins.vtvgo][trace] <Response [200]>
[09:47:37.476668][plugins.vtvgo][trace] [('id', '1'), ('type_id', '1'), ('time', '1613033257'), ('token', '1613033257.57e947cb0be94a48835ba7219cf4a399'), ('token', 'VTVGO_____VTVGO_____'), ('time', '1613033257')]
Traceback (most recent call last):
  File "/usr/local/bin/streamlink", line 33, in <module>
    sys.exit(load_entry_point('streamlink==2.0.0', 'console_scripts', 'streamlink')())
  File "/usr/local/Cellar/streamlink/2.0.0_1/libexec/lib/python3.9/site-packages/streamlink_cli/main.py", line 1052, in main
    handle_url()
  File "/usr/local/Cellar/streamlink/2.0.0_1/libexec/lib/python3.9/site-packages/streamlink_cli/main.py", line 580, in handle_url
    streams = fetch_streams(plugin)
  File "/usr/local/Cellar/streamlink/2.0.0_1/libexec/lib/python3.9/site-packages/streamlink_cli/main.py", line 459, in fetch_streams
    return plugin.streams(stream_types=args.stream_types,
  File "/usr/local/Cellar/streamlink/2.0.0_1/libexec/lib/python3.9/site-packages/streamlink/plugin/plugin.py", line 317, in streams
    ostreams = self._get_streams()
  File "/usr/local/Cellar/streamlink/2.0.0_1/libexec/lib/python3.9/site-packages/streamlink/plugins/vtvgo.py", line 38, in _get_streams
    hls_url = self.session.http.json(res)['stream_url'][0]
TypeError: list indices must be integers or slices, not str
```

### Additional comments, etc.

I'm not a pro in python, but was able debug this issue.

The plugin expects 4 parameters, but the regex finds 6 parameters on the website.
`[09:47:37.476668][plugins.vtvgo][trace] [('id', '1'), ('type_id', '1'), ('time', '1613033257'), ('token', '1613033257.57e947cb0be94a48835ba7219cf4a399'), ('token', 'VTVGO_____VTVGO_____'), ('time', '1613033257')]`

The last 2 items are redundant and can be removed.

To fix this issue I just added this line to remove the last 2 items.

```diff
params = self._params_re.findall(res.text)
+ del params[-2:]
```

[Love Streamlink? Please consider supporting our collective. Thanks!](https://opencollective.com/streamlink/donate)



Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/vtvgo.py b/src/streamlink/plugins/vtvgo.py
--- a/src/streamlink/plugins/vtvgo.py
+++ b/src/streamlink/plugins/vtvgo.py
@@ -1,19 +1,37 @@
 import logging
 import re
 
-from streamlink.exceptions import PluginError
 from streamlink.plugin import Plugin
+from streamlink.plugin.api import validate
+from streamlink.plugin.api.utils import itertags
 from streamlink.stream import HLSStream
+from streamlink.utils import parse_json
 
 log = logging.getLogger(__name__)
 
 
 class VTVgo(Plugin):
-
     AJAX_URL = 'https://vtvgo.vn/ajax-get-stream'
 
     _url_re = re.compile(r'https://vtvgo\.vn/xem-truc-tuyen-kenh-')
-    _params_re = re.compile(r'''var\s(?P<key>(?:type_)?id|time|token)\s*=\s*["']?(?P<value>[^"']+)["']?;''')
+    _params_re = re.compile(r'''var\s+(?P<key>(?:type_)?id|time|token)\s*=\s*["']?(?P<value>[^"']+)["']?;''')
+
+    _schema_params = validate.Schema(
+        validate.transform(lambda html: next(tag.text for tag in itertags(html, "script") if "setplayer(" in tag.text)),
+        validate.transform(_params_re.findall),
+        [
+            ("id", int),
+            ("type_id", str),
+            ("time", str),
+            ("token", str)
+        ]
+    )
+    _schema_stream_url = validate.Schema(
+        validate.transform(parse_json),
+        {"stream_url": [validate.url()]},
+        validate.get("stream_url"),
+        validate.get(0)
+    )
 
     @classmethod
     def can_handle_url(cls, url):
@@ -25,17 +43,10 @@ def _get_streams(self):
             'Referer': self.url,
             'X-Requested-With': 'XMLHttpRequest',
         })
-        res = self.session.http.get(self.url)
-
-        params = self._params_re.findall(res.text)
-        if not params:
-            raise PluginError('No POST data')
-        elif len(params) != 4:
-            raise PluginError('Not enough POST data: {0!r}'.format(params))
+        params = self.session.http.get(self.url, schema=self._schema_params)
 
         log.trace('{0!r}'.format(params))
-        res = self.session.http.post(self.AJAX_URL, data=dict(params))
-        hls_url = self.session.http.json(res)['stream_url'][0]
+        hls_url = self.session.http.post(self.AJAX_URL, data=dict(params), schema=self._schema_stream_url)
 
         return HLSStream.parse_variant_playlist(self.session, hls_url)
 


Test patch: