We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
plugins.ard_mediathek: No playable streams found on this URL
### 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

The ARD (German Public TV) seems not to be working at the moment with Streamlink. 

It gives a 'error: No playable streams found on this URL: https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU'


### Debug log

```text
[cli][debug] OS:         Linux-5.10.0-15-amd64-x86_64-with-glibc2.31
[cli][debug] Python:     3.9.2
[cli][debug] Streamlink: 0.0.0+unknown
[cli][debug] Dependencies:
[cli][debug]  PySocks: 1.7.1
[cli][debug]  isodate: 0.6.1
[cli][debug]  lxml: 4.8.0
[cli][debug]  pycountry: 22.3.5
[cli][debug]  pycryptodome: 3.14.1
[cli][debug]  requests: 2.27.1
[cli][debug]  websocket-client: 1.3.1
[cli][debug]  importlib-metadata: 4.11.3
[cli][debug] Arguments:
[cli][debug]  url=https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU
[cli][debug]  stream=['720p']
[cli][debug]  --loglevel=debug
[cli][debug]  --output=blah.mp4
[cli][debug]  --http-proxy=socks5h://xxx.xxxd@xxxx.dynv6.net:8200
[cli][info] Found matching plugin ard_mediathek for URL https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU
error: No playable streams found on this URL: https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU
```


--- 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/ard_mediathek.py`
Content:
```
1 """
2 $description Live TV channels and video on-demand service from ARD, a German public, independent broadcaster.
3 $url ardmediathek.de
4 $url mediathek.daserste.de
5 $type live, vod
6 $region Germany
7 """
8 
9 import logging
10 import re
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.stream.http import HTTPStream
16 
17 
18 log = logging.getLogger(__name__)
19 
20 
21 @pluginmatcher(re.compile(
22     r"https?://(?:(\w+\.)?ardmediathek\.de/|mediathek\.daserste\.de/)"
23 ))
24 class ARDMediathek(Plugin):
25     _QUALITY_MAP = {
26         4: "1080p",
27         3: "720p",
28         2: "540p",
29         1: "360p",
30         0: "270p"
31     }
32 
33     def _get_streams(self):
34         data_json = self.session.http.get(self.url, schema=validate.Schema(
35             validate.parse_html(),
36             validate.xml_findtext(".//script[@id='fetchedContextValue'][@type='application/json']"),
37             validate.any(None, validate.all(
38                 validate.parse_json(),
39                 {str: dict},
40                 validate.transform(lambda obj: list(obj.items())),
41                 validate.filter(lambda item: item[0].startswith("https://api.ardmediathek.de/page-gateway/pages/")),
42                 validate.any(validate.get((0, 1)), [])
43             ))
44         ))
45         if not data_json:
46             return
47 
48         schema_data = validate.Schema({
49             "id": str,
50             "widgets": validate.all(
51                 [dict],
52                 validate.filter(lambda item: item.get("mediaCollection")),
53                 validate.get(0),
54                 validate.any(None, validate.all(
55                     {
56                         "geoblocked": bool,
57                         "publicationService": {
58                             "name": str,
59                         },
60                         "show": validate.any(None, validate.all(
61                             {"title": str},
62                             validate.get("title")
63                         )),
64                         "title": str,
65                         "mediaCollection": {
66                             "embedded": {
67                                 "_mediaArray": [validate.all(
68                                     {
69                                         "_mediaStreamArray": [validate.all(
70                                             {
71                                                 "_quality": validate.any(str, int),
72                                                 "_stream": validate.url(),
73                                             },
74                                             validate.union_get("_quality", "_stream")
75                                         )]
76                                     },
77                                     validate.get("_mediaStreamArray"),
78                                     validate.transform(dict)
79                                 )]
80                             }
81                         },
82                     },
83                     validate.union_get(
84                         "geoblocked",
85                         ("mediaCollection", "embedded", "_mediaArray", 0),
86                         ("publicationService", "name"),
87                         "title",
88                         "show",
89                     )
90                 ))
91             )
92         })
93         data = schema_data.validate(data_json)
94 
95         log.debug(f"Found media id: {data['id']}")
96         if not data["widgets"]:
97             log.info("The content is unavailable")
98             return
99 
100         geoblocked, media, self.author, self.title, show = data["widgets"]
101         if geoblocked:
102             log.info("The content is not available in your region")
103             return
104         if show:
105             self.title = f"{show}: {self.title}"
106 
107         if media.get("auto"):
108             yield from HLSStream.parse_variant_playlist(self.session, media.get("auto")).items()
109         else:
110             for quality, stream in media.items():
111                 yield self._QUALITY_MAP.get(quality, quality), HTTPStream(self.session, stream)
112 
113 
114 __plugin__ = ARDMediathek
115
```
--- 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()

```

diff --git a/src/streamlink/plugins/ard_mediathek.py b/src/streamlink/plugins/ard_mediathek.py
--- a/src/streamlink/plugins/ard_mediathek.py
+++ b/src/streamlink/plugins/ard_mediathek.py
@@ -19,29 +19,50 @@
 
 
 @pluginmatcher(re.compile(
-    r"https?://(?:(\w+\.)?ardmediathek\.de/|mediathek\.daserste\.de/)"
+    r"""
+        https?://(\w+\.)?ardmediathek\.de/
+        (?:
+            live/(?:[^/]+/)?(?P<id_live>\w+)
+            |
+            video/(?:[^/]+/[^/]+/[^/]+/)?(?P<id_video>\w+)
+        )
+        (?:\?|$)
+    """,
+    re.VERBOSE,
 ))
 class ARDMediathek(Plugin):
+    _URL_API = "https://api.ardmediathek.de/page-gateway/pages/ard/item/{item}"
     _QUALITY_MAP = {
         4: "1080p",
         3: "720p",
         2: "540p",
         1: "360p",
-        0: "270p"
+        0: "270p",
     }
 
     def _get_streams(self):
         data_json = self.session.http.get(self.url, schema=validate.Schema(
             validate.parse_html(),
-            validate.xml_findtext(".//script[@id='fetchedContextValue'][@type='application/json']"),
-            validate.any(None, validate.all(
+            validate.xml_xpath_string(".//script[@type='application/json'][@id='fetchedContextValue2'][1]/text()"),
+            validate.none_or_all(
                 validate.parse_json(),
-                {str: dict},
-                validate.transform(lambda obj: list(obj.items())),
+                [validate.list(str, {"data": dict})],
                 validate.filter(lambda item: item[0].startswith("https://api.ardmediathek.de/page-gateway/pages/")),
-                validate.any(validate.get((0, 1)), [])
-            ))
+                validate.any(
+                    validate.get((0, 1, "data")),
+                    [],
+                ),
+            ),
         ))
+        if not data_json:
+            data_json = self.session.http.get(
+                self._URL_API.format(item=self.match.group("id_live") or self.match.group("id_video")),
+                params={
+                    "devicetype": "pc",
+                    "embedded": "false",
+                },
+                schema=validate.Schema(validate.parse_json()),
+            )
         if not data_json:
             return

