We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[media.ccc.de:lists] playlist_id should be case-sensitive
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting that yt-dlp is broken on a **supported** site
- [X] I've verified that I'm running yt-dlp version **2023.07.06** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)
- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates
- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)
- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required

### Region

_No response_

### Provide a description that is worded well enough to be understood

Some playlists use uppercase `playlist_id`s, like `https://media.ccc.de/c/DS2023` → `https://media.ccc.de/public/conferences/DS2022` or `https://media.ccc.de/c/MCH2022` → `https://media.ccc.de/public/conferences/MCH2022`. So I guess removing `.lower()` in https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/ccc.py#L96 should resolve this.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
$ python -m yt_dlp --verbose --ignore-config https://media.ccc.de/c/DS2023
[debug] Command-line config: ['--verbose', '--ignore-config', 'https://media.ccc.de/c/DS2023']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8
[debug] yt-dlp version stable@2023.07.06 [b532a3481] (source)
[debug] Lazy loading extractors is disabled
[debug] Git HEAD: 30ba233d4
[debug] Python 3.11.5 (CPython x86_64 64bit) - Linux-6.5.0-5-generic-x86_64-with-glibc2.38 (OpenSSL 3.0.10 1 Aug 2023, glibc 2.38)
[debug] exe versions: ffmpeg 6.0 (setts), ffprobe 6.0, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.11.0, brotli-1.0.9, certifi-2022.09.24, mutagen-1.46.0, pyxattr-0.8.1, secretstorage-3.3.3, sqlite3-2.6.0, websockets-10.4
[debug] Proxy map: {}
[debug] Loaded 1866 extractors
[media.ccc.de:lists] Extracting URL: https://media.ccc.de/c/DS2023
[media.ccc.de:lists] ds2023: Downloading JSON metadata
ERROR: [media.ccc.de:lists] DS2023: Unable to download JSON metadata: HTTP Error 404: Not Found (caused by <HTTPError 404: Not Found>); please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U
[…]
The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/tmp/yt-dlp/yt_dlp/extractor/common.py", line 847, in _request_webpage
    return self._downloader.urlopen(self._create_request(url_or_request, data, headers, query))
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/tmp/yt-dlp/yt_dlp/YoutubeDL.py", line 4078, in urlopen
    raise _CompatHTTPError(e) from e
