We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
plugins.artetv: error: Unable to validate response text: ValidationError(dict):
### Checklist

- [X] This is a [plugin issue](https://streamlink.github.io/plugins.html) and not [a different kind of issue](https://github.com/streamlink/streamlink/issues/new/choose)
- [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
streamlink 6.5.0

### Description

I  fix this issue 
```
by adding '**API_HLS_NG**'     in line 51  of file 
`/usr/lib/python3.11/site-packages/streamlink/plugins/artetv.py`
like  this :
```
![image](https://github.com/streamlink/streamlink/assets/19744191/b78f47ba-67b2-439b-b336-85bef7e4615a)
link/streamlink/assets/19744191/b78f47ba-67b2-439b-b336-85bef7e4615a)

### Debug log

```text
error: Unable to validate response text: ValidationError(dict):
  Unable to validate value of key 'data'
  Context(dict):
    Unable to validate value of key 'attributes'
    Context(dict):
      Unable to validate value of key 'streams'
      Context(AnySchema):
        ValidationError(AnySchema):
        ValidationError(AnySchema):
          ValidationError(dict):
            Unable to validate value of key 'protocol'
            Context(AnySchema):
              ValidationError(equality):
                'API_HLS_NG' does not equal 'HLS'
              ValidationError(equality):
                'API_HLS_NG' does not equal 'HLS_NG'
```


--- 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/artetv.py`
Content:
```
1 """
2 $description European public service channel promoting culture, including magazine shows, concerts and documentaries.
3 $url arte.tv
4 $type live, vod
5 $metadata title
6 """
7 
8 import logging
9 import re
10 from operator import itemgetter
11 
12 from streamlink.plugin import Plugin, pluginmatcher
13 from streamlink.plugin.api import validate
14 from streamlink.stream.hls import HLSStream
15 
16 
17 log = logging.getLogger(__name__)
18 
19 
20 @pluginmatcher(re.compile(r"""
21     https?://(?:\w+\.)?arte\.tv/(?:guide/)?
22     (?P<language>[a-z]{2})/
23     (?:
24         (?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+
25         |
26         (?:direct|live)
27     )
28 """, re.VERBOSE))
29 class ArteTV(Plugin):
30     API_URL = "https://api.arte.tv/api/player/v2/config/{0}/{1}"
31     API_TOKEN = "MzYyZDYyYmM1Y2Q3ZWRlZWFjMmIyZjZjNTRiMGY4MzY4NzBhOWQ5YjE4MGQ1NGFiODJmOTFlZDQwN2FkOTZjMQ"
32 
33     def _get_streams(self):
34         language = self.match.group("language")
35         video_id = self.match.group("video_id")
36 
37         json_url = self.API_URL.format(language, video_id or "LIVE")
38         headers = {
39             "Authorization": f"Bearer {self.API_TOKEN}",
40         }
41         streams, metadata = self.session.http.get(json_url, headers=headers, schema=validate.Schema(
42             validate.parse_json(),
43             {"data": {"attributes": {
44                 "streams": validate.any(
45                     [],
46                     [
47                         validate.all(
48                             {
49                                 "url": validate.url(),
50                                 "slot": int,
51                                 "protocol": validate.any("HLS", "HLS_NG"),
52                             },
53                             validate.union_get("slot", "protocol", "url"),
54                         ),
55                     ],
56                 ),
57                 "metadata": {
58                     "title": str,
59                     "subtitle": validate.any(None, str),
60                 },
61             }}},
62             validate.get(("data", "attributes")),
63             validate.union_get("streams", "metadata"),
64         ))
65 
66         if not streams:
67             return
68 
69         self.title = f"{metadata['title']} - {metadata['subtitle']}" if metadata["subtitle"] else metadata["title"]
70 
71         for _slot, _protocol, url in sorted(streams, key=itemgetter(0)):
72             return HLSStream.parse_variant_playlist(self.session, url)
73 
74 
75 __plugin__ = ArteTV
76
```
--- 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/artetv.py b/src/streamlink/plugins/artetv.py
--- a/src/streamlink/plugins/artetv.py
+++ b/src/streamlink/plugins/artetv.py
@@ -2,6 +2,7 @@
 $description European public service channel promoting culture, including magazine shows, concerts and documentaries.
 $url arte.tv
 $type live, vod
+$metadata id
 $metadata title
 """
 
@@ -17,38 +18,41 @@
 log = logging.getLogger(__name__)
 
 
-@pluginmatcher(re.compile(r"""
-    https?://(?:\w+\.)?arte\.tv/(?:guide/)?
-    (?P<language>[a-z]{2})/
-    (?:
-        (?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+
-        |
-        (?:direct|live)
-    )
-""", re.VERBOSE))
+@pluginmatcher(
+    name="live",
+    pattern=re.compile(
+        r"https?://(?:\w+\.)?arte\.tv/(?P<language>[a-z]{2})/(?:direct|live)/?",
+    ),
+)
+@pluginmatcher(
+    name="vod",
+    pattern=re.compile(
+        r"https?://(?:\w+\.)?arte\.tv/(?:guide/)?(?P<language>[a-z]{2})/(?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+",
+    ),
+)
 class ArteTV(Plugin):
-    API_URL = "https://api.arte.tv/api/player/v2/config/{0}/{1}"
-    API_TOKEN = "MzYyZDYyYmM1Y2Q3ZWRlZWFjMmIyZjZjNTRiMGY4MzY4NzBhOWQ5YjE4MGQ1NGFiODJmOTFlZDQwN2FkOTZjMQ"
+    API_URL = "https://api.arte.tv/api/player/v2/config/{language}/{id}"
 
     def _get_streams(self):
-        language = self.match.group("language")
-        video_id = self.match.group("video_id")
+        self.id = self.match["video_id"] if self.matches["vod"] else "LIVE"
 
-        json_url = self.API_URL.format(language, video_id or "LIVE")
-        headers = {
-            "Authorization": f"Bearer {self.API_TOKEN}",
-        }
-        streams, metadata = self.session.http.get(json_url, headers=headers, schema=validate.Schema(
+        json_url = self.API_URL.format(
+            language=self.match["language"],
+            id=self.id,
+        )
+        streams, metadata = self.session.http.get(json_url, schema=validate.Schema(
             validate.parse_json(),
-            {"data": {"attributes": {
+            {"data": {"attributes": dict}},
+            validate.get(("data", "attributes")),
+            {
                 "streams": validate.any(
                     [],
                     [
                         validate.all(
                             {
-                                "url": validate.url(),
                                 "slot": int,
-                                "protocol": validate.any("HLS", "HLS_NG"),
+                                "protocol": str,
+                                "url": validate.url(),
                             },
                             validate.union_get("slot", "protocol", "url"),
                         ),
@@ -58,17 +62,15 @@
                     "title": str,
                     "subtitle": validate.any(None, str),
                 },
-            }}},
-            validate.get(("data", "attributes")),
+            },
             validate.union_get("streams", "metadata"),
         ))
 
-        if not streams:
-            return
-
         self.title = f"{metadata['title']} - {metadata['subtitle']}" if metadata["subtitle"] else metadata["title"]
 
-        for _slot, _protocol, url in sorted(streams, key=itemgetter(0)):
+        for _slot, protocol, url in sorted(streams, key=itemgetter(0)):
+            if "HLS" not in protocol:
+                continue
             return HLSStream.parse_variant_playlist(self.session, url)

{"golden_diff": "diff --git a/src/streamlink/plugins/artetv.py b/src/streamlink/plugins/artetv.py\n--- a/src/streamlink/plugins/artetv.py\n+++ b/src/streamlink/plugins/artetv.py\n@@ -2,6 +2,7 @@\n $description European public service channel promoting culture, including magazine shows, concerts and documentaries.\n $url arte.tv\n $type live, vod\n+$metadata id\n $metadata title\n \"\"\"\n \n@@ -17,38 +18,41 @@\n log = logging.getLogger(__name__)\n \n \n-@pluginmatcher(re.compile(r\"\"\"\n-    https?://(?:\\w+\\.)?arte\\.tv/(?:guide/)?\n-    (?P<language>[a-z]{2})/\n-    (?:\n-        (?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+\n-        |\n-        (?:direct|live)\n-    )\n-\"\"\", re.VERBOSE))\n+@pluginmatcher(\n+    name=\"live\",\n+    pattern=re.compile(\n+        r\"https?://(?:\\w+\\.)?arte\\.tv/(?P<language>[a-z]{2})/(?:direct|live)/?\",\n+    ),\n+)\n+@pluginmatcher(\n+    name=\"vod\",\n+    pattern=re.compile(\n+        r\"https?://(?:\\w+\\.)?arte\\.tv/(?:guide/)?(?P<language>[a-z]{2})/(?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+\",\n+    ),\n+)\n class ArteTV(Plugin):\n-    API_URL = \"https://api.arte.tv/api/player/v2/config/{0}/{1}\"\n-    API_TOKEN = \"MzYyZDYyYmM1Y2Q3ZWRlZWFjMmIyZjZjNTRiMGY4MzY4NzBhOWQ5YjE4MGQ1NGFiODJmOTFlZDQwN2FkOTZjMQ\"\n+    API_URL = \"https://api.arte.tv/api/player/v2/config/{language}/{id}\"\n \n     def _get_streams(self):\n-        language = self.match.group(\"language\")\n-        video_id = self.match.group(\"video_id\")\n+        self.id = self.match[\"video_id\"] if self.matches[\"vod\"] else \"LIVE\"\n \n-        json_url = self.API_URL.format(language, video_id or \"LIVE\")\n-        headers = {\n-            \"Authorization\": f\"Bearer {self.API_TOKEN}\",\n-        }\n-        streams, metadata = self.session.http.get(json_url, headers=headers, schema=validate.Schema(\n+        json_url = self.API_URL.format(\n+            language=self.match[\"language\"],\n+            id=self.id,\n+        )\n+        streams, metadata = self.session.http.get(json_url, schema=validate.Schema(\n             validate.parse_json(),\n-            {\"data\": {\"attributes\": {\n+            {\"data\": {\"attributes\": dict}},\n+            validate.get((\"data\", \"attributes\")),\n+            {\n                 \"streams\": validate.any(\n                     [],\n                     [\n                         validate.all(\n                             {\n-                                \"url\": validate.url(),\n                                 \"slot\": int,\n-                                \"protocol\": validate.any(\"HLS\", \"HLS_NG\"),\n+                                \"protocol\": str,\n+                                \"url\": validate.url(),\n                             },\n                             validate.union_get(\"slot\", \"protocol\", \"url\"),\n                         ),\n@@ -58,17 +62,15 @@\n                     \"title\": str,\n                     \"subtitle\": validate.any(None, str),\n                 },\n-            }}},\n-            validate.get((\"data\", \"attributes\")),\n+            },\n             validate.union_get(\"streams\", \"metadata\"),\n         ))\n \n-        if not streams:\n-            return\n-\n         self.title = f\"{metadata['title']} - {metadata['subtitle']}\" if metadata[\"subtitle\"] else metadata[\"title\"]\n \n-        for _slot, _protocol, url in sorted(streams, key=itemgetter(0)):\n+        for _slot, protocol, url in sorted(streams, key=itemgetter(0)):\n+            if \"HLS\" not in protocol:\n+                continue\n             return HLSStream.parse_variant_playlist(self.session, url)\n", "issue": "plugins.artetv: error: Unable to validate response text: ValidationError(dict):\n### Checklist\r\n\r\n- [X] This is a [plugin issue](https://streamlink.github.io/plugins.html) and not [a different kind of issue](https://github.com/streamlink/streamlink/issues/new/choose)\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\nstreamlink 6.5.0\r\n\r\n### Description\r\n\r\nI  fix this issue \r\n```\r\nby adding '**API_HLS_NG**'     in line 51  of file \r\n`/usr/lib/python3.11/site-packages/streamlink/plugins/artetv.py`\r\nlike  this :\r\n```\r\n![image](https://github.com/streamlink/streamlink/assets/19744191/b78f47ba-67b2-439b-b336-85bef7e4615a)\r\nlink/streamlink/assets/19744191/b78f47ba-67b2-439b-b336-85bef7e4615a)\r\n\r\n### Debug log\r\n\r\n```text\r\nerror: Unable to validate response text: ValidationError(dict):\r\n  Unable to validate value of key 'data'\r\n  Context(dict):\r\n    Unable to validate value of key 'attributes'\r\n    Context(dict):\r\n      Unable to validate value of key 'streams'\r\n      Context(AnySchema):\r\n        ValidationError(AnySchema):\r\n        ValidationError(AnySchema):\r\n          ValidationError(dict):\r\n            Unable to validate value of key 'protocol'\r\n            Context(AnySchema):\r\n              ValidationError(equality):\r\n                'API_HLS_NG' does not equal 'HLS'\r\n              ValidationError(equality):\r\n                'API_HLS_NG' does not equal 'HLS_NG'\r\n```\r\n\n", "before_files": [{"content": "\"\"\"\n$description European public service channel promoting culture, including magazine shows, concerts and documentaries.\n$url arte.tv\n$type live, vod\n$metadata title\n\"\"\"\n\nimport logging\nimport re\nfrom operator import itemgetter\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(re.compile(r\"\"\"\n    https?://(?:\\w+\\.)?arte\\.tv/(?:guide/)?\n    (?P<language>[a-z]{2})/\n    (?:\n        (?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+\n        |\n        (?:direct|live)\n    )\n\"\"\", re.VERBOSE))\nclass ArteTV(Plugin):\n    API_URL = \"https://api.arte.tv/api/player/v2/config/{0}/{1}\"\n    API_TOKEN = \"MzYyZDYyYmM1Y2Q3ZWRlZWFjMmIyZjZjNTRiMGY4MzY4NzBhOWQ5YjE4MGQ1NGFiODJmOTFlZDQwN2FkOTZjMQ\"\n\n    def _get_streams(self):\n        language = self.match.group(\"language\")\n        video_id = self.match.group(\"video_id\")\n\n        json_url = self.API_URL.format(language, video_id or \"LIVE\")\n        headers = {\n            \"Authorization\": f\"Bearer {self.API_TOKEN}\",\n        }\n        streams, metadata = self.session.http.get(json_url, headers=headers, schema=validate.Schema(\n            validate.parse_json(),\n            {\"data\": {\"attributes\": {\n                \"streams\": validate.any(\n                    [],\n                    [\n                        validate.all(\n                            {\n                                \"url\": validate.url(),\n                                \"slot\": int,\n                                \"protocol\": validate.any(\"HLS\", \"HLS_NG\"),\n                            },\n                            validate.union_get(\"slot\", \"protocol\", \"url\"),\n                        ),\n                    ],\n                ),\n                \"metadata\": {\n                    \"title\": str,\n                    \"subtitle\": validate.any(None, str),\n                },\n            }}},\n            validate.get((\"data\", \"attributes\")),\n            validate.union_get(\"streams\", \"metadata\"),\n        ))\n\n        if not streams:\n            return\n\n        self.title = f\"{metadata['title']} - {metadata['subtitle']}\" if metadata[\"subtitle\"] else metadata[\"title\"]\n\n        for _slot, _protocol, url in sorted(streams, key=itemgetter(0)):\n            return HLSStream.parse_variant_playlist(self.session, url)\n\n\n__plugin__ = ArteTV\n", "path": "src/streamlink/plugins/artetv.py"}], "after_files": [{"content": "\"\"\"\n$description European public service channel promoting culture, including magazine shows, concerts and documentaries.\n$url arte.tv\n$type live, vod\n$metadata id\n$metadata title\n\"\"\"\n\nimport logging\nimport re\nfrom operator import itemgetter\n\nfrom streamlink.plugin import Plugin, pluginmatcher\nfrom streamlink.plugin.api import validate\nfrom streamlink.stream.hls import HLSStream\n\n\nlog = logging.getLogger(__name__)\n\n\n@pluginmatcher(\n    name=\"live\",\n    pattern=re.compile(\n        r\"https?://(?:\\w+\\.)?arte\\.tv/(?P<language>[a-z]{2})/(?:direct|live)/?\",\n    ),\n)\n@pluginmatcher(\n    name=\"vod\",\n    pattern=re.compile(\n        r\"https?://(?:\\w+\\.)?arte\\.tv/(?:guide/)?(?P<language>[a-z]{2})/(?:videos/)?(?P<video_id>(?!RC-|videos)[^/]+?)/.+\",\n    ),\n)\nclass ArteTV(Plugin):\n    API_URL = \"https://api.arte.tv/api/player/v2/config/{language}/{id}\"\n\n    def _get_streams(self):\n        self.id = self.match[\"video_id\"] if self.matches[\"vod\"] else \"LIVE\"\n\n        json_url = self.API_URL.format(\n            language=self.match[\"language\"],\n            id=self.id,\n        )\n        streams, metadata = self.session.http.get(json_url, schema=validate.Schema(\n            validate.parse_json(),\n            {\"data\": {\"attributes\": dict}},\n            validate.get((\"data\", \"attributes\")),\n            {\n                \"streams\": validate.any(\n                    [],\n                    [\n                        validate.all(\n                            {\n                                \"slot\": int,\n                                \"protocol\": str,\n                                \"url\": validate.url(),\n                            },\n                            validate.union_get(\"slot\", \"protocol\", \"url\"),\n                        ),\n                    ],\n                ),\n                \"metadata\": {\n                    \"title\": str,\n                    \"subtitle\": validate.any(None, str),\n                },\n            },\n            validate.union_get(\"streams\", \"metadata\"),\n        ))\n\n        self.title = f\"{metadata['title']} - {metadata['subtitle']}\" if metadata[\"subtitle\"] else metadata[\"title\"]\n\n        for _slot, protocol, url in sorted(streams, key=itemgetter(0)):\n            if \"HLS\" not in protocol:\n                continue\n            return HLSStream.parse_variant_playlist(self.session, url)\n\n\n__plugin__ = ArteTV\n", "path": "src/streamlink/plugins/artetv.py"}]}