Repository: streamlink/streamlink

Issue:
plugins.vk: fixes required
### 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 build from the master branch

### Description

Needs support for the web application firewall cookie.

~Seems necessary to add all parameters to the API POST data in `_get_streams()` now.~

ref: https://github.com/streamlink/streamlink/pull/4613#issuecomment-1173040359


### Debug log

```text
$ streamlink -l debug https://vk.com/video-211154316_456239169
[cli][debug] OS:         Linux-4.9.0-18-amd64-x86_64-with-debian-9.13
[cli][debug] Python:     3.7.3
[cli][debug] Streamlink: 4.1.0+45.gb277114d
[cli][debug] Dependencies:
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.9.1
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.15.0
[cli][debug]  PySocks: 1.7.1
[cli][debug]  requests: 2.28.1
[cli][debug]  websocket-client: 1.3.3
[cli][debug]  importlib-metadata: 4.12.0
[cli][debug] Arguments:
[cli][debug]  url=https://vk.com/video-211154316_456239169
[cli][debug]  --loglevel=debug
[cli][info] Found matching plugin vk for URL https://vk.com/video-211154316_456239169
[plugins.vk][debug] video ID: -211154316_456239169
[plugins.vk][error] Could not parse API response
error: No playable streams found on this URL: https://vk.com/video-211154316_456239169
```



Discussion:

Resolving patch:
diff --git a/src/streamlink/plugins/vk.py b/src/streamlink/plugins/vk.py
--- a/src/streamlink/plugins/vk.py
+++ b/src/streamlink/plugins/vk.py
@@ -6,6 +6,7 @@
 
 import logging
 import re
+from hashlib import md5
 from urllib.parse import parse_qsl, unquote, urlparse
 
 from streamlink.exceptions import NoStreamsError
@@ -13,6 +14,7 @@
 from streamlink.plugin.api import validate
 from streamlink.stream.dash import DASHStream
 from streamlink.stream.hls import HLSStream
+from streamlink.utils.url import update_qsd
 
 log = logging.getLogger(__name__)
 
@@ -25,6 +27,22 @@
 ))
 class VK(Plugin):
     API_URL = "https://vk.com/al_video.php"
+    HASH_COOKIE = "hash429"
+
+    def _get_cookies(self):
+        def on_response(res, **kwargs):
+            if res.headers.get("x-waf-redirect") == "1":
+                if not res.headers.get("X-WAF-Backend-Status"):
+                    log.debug("Getting WAF cookie")
+                    cookie = res.cookies.get(self.HASH_COOKIE)
+                    key = md5(cookie.encode("utf-8")).hexdigest()
+                    res.headers["Location"] = update_qsd(res.headers["Location"], qsd={"key": key})
+                    return res
+                elif res.headers.get("X-WAF-Backend-Status") == "challenge_success":
+                    self.session.http.cookies.update(res.cookies)
+                    return res
+
+        self.session.http.get("https://vk.com/", hooks={"response": on_response})
 
     def _has_video_id(self):
         return any(m for m in self.matches[:-1])
@@ -56,21 +74,19 @@ def follow_vk_redirect(self):
         raise NoStreamsError(self.url)
 
     def _get_streams(self):
+        self._get_cookies()
         self.follow_vk_redirect()
 
         video_id = self.match.group("video_id")
         if not video_id:
             return
 
-        log.debug(f"video ID: {video_id}")
+        log.debug(f"Video ID: {video_id}")
         try:
             data = self.session.http.post(
                 self.API_URL,
-                params={
-                    "act": "show",
-                    "al": "1",
-                    "video": video_id,
-                },
+                params={"act": "show"},
+                data={"act": "show", "al": "1", "video": video_id},
                 headers={"Referer": self.url},
                 schema=validate.Schema(
                     validate.transform(lambda text: re.sub(r"^\s*<!--\s*", "", text)),


Test patch: