prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN 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
  ```
  
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/streamlink/plugins/vk.py`
  Content:
  ```
  1 """
  2 $description Russian live-streaming and video hosting social platform.
  3 $url vk.com
  4 $type live, vod
  5 """
  6 
  7 import logging
  8 import re
  9 from urllib.parse import parse_qsl, unquote, urlparse
  10 
  11 from streamlink.exceptions import NoStreamsError
  12 from streamlink.plugin import Plugin, PluginError, pluginmatcher
  13 from streamlink.plugin.api import validate
  14 from streamlink.stream.dash import DASHStream
  15 from streamlink.stream.hls import HLSStream
  16 
  17 log = logging.getLogger(__name__)
  18 
  19 
  20 @pluginmatcher(re.compile(
  21     r"https?://(?:\w+\.)?vk\.com/videos?(?:\?z=video)?(?P<video_id>-?\d+_\d+)"
  22 ))
  23 @pluginmatcher(re.compile(
  24     r"https?://(\w+\.)?vk\.com/.+"
  25 ))
  26 class VK(Plugin):
  27     API_URL = "https://vk.com/al_video.php"
  28 
  29     def _has_video_id(self):
  30         return any(m for m in self.matches[:-1])
  31 
  32     def follow_vk_redirect(self):
  33         if self._has_video_id():
  34             return
  35 
  36         try:
  37             parsed_url = urlparse(self.url)
  38             true_path = next(unquote(v).split("/")[0] for k, v in parse_qsl(parsed_url.query) if k == "z" and len(v) > 0)
  39             self.url = f"{parsed_url.scheme}://{parsed_url.netloc}/{true_path}"
  40             if self._has_video_id():
  41                 return
  42         except StopIteration:
  43             pass
  44 
  45         try:
  46             self.url = self.session.http.get(self.url, schema=validate.Schema(
  47                 validate.parse_html(),
  48                 validate.xml_xpath_string(".//head/meta[@property='og:url'][@content]/@content"),
  49                 str
  50             ))
  51         except PluginError:
  52             pass
  53         if self._has_video_id():
  54             return
  55 
  56         raise NoStreamsError(self.url)
  57 
  58     def _get_streams(self):
  59         self.follow_vk_redirect()
  60 
  61         video_id = self.match.group("video_id")
  62         if not video_id:
  63             return
  64 
  65         log.debug(f"video ID: {video_id}")
  66         try:
  67             data = self.session.http.post(
  68                 self.API_URL,
  69                 params={
  70                     "act": "show",
  71                     "al": "1",
  72                     "video": video_id,
  73                 },
  74                 headers={"Referer": self.url},
  75                 schema=validate.Schema(
  76                     validate.transform(lambda text: re.sub(r"^\s*<!--\s*", "", text)),
  77                     validate.parse_json(),
  78                     {"payload": list},
  79                     validate.get(("payload", -1)),
  80                     list,
  81                     validate.get(-1),
  82                     {"player": {"params": [dict]}},
  83                     validate.get(("player", "params", 0)),
  84                     {
  85                         validate.optional("hls"): validate.url(),
  86                         validate.optional("manifest"): validate.startswith("<?xml"),
  87                         validate.optional("md_author"): validate.any(str, None),
  88                         validate.optional("md_title"): validate.any(str, None),
  89                     }
  90                 )
  91             )
  92         except PluginError:
  93             log.error("Could not parse API response")
  94             return
  95 
  96         self.id = video_id
  97         self.author = data.get("md_author")
  98         self.title = data.get("md_title")
  99 
  100         hls = data.get("hls")
  101         if hls:
  102             return HLSStream.parse_variant_playlist(self.session, hls)
  103 
  104         dash_manifest = data.get("manifest")
  105         if dash_manifest:
  106             return DASHStream.parse_manifest(self.session, dash_manifest)
  107 
  108 
  109 __plugin__ = VK
  110
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: 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 @@
           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)),
  
verification_info: {"golden_diff": "diff --git a/src/streamlink/plugins/vk.py b/src/streamlink/plugins/vk.py\n--- a/src/streamlink/plugins/vk.py\n+++ b/src/streamlink/plugins/vk.py\n@@ -6,6 +6,7 @@\n \n import logging\n import re\n+from hashlib import md5\n from urllib.parse import parse_qsl, unquote, urlparse\n \n from streamlink.exceptions import NoStreamsError\n@@ -13,6 +14,7 @@\n from streamlink.plugin.api import validate\n from streamlink.stream.dash import DASHStream\n from streamlink.stream.hls import HLSStream\n+from streamlink.utils.url import update_qsd\n \n log = logging.getLogger(__name__)\n \n@@ -25,6 +27,22 @@\n ))\n class VK(Plugin):\n     API_URL = \"https://vk.com/al_video.php\"\n+    HASH_COOKIE = \"hash429\"\n+\n+    def _get_cookies(self):\n+        def on_response(res, **kwargs):\n+            if res.headers.get(\"x-waf-redirect\") == \"1\":\n+                if not res.headers.get(\"X-WAF-Backend-Status\"):\n+                    log.debug(\"Getting WAF cookie\")\n+                    cookie = res.cookies.get(self.HASH_COOKIE)\n+                    key = md5(cookie.encode(\"utf-8\")).hexdigest()\n+                    res.headers[\"Location\"] = update_qsd(res.headers[\"Location\"], qsd={\"key\": key})\n+                    return res\n+                elif res.headers.get(\"X-WAF-Backend-Status\") == \"challenge_success\":\n+                    self.session.http.cookies.update(res.cookies)\n+                    return res\n+\n+        self.session.http.get(\"https://vk.com/\", hooks={\"response\": on_response})\n \n     def _has_video_id(self):\n         return any(m for m in self.matches[:-1])\n@@ -56,21 +74,19 @@\n         raise NoStreamsError(self.url)\n \n     def _get_streams(self):\n+        self._get_cookies()\n         self.follow_vk_redirect()\n \n         video_id = self.match.group(\"video_id\")\n         if not video_id:\n             return\n \n-        log.debug(f\"video ID: {video_id}\")\n+        log.debug(f\"Video ID: {video_id}\")\n         try:\n             data = self.session.http.post(\n                 self.API_URL,\n-                params={\n-                    \"act\": \"show\",\n-                    \"al\": \"1\",\n-                    \"video\": video_id,\n-                },\n+                params={\"act\": \"show\"},\n+                data={\"act\": \"show\", \"al\": \"1\", \"video\": video_id},\n                 headers={\"Referer\": self.url},\n                 schema=validate.Schema(\n                     validate.transform(lambda text: re.sub(r\"^\\s*<!--\\s*\", \"\", text)),\n", "issue": "plugins.vk: fixes required\n### Checklist\r\n\r\n- [X] This is a plugin issue and not a different kind of issue\r\n- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)\r\n- [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)\r\n- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)\r\n\r\n### Streamlink version\r\n\r\nLatest build from the master branch\r\n\r\n### Description\r\n\r\nNeeds support for the web application firewall cookie.\r\n\r\n~Seems necessary to add all parameters to the API POST data in `_get_streams()` now.~\r\n\r\nref: https://github.com/streamlink/streamlink/pull/4613#issuecomment-1173040359\r\n\r\n\r\n### Debug log\r\n\r\n```text\r\n$ streamlink -l debug https://vk.com/video-211154316_456239169\r\n[cli][debug] OS:         Linux-4.9.0-18-amd64-x86_64-with-debian-9.13\r\n[cli][debug] Python:     3.7.3\r\n[cli][debug] Streamlink: 4.1.0+45.gb277114d\r\n[cli][debug] Dependencies:\r\n[cli][debug]  isodate: 0.6.1\r\n[cli][debug]  lxml: 4.9.1\r\n[cli][debug]  pycountry: 22.3.5\r\n[cli][debug]  pycryptodome: 3.15.0\r\n[cli][debug]  PySocks: 1.7.1\r\n[cli][debug]  requests: 2.28.1\r\n[cli][debug]  websocket-client: 1.3.3\r\n[cli][debug]  importlib-metadata: 4.12.0\r\n[cli][debug] Arguments:\r\n[cli][debug]  url=https://vk.com/video-211154316_456239169\r\n[cli][debug]  --loglevel=debug\r\n[cli][info] Found matching plugin vk for URL https://vk.com/video-211154316_456239169\r\n[plugins.vk][debug] video ID: -211154316_456239169\r\n[plugins.vk][error] Could not parse API response\r\nerror: No playable streams found on this URL: https://vk.com/video-211154316_456239169\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\n$description Russian live-streaming and video hosting social platform.\n$url vk.com\n$type live, vod\n\"\"\"\n\nimport logging\nimport re\nfrom urllib.parse import parse_qsl, unquote, urlparse\n\nfrom streamlink.exceptions import NoStreamsError\nfrom streamlink.plugin import Plugin, PluginError, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.dash import DASHStream\nfrom streamlink.stream.hls import HLSStream\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(\n    r\"https?://(?:\\w+\\.)?vk\\.com/videos?(?:\\?z=video)?(?P<video_id>-?\\d+_\\d+)\"\n))\n@pluginmatcher(re.compile(\n    r\"https?://(\\w+\\.)?vk\\.com/.+\"\n))\nclass VK(Plugin):\n    API_URL = \"https://vk.com/al_video.php\"\n\n    def _has_video_id(self):\n        return any(m for m in self.matches[:-1])\n\n    def follow_vk_redirect(self):\n        if self._has_video_id():\n            return\n\n        try:\n            parsed_url = urlparse(self.url)\n            true_path = next(unquote(v).split(\"/\")[0] for k, v in parse_qsl(parsed_url.query) if k == \"z\" and len(v) > 0)\n            self.url = f\"{parsed_url.scheme}://{parsed_url.netloc}/{true_path}\"\n            if self._has_video_id():\n                return\n        except StopIteration:\n            pass\n\n        try:\n            self.url = self.session.http.get(self.url, schema=validate.Schema(\n                validate.parse_html(),\n                validate.xml_xpath_string(\".//head/meta[@property='og:url'][@content]/@content\"),\n                str\n            ))\n        except PluginError:\n            pass\n        if self._has_video_id():\n            return\n\n        raise NoStreamsError(self.url)\n\n    def _get_streams(self):\n        self.follow_vk_redirect()\n\n        video_id = self.match.group(\"video_id\")\n        if not video_id:\n            return\n\n        log.debug(f\"video ID: {video_id}\")\n        try:\n            data = self.session.http.post(\n                self.API_URL,\n                params={\n                    \"act\": \"show\",\n                    \"al\": \"1\",\n                    \"video\": video_id,\n                },\n                headers={\"Referer\": self.url},\n                schema=validate.Schema(\n                    validate.transform(lambda text: re.sub(r\"^\\s*<!--\\s*\", \"\", text)),\n                    validate.parse_json(),\n                    {\"payload\": list},\n                    validate.get((\"payload\", -1)),\n                    list,\n                    validate.get(-1),\n                    {\"player\": {\"params\": [dict]}},\n                    validate.get((\"player\", \"params\", 0)),\n                    {\n                        validate.optional(\"hls\"): validate.url(),\n                        validate.optional(\"manifest\"): validate.startswith(\"<?xml\"),\n                        validate.optional(\"md_author\"): validate.any(str, None),\n                        validate.optional(\"md_title\"): validate.any(str, None),\n                    }\n                )\n            )\n        except PluginError:\n            log.error(\"Could not parse API response\")\n            return\n\n        self.id = video_id\n        self.author = data.get(\"md_author\")\n        self.title = data.get(\"md_title\")\n\n        hls = data.get(\"hls\")\n        if hls:\n            return HLSStream.parse_variant_playlist(self.session, hls)\n\n        dash_manifest = data.get(\"manifest\")\n        if dash_manifest:\n            return DASHStream.parse_manifest(self.session, dash_manifest)\n\n\n__plugin__ = VK\n", "path": "src/streamlink/plugins/vk.py"}], "after_files": [{"content": "\"\"\"\n$description Russian live-streaming and video hosting social platform.\n$url vk.com\n$type live, vod\n\"\"\"\n\nimport logging\nimport re\nfrom hashlib import md5\nfrom urllib.parse import parse_qsl, unquote, urlparse\n\nfrom streamlink.exceptions import NoStreamsError\nfrom streamlink.plugin import Plugin, PluginError, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.dash import DASHStream\nfrom streamlink.stream.hls import HLSStream\nfrom streamlink.utils.url import update_qsd\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(\n    r\"https?://(?:\\w+\\.)?vk\\.com/videos?(?:\\?z=video)?(?P<video_id>-?\\d+_\\d+)\"\n))\n@pluginmatcher(re.compile(\n    r\"https?://(\\w+\\.)?vk\\.com/.+\"\n))\nclass VK(Plugin):\n    API_URL = \"https://vk.com/al_video.php\"\n    HASH_COOKIE = \"hash429\"\n\n    def _get_cookies(self):\n        def on_response(res, **kwargs):\n            if res.headers.get(\"x-waf-redirect\") == \"1\":\n                if not res.headers.get(\"X-WAF-Backend-Status\"):\n                    log.debug(\"Getting WAF cookie\")\n                    cookie = res.cookies.get(self.HASH_COOKIE)\n                    key = md5(cookie.encode(\"utf-8\")).hexdigest()\n                    res.headers[\"Location\"] = update_qsd(res.headers[\"Location\"], qsd={\"key\": key})\n                    return res\n                elif res.headers.get(\"X-WAF-Backend-Status\") == \"challenge_success\":\n                    self.session.http.cookies.update(res.cookies)\n                    return res\n\n        self.session.http.get(\"https://vk.com/\", hooks={\"response\": on_response})\n\n    def _has_video_id(self):\n        return any(m for m in self.matches[:-1])\n\n    def follow_vk_redirect(self):\n        if self._has_video_id():\n            return\n\n        try:\n            parsed_url = urlparse(self.url)\n            true_path = next(unquote(v).split(\"/\")[0] for k, v in parse_qsl(parsed_url.query) if k == \"z\" and len(v) > 0)\n            self.url = f\"{parsed_url.scheme}://{parsed_url.netloc}/{true_path}\"\n            if self._has_video_id():\n                return\n        except StopIteration:\n            pass\n\n        try:\n            self.url = self.session.http.get(self.url, schema=validate.Schema(\n                validate.parse_html(),\n                validate.xml_xpath_string(\".//head/meta[@property='og:url'][@content]/@content\"),\n                str\n            ))\n        except PluginError:\n            pass\n        if self._has_video_id():\n            return\n\n        raise NoStreamsError(self.url)\n\n    def _get_streams(self):\n        self._get_cookies()\n        self.follow_vk_redirect()\n\n        video_id = self.match.group(\"video_id\")\n        if not video_id:\n            return\n\n        log.debug(f\"Video ID: {video_id}\")\n        try:\n            data = self.session.http.post(\n                self.API_URL,\n                params={\"act\": \"show\"},\n                data={\"act\": \"show\", \"al\": \"1\", \"video\": video_id},\n                headers={\"Referer\": self.url},\n                schema=validate.Schema(\n                    validate.transform(lambda text: re.sub(r\"^\\s*<!--\\s*\", \"\", text)),\n                    validate.parse_json(),\n                    {\"payload\": list},\n                    validate.get((\"payload\", -1)),\n                    list,\n                    validate.get(-1),\n                    {\"player\": {\"params\": [dict]}},\n                    validate.get((\"player\", \"params\", 0)),\n                    {\n                        validate.optional(\"hls\"): validate.url(),\n                        validate.optional(\"manifest\"): validate.startswith(\"<?xml\"),\n                        validate.optional(\"md_author\"): validate.any(str, None),\n                        validate.optional(\"md_title\"): validate.any(str, None),\n                    }\n                )\n            )\n        except PluginError:\n            log.error(\"Could not parse API response\")\n            return\n\n        self.id = video_id\n        self.author = data.get(\"md_author\")\n        self.title = data.get(\"md_title\")\n\n        hls = data.get(\"hls\")\n        if hls:\n            return HLSStream.parse_variant_playlist(self.session, hls)\n\n        dash_manifest = data.get(\"manifest\")\n        if dash_manifest:\n            return DASHStream.parse_manifest(self.session, dash_manifest)\n\n\n__plugin__ = VK\n", "path": "src/streamlink/plugins/vk.py"}]}