yt_dlp.networking.exceptions._CompatHTTPError: HTTP Error 404: Not Found
```


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `yt_dlp/extractor/ccc.py`
Content:
```
1 from .common import InfoExtractor
2 from ..utils import (
3     int_or_none,
4     parse_iso8601,
5     try_get,
6     url_or_none,
7 )
8 
9 
10 class CCCIE(InfoExtractor):
11     IE_NAME = 'media.ccc.de'
12     _VALID_URL = r'https?://(?:www\.)?media\.ccc\.de/v/(?P<id>[^/?#&]+)'
13 
14     _TESTS = [{
15         'url': 'https://media.ccc.de/v/30C3_-_5443_-_en_-_saal_g_-_201312281830_-_introduction_to_processor_design_-_byterazor#video',
16         'md5': '3a1eda8f3a29515d27f5adb967d7e740',
17         'info_dict': {
18             'id': '1839',
19             'ext': 'mp4',
20             'title': 'Introduction to Processor Design',
21             'creator': 'byterazor',
22             'description': 'md5:df55f6d073d4ceae55aae6f2fd98a0ac',
23             'thumbnail': r're:^https?://.*\.jpg$',
24             'upload_date': '20131228',
25             'timestamp': 1388188800,
26             'duration': 3710,
27             'tags': list,
28         }
29     }, {
30         'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',
31         'only_matching': True,
32     }]
33 
34     def _real_extract(self, url):
35         display_id = self._match_id(url)
36         webpage = self._download_webpage(url, display_id)
37         event_id = self._search_regex(r"data-id='(\d+)'", webpage, 'event id')
38         event_data = self._download_json('https://media.ccc.de/public/events/%s' % event_id, event_id)
39 
40         formats = []
41         for recording in event_data.get('recordings', []):
42             recording_url = recording.get('recording_url')
43             if not recording_url:
44                 continue
45             language = recording.get('language')
46             folder = recording.get('folder')
47             format_id = None
48             if language:
49                 format_id = language
50             if folder:
51                 if language:
52                     format_id += '-' + folder
53                 else:
54                     format_id = folder
55             vcodec = 'h264' if 'h264' in folder else (
56                 'none' if folder in ('mp3', 'opus') else None
57             )
58             formats.append({
59                 'format_id': format_id,
60                 'url': recording_url,
61                 'width': int_or_none(recording.get('width')),
62                 'height': int_or_none(recording.get('height')),
63                 'filesize': int_or_none(recording.get('size'), invscale=1024 * 1024),
64                 'language': language,
65                 'vcodec': vcodec,
66             })
67 
68         return {
69             'id': event_id,
70             'display_id': display_id,
71             'title': event_data['title'],
72             'creator': try_get(event_data, lambda x: ', '.join(x['persons'])),
73             'description': event_data.get('description'),
74             'thumbnail': event_data.get('thumb_url'),
75             'timestamp': parse_iso8601(event_data.get('date')),
76             'duration': int_or_none(event_data.get('length')),
77             'view_count': int_or_none(event_data.get('view_count')),
78             'tags': event_data.get('tags'),
79             'formats': formats,
80         }
81 
82 
83 class CCCPlaylistIE(InfoExtractor):
84     IE_NAME = 'media.ccc.de:lists'
85     _VALID_URL = r'https?://(?:www\.)?media\.ccc\.de/c/(?P<id>[^/?#&]+)'
86     _TESTS = [{
87         'url': 'https://media.ccc.de/c/30c3',
88         'info_dict': {
89             'title': '30C3',
90             'id': '30c3',
91         },
92         'playlist_count': 135,
93     }]
94 
95     def _real_extract(self, url):
96         playlist_id = self._match_id(url).lower()
97 
98         conf = self._download_json(
99             'https://media.ccc.de/public/conferences/' + playlist_id,
100             playlist_id)
101 
102         entries = []
103         for e in conf['events']:
104             event_url = url_or_none(e.get('frontend_link'))
105             if event_url:
106                 entries.append(self.url_result(event_url, ie=CCCIE.ie_key()))
107 
108         return self.playlist_result(entries, playlist_id, conf.get('title'))
109
```
--- 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/yt_dlp/extractor/ccc.py b/yt_dlp/extractor/ccc.py
--- a/yt_dlp/extractor/ccc.py
+++ b/yt_dlp/extractor/ccc.py
@@ -90,10 +90,17 @@
             'id': '30c3',
         },
         'playlist_count': 135,
+    }, {
+        'url': 'https://media.ccc.de/c/DS2023',
+        'info_dict': {
+            'title': 'Datenspuren 2023',
+            'id': 'DS2023',
+        },
+        'playlist_count': 37
     }]
 
     def _real_extract(self, url):
-        playlist_id = self._match_id(url).lower()
+        playlist_id = self._match_id(url)
 
         conf = self._download_json(
             'https://media.ccc.de/public/conferences/' + playlist_id,

{"golden_diff": "diff --git a/yt_dlp/extractor/ccc.py b/yt_dlp/extractor/ccc.py\n--- a/yt_dlp/extractor/ccc.py\n+++ b/yt_dlp/extractor/ccc.py\n@@ -90,10 +90,17 @@\n             'id': '30c3',\n         },\n         'playlist_count': 135,\n+    }, {\n+        'url': 'https://media.ccc.de/c/DS2023',\n+        'info_dict': {\n+            'title': 'Datenspuren 2023',\n+            'id': 'DS2023',\n+        },\n+        'playlist_count': 37\n     }]\n \n     def _real_extract(self, url):\n-        playlist_id = self._match_id(url).lower()\n+        playlist_id = self._match_id(url)\n \n         conf = self._download_json(\n             'https://media.ccc.de/public/conferences/' + playlist_id,\n", "issue": "[media.ccc.de:lists] playlist_id should be case-sensitive\n### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE\n\n- [X] I understand that I will be **blocked** if I *intentionally* remove or skip any mandatory\\* field\n\n### Checklist\n\n- [X] I'm reporting that yt-dlp is broken on a **supported** site\n- [X] I've verified that I'm running yt-dlp version **2023.07.06** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)\n- [X] I've checked that all provided URLs are playable in a browser with the same IP and same login details\n- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/yt-dlp/yt-dlp/wiki/FAQ#video-url-contains-an-ampersand--and-im-getting-some-strange-output-1-2839-or-v-is-not-recognized-as-an-internal-or-external-command)\n- [X] I've searched [known issues](https://github.com/yt-dlp/yt-dlp/issues/3766) and the [bugtracker](https://github.com/yt-dlp/yt-dlp/issues?q=) for similar issues **including closed ones**. DO NOT post duplicates\n- [X] I've read the [guidelines for opening an issue](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#opening-an-issue)\n- [ ] I've read about [sharing account credentials](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#are-you-willing-to-share-account-details-if-needed) and I'm willing to share it if required\n\n### Region\n\n_No response_\n\n### Provide a description that is worded well enough to be understood\n\nSome playlists use uppercase `playlist_id`s, like `https://media.ccc.de/c/DS2023` \u2192 `https://media.ccc.de/public/conferences/DS2022` or `https://media.ccc.de/c/MCH2022` \u2192 `https://media.ccc.de/public/conferences/MCH2022`. So I guess removing `.lower()` in https://github.com/yt-dlp/yt-dlp/blob/master/yt_dlp/extractor/ccc.py#L96 should resolve this.\n\n### Provide verbose output that clearly demonstrates the problem\n\n- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)\n- [ ] If using API, add `'verbose': True` to `YoutubeDL` params instead\n- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below\n\n### Complete Verbose Output\n\n```shell\n$ python -m yt_dlp --verbose --ignore-config https://media.ccc.de/c/DS2023\r\n[debug] Command-line config: ['--verbose', '--ignore-config', 'https://media.ccc.de/c/DS2023']\r\n[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8, error utf-8, screen utf-8\r\n[debug] yt-dlp version stable@2023.07.06 [b532a3481] (source)\r\n[debug] Lazy loading extractors is disabled\r\n[debug] Git HEAD: 30ba233d4\r\n[debug] Python 3.11.5 (CPython x86_64 64bit) - Linux-6.5.0-5-generic-x86_64-with-glibc2.38 (OpenSSL 3.0.10 1 Aug 2023, glibc 2.38)\r\n[debug] exe versions: ffmpeg 6.0 (setts), ffprobe 6.0, rtmpdump 2.4\r\n[debug] Optional libraries: Cryptodome-3.11.0, brotli-1.0.9, certifi-2022.09.24, mutagen-1.46.0, pyxattr-0.8.1, secretstorage-3.3.3, sqlite3-2.6.0, websockets-10.4\r\n[debug] Proxy map: {}\r\n[debug] Loaded 1866 extractors\r\n[media.ccc.de:lists] Extracting URL: https://media.ccc.de/c/DS2023\r\n[media.ccc.de:lists] ds2023: Downloading JSON metadata\r\nERROR: [media.ccc.de:lists] DS2023: Unable to download JSON metadata: HTTP Error 404: Not Found (caused by <HTTPError 404: Not Found>); please report this issue on  https://github.com/yt-dlp/yt-dlp/issues?q= , filling out the appropriate issue template. Confirm you are on the latest version using  yt-dlp -U\r\n[\u2026]\r\nThe above exception was the direct cause of the following exception:\r\n\r\nTraceback (most recent call last):\r\n  File \"/tmp/yt-dlp/yt_dlp/extractor/common.py\", line 847, in _request_webpage\r\n    return self._downloader.urlopen(self._create_request(url_or_request, data, headers, query))\r\n           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\r\n  File \"/tmp/yt-dlp/yt_dlp/YoutubeDL.py\", line 4078, in urlopen\r\n    raise _CompatHTTPError(e) from e\r\nyt_dlp.networking.exceptions._CompatHTTPError: HTTP Error 404: Not Found\n```\n\n", "before_files": [{"content": "from .common import InfoExtractor\nfrom ..utils import (\n    int_or_none,\n    parse_iso8601,\n    try_get,\n    url_or_none,\n)\n\n\nclass CCCIE(InfoExtractor):\n    IE_NAME = 'media.ccc.de'\n    _VALID_URL = r'https?://(?:www\\.)?media\\.ccc\\.de/v/(?P<id>[^/?#&]+)'\n\n    _TESTS = [{\n        'url': 'https://media.ccc.de/v/30C3_-_5443_-_en_-_saal_g_-_201312281830_-_introduction_to_processor_design_-_byterazor#video',\n        'md5': '3a1eda8f3a29515d27f5adb967d7e740',\n        'info_dict': {\n            'id': '1839',\n            'ext': 'mp4',\n            'title': 'Introduction to Processor Design',\n            'creator': 'byterazor',\n            'description': 'md5:df55f6d073d4ceae55aae6f2fd98a0ac',\n            'thumbnail': r're:^https?://.*\\.jpg$',\n            'upload_date': '20131228',\n            'timestamp': 1388188800,\n            'duration': 3710,\n            'tags': list,\n        }\n    }, {\n        'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        display_id = self._match_id(url)\n        webpage = self._download_webpage(url, display_id)\n        event_id = self._search_regex(r\"data-id='(\\d+)'\", webpage, 'event id')\n        event_data = self._download_json('https://media.ccc.de/public/events/%s' % event_id, event_id)\n\n        formats = []\n        for recording in event_data.get('recordings', []):\n            recording_url = recording.get('recording_url')\n            if not recording_url:\n                continue\n            language = recording.get('language')\n            folder = recording.get('folder')\n            format_id = None\n            if language:\n                format_id = language\n            if folder:\n                if language:\n                    format_id += '-' + folder\n                else:\n                    format_id = folder\n            vcodec = 'h264' if 'h264' in folder else (\n                'none' if folder in ('mp3', 'opus') else None\n            )\n            formats.append({\n                'format_id': format_id,\n                'url': recording_url,\n                'width': int_or_none(recording.get('width')),\n                'height': int_or_none(recording.get('height')),\n                'filesize': int_or_none(recording.get('size'), invscale=1024 * 1024),\n                'language': language,\n                'vcodec': vcodec,\n            })\n\n        return {\n            'id': event_id,\n            'display_id': display_id,\n            'title': event_data['title'],\n            'creator': try_get(event_data, lambda x: ', '.join(x['persons'])),\n            'description': event_data.get('description'),\n            'thumbnail': event_data.get('thumb_url'),\n            'timestamp': parse_iso8601(event_data.get('date')),\n            'duration': int_or_none(event_data.get('length')),\n            'view_count': int_or_none(event_data.get('view_count')),\n            'tags': event_data.get('tags'),\n            'formats': formats,\n        }\n\n\nclass CCCPlaylistIE(InfoExtractor):\n    IE_NAME = 'media.ccc.de:lists'\n    _VALID_URL = r'https?://(?:www\\.)?media\\.ccc\\.de/c/(?P<id>[^/?#&]+)'\n    _TESTS = [{\n        'url': 'https://media.ccc.de/c/30c3',\n        'info_dict': {\n            'title': '30C3',\n            'id': '30c3',\n        },\n        'playlist_count': 135,\n    }]\n\n    def _real_extract(self, url):\n        playlist_id = self._match_id(url).lower()\n\n        conf = self._download_json(\n            'https://media.ccc.de/public/conferences/' + playlist_id,\n            playlist_id)\n\n        entries = []\n        for e in conf['events']:\n            event_url = url_or_none(e.get('frontend_link'))\n            if event_url:\n                entries.append(self.url_result(event_url, ie=CCCIE.ie_key()))\n\n        return self.playlist_result(entries, playlist_id, conf.get('title'))\n", "path": "yt_dlp/extractor/ccc.py"}], "after_files": [{"content": "from .common import InfoExtractor\nfrom ..utils import (\n    int_or_none,\n    parse_iso8601,\n    try_get,\n    url_or_none,\n)\n\n\nclass CCCIE(InfoExtractor):\n    IE_NAME = 'media.ccc.de'\n    _VALID_URL = r'https?://(?:www\\.)?media\\.ccc\\.de/v/(?P<id>[^/?#&]+)'\n\n    _TESTS = [{\n        'url': 'https://media.ccc.de/v/30C3_-_5443_-_en_-_saal_g_-_201312281830_-_introduction_to_processor_design_-_byterazor#video',\n        'md5': '3a1eda8f3a29515d27f5adb967d7e740',\n        'info_dict': {\n            'id': '1839',\n            'ext': 'mp4',\n            'title': 'Introduction to Processor Design',\n            'creator': 'byterazor',\n            'description': 'md5:df55f6d073d4ceae55aae6f2fd98a0ac',\n            'thumbnail': r're:^https?://.*\\.jpg$',\n            'upload_date': '20131228',\n            'timestamp': 1388188800,\n            'duration': 3710,\n            'tags': list,\n        }\n    }, {\n        'url': 'https://media.ccc.de/v/32c3-7368-shopshifting#download',\n        'only_matching': True,\n    }]\n\n    def _real_extract(self, url):\n        display_id = self._match_id(url)\n        webpage = self._download_webpage(url, display_id)\n        event_id = self._search_regex(r\"data-id='(\\d+)'\", webpage, 'event id')\n        event_data = self._download_json('https://media.ccc.de/public/events/%s' % event_id, event_id)\n\n        formats = []\n        for recording in event_data.get('recordings', []):\n            recording_url = recording.get('recording_url')\n            if not recording_url:\n                continue\n            language = recording.get('language')\n            folder = recording.get('folder')\n            format_id = None\n            if language:\n                format_id = language\n            if folder:\n                if language:\n                    format_id += '-' + folder\n                else:\n                    format_id = folder\n            vcodec = 'h264' if 'h264' in folder else (\n                'none' if folder in ('mp3', 'opus') else None\n            )\n            formats.append({\n                'format_id': format_id,\n                'url': recording_url,\n                'width': int_or_none(recording.get('width')),\n                'height': int_or_none(recording.get('height')),\n                'filesize': int_or_none(recording.get('size'), invscale=1024 * 1024),\n                'language': language,\n                'vcodec': vcodec,\n            })\n\n        return {\n            'id': event_id,\n            'display_id': display_id,\n            'title': event_data['title'],\n            'creator': try_get(event_data, lambda x: ', '.join(x['persons'])),\n            'description': event_data.get('description'),\n            'thumbnail': event_data.get('thumb_url'),\n            'timestamp': parse_iso8601(event_data.get('date')),\n            'duration': int_or_none(event_data.get('length')),\n            'view_count': int_or_none(event_data.get('view_count')),\n            'tags': event_data.get('tags'),\n            'formats': formats,\n        }\n\n\nclass CCCPlaylistIE(InfoExtractor):\n    IE_NAME = 'media.ccc.de:lists'\n    _VALID_URL = r'https?://(?:www\\.)?media\\.ccc\\.de/c/(?P<id>[^/?#&]+)'\n    _TESTS = [{\n        'url': 'https://media.ccc.de/c/30c3',\n        'info_dict': {\n            'title': '30C3',\n            'id': '30c3',\n        },\n        'playlist_count': 135,\n    }, {\n        'url': 'https://media.ccc.de/c/DS2023',\n        'info_dict': {\n            'title': 'Datenspuren 2023',\n            'id': 'DS2023',\n        },\n        'playlist_count': 37\n    }]\n\n    def _real_extract(self, url):\n        playlist_id = self._match_id(url)\n\n        conf = self._download_json(\n            'https://media.ccc.de/public/conferences/' + playlist_id,\n            playlist_id)\n\n        entries = []\n        for e in conf['events']:\n            event_url = url_or_none(e.get('frontend_link'))\n            if event_url:\n                entries.append(self.url_result(event_url, ie=CCCIE.ie_key()))\n\n        return self.playlist_result(entries, playlist_id, conf.get('title'))\n", "path": "yt_dlp/extractor/ccc.py"}]}