{"golden_diff": "diff --git a/src/streamlink/plugins/ard_mediathek.py b/src/streamlink/plugins/ard_mediathek.py\n--- a/src/streamlink/plugins/ard_mediathek.py\n+++ b/src/streamlink/plugins/ard_mediathek.py\n@@ -19,29 +19,50 @@\n \n \n @pluginmatcher(re.compile(\n-    r\"https?://(?:(\\w+\\.)?ardmediathek\\.de/|mediathek\\.daserste\\.de/)\"\n+    r\"\"\"\n+        https?://(\\w+\\.)?ardmediathek\\.de/\n+        (?:\n+            live/(?:[^/]+/)?(?P<id_live>\\w+)\n+            |\n+            video/(?:[^/]+/[^/]+/[^/]+/)?(?P<id_video>\\w+)\n+        )\n+        (?:\\?|$)\n+    \"\"\",\n+    re.VERBOSE,\n ))\n class ARDMediathek(Plugin):\n+    _URL_API = \"https://api.ardmediathek.de/page-gateway/pages/ard/item/{item}\"\n     _QUALITY_MAP = {\n         4: \"1080p\",\n         3: \"720p\",\n         2: \"540p\",\n         1: \"360p\",\n-        0: \"270p\"\n+        0: \"270p\",\n     }\n \n     def _get_streams(self):\n         data_json = self.session.http.get(self.url, schema=validate.Schema(\n             validate.parse_html(),\n-            validate.xml_findtext(\".//script[@id='fetchedContextValue'][@type='application/json']\"),\n-            validate.any(None, validate.all(\n+            validate.xml_xpath_string(\".//script[@type='application/json'][@id='fetchedContextValue2'][1]/text()\"),\n+            validate.none_or_all(\n                 validate.parse_json(),\n-                {str: dict},\n-                validate.transform(lambda obj: list(obj.items())),\n+                [validate.list(str, {\"data\": dict})],\n                 validate.filter(lambda item: item[0].startswith(\"https://api.ardmediathek.de/page-gateway/pages/\")),\n-                validate.any(validate.get((0, 1)), [])\n-            ))\n+                validate.any(\n+                    validate.get((0, 1, \"data\")),\n+                    [],\n+                ),\n+            ),\n         ))\n+        if not data_json:\n+            data_json = self.session.http.get(\n+                self._URL_API.format(item=self.match.group(\"id_live\") or self.match.group(\"id_video\")),\n+                params={\n+                    \"devicetype\": \"pc\",\n+                    \"embedded\": \"false\",\n+                },\n+                schema=validate.Schema(validate.parse_json()),\n+            )\n         if not data_json:\n             return\n", "issue": "plugins.ard_mediathek: No playable streams found on this URL\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\nThe ARD (German Public TV) seems not to be working at the moment with Streamlink. \r\n\r\nIt gives a 'error: No playable streams found on this URL: https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU'\r\n\r\n\r\n### Debug log\r\n\r\n```text\r\n[cli][debug] OS:         Linux-5.10.0-15-amd64-x86_64-with-glibc2.31\r\n[cli][debug] Python:     3.9.2\r\n[cli][debug] Streamlink: 0.0.0+unknown\r\n[cli][debug] Dependencies:\r\n[cli][debug]  PySocks: 1.7.1\r\n[cli][debug]  isodate: 0.6.1\r\n[cli][debug]  lxml: 4.8.0\r\n[cli][debug]  pycountry: 22.3.5\r\n[cli][debug]  pycryptodome: 3.14.1\r\n[cli][debug]  requests: 2.27.1\r\n[cli][debug]  websocket-client: 1.3.1\r\n[cli][debug]  importlib-metadata: 4.11.3\r\n[cli][debug] Arguments:\r\n[cli][debug]  url=https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU\r\n[cli][debug]  stream=['720p']\r\n[cli][debug]  --loglevel=debug\r\n[cli][debug]  --output=blah.mp4\r\n[cli][debug]  --http-proxy=socks5h://xxx.xxxd@xxxx.dynv6.net:8200\r\n[cli][info] Found matching plugin ard_mediathek for URL https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU\r\nerror: No playable streams found on this URL: https://www.ardmediathek.de/daserste/live/Y3JpZDovL2Rhc2Vyc3RlLmRlL0xpdmVzdHJlYW0tRGFzRXJzdGU\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\n$description Live TV channels and video on-demand service from ARD, a German public, independent broadcaster.\n$url ardmediathek.de\n$url mediathek.daserste.de\n$type live, vod\n$region Germany\n\"\"\"\n\nimport logging\nimport re\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\nfrom streamlink.stream.http import HTTPStream\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(\n    r\"https?://(?:(\\w+\\.)?ardmediathek\\.de/|mediathek\\.daserste\\.de/)\"\n))\nclass ARDMediathek(Plugin):\n    _QUALITY_MAP = {\n        4: \"1080p\",\n        3: \"720p\",\n        2: \"540p\",\n        1: \"360p\",\n        0: \"270p\"\n    }\n\n    def _get_streams(self):\n        data_json = self.session.http.get(self.url, schema=validate.Schema(\n            validate.parse_html(),\n            validate.xml_findtext(\".//script[@id='fetchedContextValue'][@type='application/json']\"),\n            validate.any(None, validate.all(\n                validate.parse_json(),\n                {str: dict},\n                validate.transform(lambda obj: list(obj.items())),\n                validate.filter(lambda item: item[0].startswith(\"https://api.ardmediathek.de/page-gateway/pages/\")),\n                validate.any(validate.get((0, 1)), [])\n            ))\n        ))\n        if not data_json:\n            return\n\n        schema_data = validate.Schema({\n            \"id\": str,\n            \"widgets\": validate.all(\n                [dict],\n                validate.filter(lambda item: item.get(\"mediaCollection\")),\n                validate.get(0),\n                validate.any(None, validate.all(\n                    {\n                        \"geoblocked\": bool,\n                        \"publicationService\": {\n                            \"name\": str,\n                        },\n                        \"show\": validate.any(None, validate.all(\n                            {\"title\": str},\n                            validate.get(\"title\")\n                        )),\n                        \"title\": str,\n                        \"mediaCollection\": {\n                            \"embedded\": {\n                                \"_mediaArray\": [validate.all(\n                                    {\n                                        \"_mediaStreamArray\": [validate.all(\n                                            {\n                                                \"_quality\": validate.any(str, int),\n                                                \"_stream\": validate.url(),\n                                            },\n                                            validate.union_get(\"_quality\", \"_stream\")\n                                        )]\n                                    },\n                                    validate.get(\"_mediaStreamArray\"),\n                                    validate.transform(dict)\n                                )]\n                            }\n                        },\n                    },\n                    validate.union_get(\n                        \"geoblocked\",\n                        (\"mediaCollection\", \"embedded\", \"_mediaArray\", 0),\n                        (\"publicationService\", \"name\"),\n                        \"title\",\n                        \"show\",\n                    )\n                ))\n            )\n        })\n        data = schema_data.validate(data_json)\n\n        log.debug(f\"Found media id: {data['id']}\")\n        if not data[\"widgets\"]:\n            log.info(\"The content is unavailable\")\n            return\n\n        geoblocked, media, self.author, self.title, show = data[\"widgets\"]\n        if geoblocked:\n            log.info(\"The content is not available in your region\")\n            return\n        if show:\n            self.title = f\"{show}: {self.title}\"\n\n        if media.get(\"auto\"):\n            yield from HLSStream.parse_variant_playlist(self.session, media.get(\"auto\")).items()\n        else:\n            for quality, stream in media.items():\n                yield self._QUALITY_MAP.get(quality, quality), HTTPStream(self.session, stream)\n\n\n__plugin__ = ARDMediathek\n", "path": "src/streamlink/plugins/ard_mediathek.py"}], "after_files": [{"content": "\"\"\"\n$description Live TV channels and video on-demand service from ARD, a German public, independent broadcaster.\n$url ardmediathek.de\n$url mediathek.daserste.de\n$type live, vod\n$region Germany\n\"\"\"\n\nimport logging\nimport re\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\nfrom streamlink.stream.http import HTTPStream\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(\n    r\"\"\"\n        https?://(\\w+\\.)?ardmediathek\\.de/\n        (?:\n            live/(?:[^/]+/)?(?P<id_live>\\w+)\n            |\n            video/(?:[^/]+/[^/]+/[^/]+/)?(?P<id_video>\\w+)\n        )\n        (?:\\?|$)\n    \"\"\",\n    re.VERBOSE,\n))\nclass ARDMediathek(Plugin):\n    _URL_API = \"https://api.ardmediathek.de/page-gateway/pages/ard/item/{item}\"\n    _QUALITY_MAP = {\n        4: \"1080p\",\n        3: \"720p\",\n        2: \"540p\",\n        1: \"360p\",\n        0: \"270p\",\n    }\n\n    def _get_streams(self):\n        data_json = self.session.http.get(self.url, schema=validate.Schema(\n            validate.parse_html(),\n            validate.xml_xpath_string(\".//script[@type='application/json'][@id='fetchedContextValue2'][1]/text()\"),\n            validate.none_or_all(\n                validate.parse_json(),\n                [validate.list(str, {\"data\": dict})],\n                validate.filter(lambda item: item[0].startswith(\"https://api.ardmediathek.de/page-gateway/pages/\")),\n                validate.any(\n                    validate.get((0, 1, \"data\")),\n                    [],\n                ),\n            ),\n        ))\n        if not data_json:\n            data_json = self.session.http.get(\n                self._URL_API.format(item=self.match.group(\"id_live\") or self.match.group(\"id_video\")),\n                params={\n                    \"devicetype\": \"pc\",\n                    \"embedded\": \"false\",\n                },\n                schema=validate.Schema(validate.parse_json()),\n            )\n        if not data_json:\n            return\n\n        schema_data = validate.Schema({\n            \"id\": str,\n            \"widgets\": validate.all(\n                [dict],\n                validate.filter(lambda item: item.get(\"mediaCollection\")),\n                validate.get(0),\n                validate.any(None, validate.all(\n                    {\n                        \"geoblocked\": bool,\n                        \"publicationService\": {\n                            \"name\": str,\n                        },\n                        \"show\": validate.any(None, validate.all(\n                            {\"title\": str},\n                            validate.get(\"title\")\n                        )),\n                        \"title\": str,\n                        \"mediaCollection\": {\n                            \"embedded\": {\n                                \"_mediaArray\": [validate.all(\n                                    {\n                                        \"_mediaStreamArray\": [validate.all(\n                                            {\n                                                \"_quality\": validate.any(str, int),\n                                                \"_stream\": validate.url(),\n                                            },\n                                            validate.union_get(\"_quality\", \"_stream\")\n                                        )]\n                                    },\n                                    validate.get(\"_mediaStreamArray\"),\n                                    validate.transform(dict)\n                                )]\n                            }\n                        },\n                    },\n                    validate.union_get(\n                        \"geoblocked\",\n                        (\"mediaCollection\", \"embedded\", \"_mediaArray\", 0),\n                        (\"publicationService\", \"name\"),\n                        \"title\",\n                        \"show\",\n                    )\n                ))\n            )\n        })\n        data = schema_data.validate(data_json)\n\n        log.debug(f\"Found media id: {data['id']}\")\n        if not data[\"widgets\"]:\n            log.info(\"The content is unavailable\")\n            return\n\n        geoblocked, media, self.author, self.title, show = data[\"widgets\"]\n        if geoblocked:\n            log.info(\"The content is not available in your region\")\n            return\n        if show:\n            self.title = f\"{show}: {self.title}\"\n\n        if media.get(\"auto\"):\n            yield from HLSStream.parse_variant_playlist(self.session, media.get(\"auto\")).items()\n        else:\n            for quality, stream in media.items():\n                yield self._QUALITY_MAP.get(quality, quality), HTTPStream(self.session, stream)\n\n\n__plugin__ = ARDMediathek\n", "path": "src/streamlink/plugins/ard_mediathek.py"}]}