prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  plugins.mediavitrina: no playable streams found on player URLs
  ### 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 stable release
  
  ### Description
  
  Since january streamlink can't handle gazprom-media mediavitrina urls like:
  
  https://player.mediavitrina.ru/gpm_tnt_v2/tnt/vitrinatv_web/player.html
  https://player.mediavitrina.ru/gpm_friday_v2/friday/vitrinatv_web/player.html
  https://player.mediavitrina.ru/tv3_v2/tv3/vitrinatv_web/player.html
  
  The reason for that is beause mediavitrina can't open a required json file like
  https://media.mediavitrina.ru/api/v3/gpm-tnt/playlist/tnt_as_array.json?application_id=&player_referer_hostname=vitrina.tv&config_checksum_sha256=&egress_version_id=1950111
  
  what i know:
  when i try to open this json file directly in browser it fails but when i specify a referer "https://player.mediavitrina.ru/" for media.mediavitrina.ru url using firefox extension it opens perfectly
  so i think mediavitrina plugin does not send this referer requesting json from media.mediavitrina.ru URL, it sends referer only for player.mediavitrina.ru URLs
  
  please fix this issue
  P.S.:
  it would be futureproof if this plugin just could handle https://media.mediavitrina.ru/api/v1/gpm-tnt/playlist/tnt_as_array.json URLs directly
  
  ### Debug log
  
  ```text
  [cli][info] Found matching plugin mediavitrina for URL https://player.mediavitri
  na.ru/gpm_tnt_v2/tnt/vitrinatv_web/player.html
  error: No playable streams found on this URL: https://player.mediavitrina.ru/gpm
  _tnt_v2/tnt/vitrinatv_web/player.html
  ```
  
  
  --- 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/mediavitrina.py`
  Content:
  ```
  1 """
  2 $description Russian live streaming platform hosting various Russian live TV channels.
  3 $url mediavitrina.ru
  4 $type live
  5 $region Russia
  6 """
  7 
  8 import logging
  9 import re
  10 from urllib.parse import urlparse
  11 
  12 from streamlink.plugin import Plugin, pluginmatcher
  13 from streamlink.plugin.api import validate
  14 from streamlink.stream.hls import HLSStream
  15 from streamlink.utils.url import update_qsd
  16 
  17 
  18 log = logging.getLogger(__name__)
  19 
  20 
  21 @pluginmatcher(re.compile(r"""https?://(?:www\.)?(?:
  22     chetv
  23     |
  24     ctc(?:love)?
  25     |
  26     domashniy
  27 )\.ru/(?:live|online)""", re.VERBOSE))
  28 @pluginmatcher(re.compile(r"https?://player\.mediavitrina\.ru/.+/player\.html"))
  29 class MediaVitrina(Plugin):
  30     _re_url_json = re.compile(r"https://media\.mediavitrina\.ru/(?:proxy)?api/v3/\w+/playlist/[\w-]+_as_array\.json[^\"']+")
  31 
  32     def _get_streams(self):
  33         self.session.http.headers.update({"Referer": self.url})
  34 
  35         p_netloc = urlparse(self.url).netloc
  36         if p_netloc == "player.mediavitrina.ru":
  37             # https://player.mediavitrina.ru/
  38             url_player = self.url
  39         elif p_netloc.endswith("ctc.ru"):
  40             # https://ctc.ru/online/
  41             url_player = self.session.http.get(
  42                 "https://ctc.ru/api/page/v1/online/",
  43                 schema=validate.Schema(
  44                     validate.parse_json(),
  45                     {"content": validate.all(
  46                         [dict],
  47                         validate.filter(lambda n: n.get("type") == "on-air"),
  48                         [{"onAirLink": validate.url(netloc="player.mediavitrina.ru")}],
  49                         validate.get((0, "onAirLink")),
  50                     )},
  51                     validate.get("content"),
  52                 ),
  53             )
  54         else:
  55             # https://chetv.ru/online/
  56             # https://ctclove.ru/online/
  57             # https://domashniy.ru/online/
  58             url_player = self.session.http.get(self.url, schema=validate.Schema(
  59                 validate.parse_html(),
  60                 validate.xml_xpath_string(".//iframe[starts-with(@src,'https://player.mediavitrina.ru/')]/@src"),
  61             ), acceptable_status=(200, 403, 404))
  62 
  63         if not url_player:
  64             return
  65 
  66         log.debug(f"url_player={url_player}")
  67         script_data = self.session.http.get(url_player, schema=validate.Schema(
  68             validate.parse_html(),
  69             validate.xml_xpath_string(".//script[contains(text(),'media.mediavitrina.ru/')]/text()"),
  70         ))
  71         if not script_data:
  72             log.debug("invalid script_data")
  73             return
  74 
  75         m = self._re_url_json.search(script_data)
  76         if not m:
  77             log.debug("invalid url_json")
  78             return
  79 
  80         url_json = m.group(0)
  81         log.debug(f"url_json={url_json}")
  82         url_json = re.sub(r"\{\{PLAYER_REFERER_HOSTNAME\}\}", "mediavitrina.ru", url_json)
  83         url_json = re.sub(r"\{\{[A-Za-z_]+\}\}", "", url_json)
  84 
  85         res_token = self.session.http.get(
  86             "https://media.mediavitrina.ru/get_token",
  87             schema=validate.Schema(
  88                 validate.parse_json(),
  89                 {"result": {"token": str}},
  90                 validate.get("result"),
  91             ))
  92         url = self.session.http.get(
  93             update_qsd(url_json, qsd=res_token),
  94             schema=validate.Schema(
  95                 validate.parse_json(),
  96                 {"hls": [validate.url()]},
  97                 validate.get(("hls", 0)),
  98             ))
  99 
  100         if not url:
  101             return
  102 
  103         if "georestrictions" in url:
  104             log.error("Stream is geo-restricted")
  105             return
  106 
  107         return HLSStream.parse_variant_playlist(self.session, url, name_fmt="{pixels}_{bitrate}")
  108 
  109 
  110 __plugin__ = MediaVitrina
  111
  ```
  --- 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/mediavitrina.py b/src/streamlink/plugins/mediavitrina.py
  --- a/src/streamlink/plugins/mediavitrina.py
  +++ b/src/streamlink/plugins/mediavitrina.py
  @@ -27,7 +27,7 @@
   )\.ru/(?:live|online)""", re.VERBOSE))
   @pluginmatcher(re.compile(r"https?://player\.mediavitrina\.ru/.+/player\.html"))
   class MediaVitrina(Plugin):
  -    _re_url_json = re.compile(r"https://media\.mediavitrina\.ru/(?:proxy)?api/v3/\w+/playlist/[\w-]+_as_array\.json[^\"']+")
  +    _re_url_json = re.compile(r"https://media\.mediavitrina\.ru/(?:proxy)?api/v3/[\w-]+/playlist/[\w-]+_as_array\.json[^\"']+")
   
       def _get_streams(self):
           self.session.http.headers.update({"Referer": self.url})
  
verification_info: {"golden_diff": "diff --git a/src/streamlink/plugins/mediavitrina.py b/src/streamlink/plugins/mediavitrina.py\n--- a/src/streamlink/plugins/mediavitrina.py\n+++ b/src/streamlink/plugins/mediavitrina.py\n@@ -27,7 +27,7 @@\n )\\.ru/(?:live|online)\"\"\", re.VERBOSE))\n @pluginmatcher(re.compile(r\"https?://player\\.mediavitrina\\.ru/.+/player\\.html\"))\n class MediaVitrina(Plugin):\n-    _re_url_json = re.compile(r\"https://media\\.mediavitrina\\.ru/(?:proxy)?api/v3/\\w+/playlist/[\\w-]+_as_array\\.json[^\\\"']+\")\n+    _re_url_json = re.compile(r\"https://media\\.mediavitrina\\.ru/(?:proxy)?api/v3/[\\w-]+/playlist/[\\w-]+_as_array\\.json[^\\\"']+\")\n \n     def _get_streams(self):\n         self.session.http.headers.update({\"Referer\": self.url})\n", "issue": "plugins.mediavitrina: no playable streams found on player URLs\n### Checklist\n\n- [X] This is a plugin issue and not a different kind of issue\n- [X] [I have read the contribution guidelines](https://github.com/streamlink/streamlink/blob/master/CONTRIBUTING.md#contributing-to-streamlink)\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)\n- [X] [I have checked the commit log of the master branch](https://github.com/streamlink/streamlink/commits/master)\n\n### Streamlink version\n\nLatest stable release\n\n### Description\n\nSince january streamlink can't handle gazprom-media mediavitrina urls like:\r\n\r\nhttps://player.mediavitrina.ru/gpm_tnt_v2/tnt/vitrinatv_web/player.html\r\nhttps://player.mediavitrina.ru/gpm_friday_v2/friday/vitrinatv_web/player.html\r\nhttps://player.mediavitrina.ru/tv3_v2/tv3/vitrinatv_web/player.html\r\n\r\nThe reason for that is beause mediavitrina can't open a required json file like\r\nhttps://media.mediavitrina.ru/api/v3/gpm-tnt/playlist/tnt_as_array.json?application_id=&player_referer_hostname=vitrina.tv&config_checksum_sha256=&egress_version_id=1950111\r\n\r\nwhat i know:\r\nwhen i try to open this json file directly in browser it fails but when i specify a referer \"https://player.mediavitrina.ru/\" for media.mediavitrina.ru url using firefox extension it opens perfectly\r\nso i think mediavitrina plugin does not send this referer requesting json from media.mediavitrina.ru URL, it sends referer only for player.mediavitrina.ru URLs\r\n\r\nplease fix this issue\r\nP.S.:\r\nit would be futureproof if this plugin just could handle https://media.mediavitrina.ru/api/v1/gpm-tnt/playlist/tnt_as_array.json URLs directly\n\n### Debug log\n\n```text\n[cli][info] Found matching plugin mediavitrina for URL https://player.mediavitri\r\nna.ru/gpm_tnt_v2/tnt/vitrinatv_web/player.html\r\nerror: No playable streams found on this URL: https://player.mediavitrina.ru/gpm\r\n_tnt_v2/tnt/vitrinatv_web/player.html\n```\n\n", "before_files": [{"content": "\"\"\"\n$description Russian live streaming platform hosting various Russian live TV channels.\n$url mediavitrina.ru\n$type live\n$region Russia\n\"\"\"\n\nimport logging\nimport re\nfrom urllib.parse import urlparse\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\nfrom streamlink.utils.url import update_qsd\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(r\"\"\"https?://(?:www\\.)?(?:\n    chetv\n    |\n    ctc(?:love)?\n    |\n    domashniy\n)\\.ru/(?:live|online)\"\"\", re.VERBOSE))\n@pluginmatcher(re.compile(r\"https?://player\\.mediavitrina\\.ru/.+/player\\.html\"))\nclass MediaVitrina(Plugin):\n    _re_url_json = re.compile(r\"https://media\\.mediavitrina\\.ru/(?:proxy)?api/v3/\\w+/playlist/[\\w-]+_as_array\\.json[^\\\"']+\")\n\n    def _get_streams(self):\n        self.session.http.headers.update({\"Referer\": self.url})\n\n        p_netloc = urlparse(self.url).netloc\n        if p_netloc == \"player.mediavitrina.ru\":\n            # https://player.mediavitrina.ru/\n            url_player = self.url\n        elif p_netloc.endswith(\"ctc.ru\"):\n            # https://ctc.ru/online/\n            url_player = self.session.http.get(\n                \"https://ctc.ru/api/page/v1/online/\",\n                schema=validate.Schema(\n                    validate.parse_json(),\n                    {\"content\": validate.all(\n                        [dict],\n                        validate.filter(lambda n: n.get(\"type\") == \"on-air\"),\n                        [{\"onAirLink\": validate.url(netloc=\"player.mediavitrina.ru\")}],\n                        validate.get((0, \"onAirLink\")),\n                    )},\n                    validate.get(\"content\"),\n                ),\n            )\n        else:\n            # https://chetv.ru/online/\n            # https://ctclove.ru/online/\n            # https://domashniy.ru/online/\n            url_player = self.session.http.get(self.url, schema=validate.Schema(\n                validate.parse_html(),\n                validate.xml_xpath_string(\".//iframe[starts-with(@src,'https://player.mediavitrina.ru/')]/@src\"),\n            ), acceptable_status=(200, 403, 404))\n\n        if not url_player:\n            return\n\n        log.debug(f\"url_player={url_player}\")\n        script_data = self.session.http.get(url_player, schema=validate.Schema(\n            validate.parse_html(),\n            validate.xml_xpath_string(\".//script[contains(text(),'media.mediavitrina.ru/')]/text()\"),\n        ))\n        if not script_data:\n            log.debug(\"invalid script_data\")\n            return\n\n        m = self._re_url_json.search(script_data)\n        if not m:\n            log.debug(\"invalid url_json\")\n            return\n\n        url_json = m.group(0)\n        log.debug(f\"url_json={url_json}\")\n        url_json = re.sub(r\"\\{\\{PLAYER_REFERER_HOSTNAME\\}\\}\", \"mediavitrina.ru\", url_json)\n        url_json = re.sub(r\"\\{\\{[A-Za-z_]+\\}\\}\", \"\", url_json)\n\n        res_token = self.session.http.get(\n            \"https://media.mediavitrina.ru/get_token\",\n            schema=validate.Schema(\n                validate.parse_json(),\n                {\"result\": {\"token\": str}},\n                validate.get(\"result\"),\n            ))\n        url = self.session.http.get(\n            update_qsd(url_json, qsd=res_token),\n            schema=validate.Schema(\n                validate.parse_json(),\n                {\"hls\": [validate.url()]},\n                validate.get((\"hls\", 0)),\n            ))\n\n        if not url:\n            return\n\n        if \"georestrictions\" in url:\n            log.error(\"Stream is geo-restricted\")\n            return\n\n        return HLSStream.parse_variant_playlist(self.session, url, name_fmt=\"{pixels}_{bitrate}\")\n\n\n__plugin__ = MediaVitrina\n", "path": "src/streamlink/plugins/mediavitrina.py"}], "after_files": [{"content": "\"\"\"\n$description Russian live streaming platform hosting various Russian live TV channels.\n$url mediavitrina.ru\n$type live\n$region Russia\n\"\"\"\n\nimport logging\nimport re\nfrom urllib.parse import urlparse\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\nfrom streamlink.utils.url import update_qsd\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(r\"\"\"https?://(?:www\\.)?(?:\n    chetv\n    |\n    ctc(?:love)?\n    |\n    domashniy\n)\\.ru/(?:live|online)\"\"\", re.VERBOSE))\n@pluginmatcher(re.compile(r\"https?://player\\.mediavitrina\\.ru/.+/player\\.html\"))\nclass MediaVitrina(Plugin):\n    _re_url_json = re.compile(r\"https://media\\.mediavitrina\\.ru/(?:proxy)?api/v3/[\\w-]+/playlist/[\\w-]+_as_array\\.json[^\\\"']+\")\n\n    def _get_streams(self):\n        self.session.http.headers.update({\"Referer\": self.url})\n\n        p_netloc = urlparse(self.url).netloc\n        if p_netloc == \"player.mediavitrina.ru\":\n            # https://player.mediavitrina.ru/\n            url_player = self.url\n        elif p_netloc.endswith(\"ctc.ru\"):\n            # https://ctc.ru/online/\n            url_player = self.session.http.get(\n                \"https://ctc.ru/api/page/v1/online/\",\n                schema=validate.Schema(\n                    validate.parse_json(),\n                    {\"content\": validate.all(\n                        [dict],\n                        validate.filter(lambda n: n.get(\"type\") == \"on-air\"),\n                        [{\"onAirLink\": validate.url(netloc=\"player.mediavitrina.ru\")}],\n                        validate.get((0, \"onAirLink\")),\n                    )},\n                    validate.get(\"content\"),\n                ),\n            )\n        else:\n            # https://chetv.ru/online/\n            # https://ctclove.ru/online/\n            # https://domashniy.ru/online/\n            url_player = self.session.http.get(self.url, schema=validate.Schema(\n                validate.parse_html(),\n                validate.xml_xpath_string(\".//iframe[starts-with(@src,'https://player.mediavitrina.ru/')]/@src\"),\n            ), acceptable_status=(200, 403, 404))\n\n        if not url_player:\n            return\n\n        log.debug(f\"url_player={url_player}\")\n        script_data = self.session.http.get(url_player, schema=validate.Schema(\n            validate.parse_html(),\n            validate.xml_xpath_string(\".//script[contains(text(),'media.mediavitrina.ru/')]/text()\"),\n        ))\n        if not script_data:\n            log.debug(\"invalid script_data\")\n            return\n\n        m = self._re_url_json.search(script_data)\n        if not m:\n            log.debug(\"invalid url_json\")\n            return\n\n        url_json = m.group(0)\n        log.debug(f\"url_json={url_json}\")\n        url_json = re.sub(r\"\\{\\{PLAYER_REFERER_HOSTNAME\\}\\}\", \"mediavitrina.ru\", url_json)\n        url_json = re.sub(r\"\\{\\{[A-Za-z_]+\\}\\}\", \"\", url_json)\n\n        res_token = self.session.http.get(\n            \"https://media.mediavitrina.ru/get_token\",\n            schema=validate.Schema(\n                validate.parse_json(),\n                {\"result\": {\"token\": str}},\n                validate.get(\"result\"),\n            ))\n        url = self.session.http.get(\n            update_qsd(url_json, qsd=res_token),\n            schema=validate.Schema(\n                validate.parse_json(),\n                {\"hls\": [validate.url()]},\n                validate.get((\"hls\", 0)),\n            ))\n\n        if not url:\n            return\n\n        if \"georestrictions\" in url:\n            log.error(\"Stream is geo-restricted\")\n            return\n\n        return HLSStream.parse_variant_playlist(self.session, url, name_fmt=\"{pixels}_{bitrate}\")\n\n\n__plugin__ = MediaVitrina\n", "path": "src/streamlink/plugins/mediavitrina.py"}]}