We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[DigitalConcertHall] cannot download videos under /films
### 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.03.04** ([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)
- [X] 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

All

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

A major part of the site Digital Concert Hall is [concert videos](https://www.digitalconcerthall.com/en/concerts) which yt-dlp handles just fine. But when I try to download videos [here](https://www.digitalconcerthall.com/en/films), e.g. [this one](https://www.digitalconcerthall.com/en/film/388) which lasts 44 minutes (can be played with the login credentials `--username deydihurdo@gufum.com --password 3PXx-5.NDNmMD2!` which you can use), it only downloads the trailer which lasts 39 seconds. Using build from commit `ecfe479`.

### Provide verbose output that clearly demonstrates the problem

- [X] Run **your** yt-dlp command with **-vU** flag added (`yt-dlp -vU <your command line>`)
- [X] 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
[debug] Command-line config: ['https://www.digitalconcerthall.com/en/film/388', '--username', 'PRIVATE', '--password', 'PRIVATE', '-vU']
[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.03.04 [392389b7d] (zip)
[debug] Python 3.11.3 (CPython x86_64 64bit) - Linux-6.3.4-arch2-1-x86_64-with-glibc2.37 (OpenSSL 3.0.8 7 Feb 2023, glibc 2.37)
[debug] exe versions: ffmpeg 6.0 (setts), ffprobe 6.0, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.17, brotli-1.0.9, certifi-2023.05.07, mutagen-1.46.0, sqlite3-2.6.0, websockets-11.0.3
[debug] Proxy map: {}
[debug] Loaded 1842 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.03.04, Current version: stable@2023.03.04
Current Build Hash: 5bfb7e4a15c47b2ff99b149b7c841e98ef606a4af18fd6330ddf3a0ed4a7ea19
yt-dlp is up to date (stable@2023.03.04)
[generic] Extracting URL: https://www.digitalconcerthall.com/en/film/388
[generic] 388: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] 388: Extracting information
[debug] Looking for embeds
[debug] Identified a JSON LD
[generic] Extracting URL: https://world-vod.dchdns.net/preview/388-t/preview.mp4#__youtubedl_smuggle=%7B%22force_videoid%22%3A+%22388%22%2C+%22to_generic%22%3A+true%2C+%22http_headers%22%3A+%7B%22Referer%22%3A+%22https%3A%2F%2Fwww.digitalconcerthall.com%2Fen%2Ffilm%2F388%22%7D%7D
[generic] 388: Downloading webpage
WARNING: [generic] URL could be a direct video link, returning it as such.
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] 388: Downloading 1 format(s): 0
[debug] Invoking http downloader on "https://world-vod.dchdns.net/preview/388-t/preview.mp4"
[download] Destination: The Berliner Philharmoniker and Frank Peter Zimmermann [388].mp4
[download] 100% of   16.16MiB in 00:00:07 at 2.05MiB/s
```


--- 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/digitalconcerthall.py`
Content:
```
1 from .common import InfoExtractor
2 
3 from ..utils import (
4     ExtractorError,
5     parse_resolution,
6     traverse_obj,
7     try_get,
8     urlencode_postdata,
9 )
10 
11 
12 class DigitalConcertHallIE(InfoExtractor):
13     IE_DESC = 'DigitalConcertHall extractor'
14     _VALID_URL = r'https?://(?:www\.)?digitalconcerthall\.com/(?P<language>[a-z]+)/concert/(?P<id>[0-9]+)'
15     _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token'
16     _ACCESS_TOKEN = None
17     _NETRC_MACHINE = 'digitalconcerthall'
18     _TESTS = [{
19         'note': 'Playlist with only one video',
20         'url': 'https://www.digitalconcerthall.com/en/concert/53201',
21         'info_dict': {
22             'id': '53201-1',
23             'ext': 'mp4',
24             'composer': 'Kurt Weill',
25             'title': '[Magic Night]',
26             'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\.jpg$',
27             'upload_date': '20210624',
28             'timestamp': 1624548600,
29             'duration': 2798,
30             'album_artist': 'Members of the Berliner Philharmoniker / Simon Rössler',
31         },
32         'params': {'skip_download': 'm3u8'},
33     }, {
34         'note': 'Concert with several works and an interview',
35         'url': 'https://www.digitalconcerthall.com/en/concert/53785',
36         'info_dict': {
37             'id': '53785',
38             'album_artist': 'Berliner Philharmoniker / Kirill Petrenko',
39             'title': 'Kirill Petrenko conducts Mendelssohn and Shostakovich',
40         },
41         'params': {'skip_download': 'm3u8'},
42         'playlist_count': 3,
43     }]
44 
45     def _perform_login(self, username, password):
46         token_response = self._download_json(
47             self._OAUTH_URL,
48             None, 'Obtaining token', errnote='Unable to obtain token', data=urlencode_postdata({
49                 'affiliate': 'none',
50                 'grant_type': 'device',
51                 'device_vendor': 'unknown',
52                 'app_id': 'dch.webapp',
53                 'app_version': '1.0.0',
54                 'client_secret': '2ySLN+2Fwb',
55             }), headers={
56                 'Content-Type': 'application/x-www-form-urlencoded',
57             })
58         self._ACCESS_TOKEN = token_response['access_token']
59         try:
60             self._download_json(
61                 self._OAUTH_URL,
62                 None, note='Logging in', errnote='Unable to login', data=urlencode_postdata({
63                     'grant_type': 'password',
64                     'username': username,
65                     'password': password,
66                 }), headers={
67                     'Content-Type': 'application/x-www-form-urlencoded',
68                     'Referer': 'https://www.digitalconcerthall.com',
69                     'Authorization': f'Bearer {self._ACCESS_TOKEN}'
70                 })
71         except ExtractorError:
72             self.raise_login_required(msg='Login info incorrect')
73 
74     def _real_initialize(self):
75         if not self._ACCESS_TOKEN:
76             self.raise_login_required(method='password')
77 
78     def _entries(self, items, language, **kwargs):
79         for item in items:
80             video_id = item['id']
81             stream_info = self._download_json(
82                 self._proto_relative_url(item['_links']['streams']['href']), video_id, headers={
83                     'Accept': 'application/json',
84                     'Authorization': f'Bearer {self._ACCESS_TOKEN}',
85                     'Accept-Language': language
86                 })
87 
88             m3u8_url = traverse_obj(
89                 stream_info, ('channel', lambda k, _: k.startswith('vod_mixed'), 'stream', 0, 'url'), get_all=False)
90             formats = self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', 'm3u8_native', fatal=False)
91 
92             yield {
93                 'id': video_id,
94                 'title': item.get('title'),
95                 'composer': item.get('name_composer'),
96                 'url': m3u8_url,
97                 'formats': formats,
98                 'duration': item.get('duration_total'),
99                 'timestamp': traverse_obj(item, ('date', 'published')),
100                 'description': item.get('short_description') or stream_info.get('short_description'),
101                 **kwargs,
102                 'chapters': [{
103                     'start_time': chapter.get('time'),
104                     'end_time': try_get(chapter, lambda x: x['time'] + x['duration']),
105                     'title': chapter.get('text'),
106                 } for chapter in item['cuepoints']] if item.get('cuepoints') else None,
107             }
108 
109     def _real_extract(self, url):
110         language, video_id = self._match_valid_url(url).group('language', 'id')
111         if not language:
112             language = 'en'
113 
114         thumbnail_url = self._html_search_regex(
115             r'(https?://images\.digitalconcerthall\.com/cms/thumbnails/.*\.jpg)',
116             self._download_webpage(url, video_id), 'thumbnail')
117         thumbnails = [{
118             'url': thumbnail_url,
119             **parse_resolution(thumbnail_url)
120         }]
121 
122         vid_info = self._download_json(
123             f'https://api.digitalconcerthall.com/v2/concert/{video_id}', video_id, headers={
124                 'Accept': 'application/json',
125                 'Accept-Language': language
126             })
127         album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '')
128 
129         return {
130             '_type': 'playlist',
131             'id': video_id,
132             'title': vid_info.get('title'),
133             'entries': self._entries(traverse_obj(vid_info, ('_embedded', ..., ...)), language,
134                                      thumbnails=thumbnails, album_artist=album_artist),
135             'thumbnails': thumbnails,
136             'album_artist': album_artist,
137         }
138
```
--- 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/digitalconcerthall.py b/yt_dlp/extractor/digitalconcerthall.py
--- a/yt_dlp/extractor/digitalconcerthall.py
+++ b/yt_dlp/extractor/digitalconcerthall.py
@@ -11,7 +11,7 @@
 
 class DigitalConcertHallIE(InfoExtractor):
     IE_DESC = 'DigitalConcertHall extractor'
-    _VALID_URL = r'https?://(?:www\.)?digitalconcerthall\.com/(?P<language>[a-z]+)/concert/(?P<id>[0-9]+)'
+    _VALID_URL = r'https?://(?:www\.)?digitalconcerthall\.com/(?P<language>[a-z]+)/(?P<type>film|concert)/(?P<id>[0-9]+)'
     _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token'
     _ACCESS_TOKEN = None
     _NETRC_MACHINE = 'digitalconcerthall'
@@ -40,6 +40,19 @@
         },
         'params': {'skip_download': 'm3u8'},
         'playlist_count': 3,
+    }, {
+        'url': 'https://www.digitalconcerthall.com/en/film/388',
+        'info_dict': {
+            'id': '388',
+            'ext': 'mp4',
+            'title': 'The Berliner Philharmoniker and Frank Peter Zimmermann',
+            'description': 'md5:cfe25a7044fa4be13743e5089b5b5eb2',
+            'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\.jpg$',
+            'upload_date': '20220714',
+            'timestamp': 1657785600,
+            'album_artist': 'Frank Peter Zimmermann / Benedikt von Bernstorff / Jakob von Bernstorff',
+        },
+        'params': {'skip_download': 'm3u8'},
     }]
 
     def _perform_login(self, username, password):
@@ -75,7 +88,7 @@
         if not self._ACCESS_TOKEN:
             self.raise_login_required(method='password')
 
-    def _entries(self, items, language, **kwargs):
+    def _entries(self, items, language, type_, **kwargs):
         for item in items:
             video_id = item['id']
             stream_info = self._download_json(
@@ -103,11 +116,11 @@
                     'start_time': chapter.get('time'),
                     'end_time': try_get(chapter, lambda x: x['time'] + x['duration']),
                     'title': chapter.get('text'),
-                } for chapter in item['cuepoints']] if item.get('cuepoints') else None,
+                } for chapter in item['cuepoints']] if item.get('cuepoints') and type_ == 'concert' else None,
             }
 
     def _real_extract(self, url):
-        language, video_id = self._match_valid_url(url).group('language', 'id')
+        language, type_, video_id = self._match_valid_url(url).group('language', 'type', 'id')
         if not language:
             language = 'en'
 
@@ -120,18 +133,18 @@
         }]
 
         vid_info = self._download_json(
-            f'https://api.digitalconcerthall.com/v2/concert/{video_id}', video_id, headers={
+            f'https://api.digitalconcerthall.com/v2/{type_}/{video_id}', video_id, headers={
                 'Accept': 'application/json',
                 'Accept-Language': language
             })
         album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '')
+        videos = [vid_info] if type_ == 'film' else traverse_obj(vid_info, ('_embedded', ..., ...))
 
         return {
             '_type': 'playlist',
             'id': video_id,
             'title': vid_info.get('title'),
-            'entries': self._entries(traverse_obj(vid_info, ('_embedded', ..., ...)), language,
-                                     thumbnails=thumbnails, album_artist=album_artist),
+            'entries': self._entries(videos, language, thumbnails=thumbnails, album_artist=album_artist, type_=type_),
             'thumbnails': thumbnails,
             'album_artist': album_artist,
         }

{"golden_diff": "diff --git a/yt_dlp/extractor/digitalconcerthall.py b/yt_dlp/extractor/digitalconcerthall.py\n--- a/yt_dlp/extractor/digitalconcerthall.py\n+++ b/yt_dlp/extractor/digitalconcerthall.py\n@@ -11,7 +11,7 @@\n \n class DigitalConcertHallIE(InfoExtractor):\n     IE_DESC = 'DigitalConcertHall extractor'\n-    _VALID_URL = r'https?://(?:www\\.)?digitalconcerthall\\.com/(?P<language>[a-z]+)/concert/(?P<id>[0-9]+)'\n+    _VALID_URL = r'https?://(?:www\\.)?digitalconcerthall\\.com/(?P<language>[a-z]+)/(?P<type>film|concert)/(?P<id>[0-9]+)'\n     _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token'\n     _ACCESS_TOKEN = None\n     _NETRC_MACHINE = 'digitalconcerthall'\n@@ -40,6 +40,19 @@\n         },\n         'params': {'skip_download': 'm3u8'},\n         'playlist_count': 3,\n+    }, {\n+        'url': 'https://www.digitalconcerthall.com/en/film/388',\n+        'info_dict': {\n+            'id': '388',\n+            'ext': 'mp4',\n+            'title': 'The Berliner Philharmoniker and Frank Peter Zimmermann',\n+            'description': 'md5:cfe25a7044fa4be13743e5089b5b5eb2',\n+            'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\\.jpg$',\n+            'upload_date': '20220714',\n+            'timestamp': 1657785600,\n+            'album_artist': 'Frank Peter Zimmermann / Benedikt von Bernstorff / Jakob von Bernstorff',\n+        },\n+        'params': {'skip_download': 'm3u8'},\n     }]\n \n     def _perform_login(self, username, password):\n@@ -75,7 +88,7 @@\n         if not self._ACCESS_TOKEN:\n             self.raise_login_required(method='password')\n \n-    def _entries(self, items, language, **kwargs):\n+    def _entries(self, items, language, type_, **kwargs):\n         for item in items:\n             video_id = item['id']\n             stream_info = self._download_json(\n@@ -103,11 +116,11 @@\n                     'start_time': chapter.get('time'),\n                     'end_time': try_get(chapter, lambda x: x['time'] + x['duration']),\n                     'title': chapter.get('text'),\n-                } for chapter in item['cuepoints']] if item.get('cuepoints') else None,\n+                } for chapter in item['cuepoints']] if item.get('cuepoints') and type_ == 'concert' else None,\n             }\n \n     def _real_extract(self, url):\n-        language, video_id = self._match_valid_url(url).group('language', 'id')\n+        language, type_, video_id = self._match_valid_url(url).group('language', 'type', 'id')\n         if not language:\n             language = 'en'\n \n@@ -120,18 +133,18 @@\n         }]\n \n         vid_info = self._download_json(\n-            f'https://api.digitalconcerthall.com/v2/concert/{video_id}', video_id, headers={\n+            f'https://api.digitalconcerthall.com/v2/{type_}/{video_id}', video_id, headers={\n                 'Accept': 'application/json',\n                 'Accept-Language': language\n             })\n         album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '')\n+        videos = [vid_info] if type_ == 'film' else traverse_obj(vid_info, ('_embedded', ..., ...))\n \n         return {\n             '_type': 'playlist',\n             'id': video_id,\n             'title': vid_info.get('title'),\n-            'entries': self._entries(traverse_obj(vid_info, ('_embedded', ..., ...)), language,\n-                                     thumbnails=thumbnails, album_artist=album_artist),\n+            'entries': self._entries(videos, language, thumbnails=thumbnails, album_artist=album_artist, type_=type_),\n             'thumbnails': thumbnails,\n             'album_artist': album_artist,\n         }\n", "issue": "[DigitalConcertHall] cannot download videos under /films\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.03.04** ([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- [X] 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\nAll\n\n### Provide a description that is worded well enough to be understood\n\nA major part of the site Digital Concert Hall is [concert videos](https://www.digitalconcerthall.com/en/concerts) which yt-dlp handles just fine. But when I try to download videos [here](https://www.digitalconcerthall.com/en/films), e.g. [this one](https://www.digitalconcerthall.com/en/film/388) which lasts 44 minutes (can be played with the login credentials `--username deydihurdo@gufum.com --password 3PXx-5.NDNmMD2!` which you can use), it only downloads the trailer which lasts 39 seconds. Using build from commit `ecfe479`.\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- [X] 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[debug] Command-line config: ['https://www.digitalconcerthall.com/en/film/388', '--username', 'PRIVATE', '--password', 'PRIVATE', '-vU']\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.03.04 [392389b7d] (zip)\r\n[debug] Python 3.11.3 (CPython x86_64 64bit) - Linux-6.3.4-arch2-1-x86_64-with-glibc2.37 (OpenSSL 3.0.8 7 Feb 2023, glibc 2.37)\r\n[debug] exe versions: ffmpeg 6.0 (setts), ffprobe 6.0, rtmpdump 2.4\r\n[debug] Optional libraries: Cryptodome-3.17, brotli-1.0.9, certifi-2023.05.07, mutagen-1.46.0, sqlite3-2.6.0, websockets-11.0.3\r\n[debug] Proxy map: {}\r\n[debug] Loaded 1842 extractors\r\n[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest\r\nAvailable version: stable@2023.03.04, Current version: stable@2023.03.04\r\nCurrent Build Hash: 5bfb7e4a15c47b2ff99b149b7c841e98ef606a4af18fd6330ddf3a0ed4a7ea19\r\nyt-dlp is up to date (stable@2023.03.04)\r\n[generic] Extracting URL: https://www.digitalconcerthall.com/en/film/388\r\n[generic] 388: Downloading webpage\r\nWARNING: [generic] Falling back on generic information extractor\r\n[generic] 388: Extracting information\r\n[debug] Looking for embeds\r\n[debug] Identified a JSON LD\r\n[generic] Extracting URL: https://world-vod.dchdns.net/preview/388-t/preview.mp4#__youtubedl_smuggle=%7B%22force_videoid%22%3A+%22388%22%2C+%22to_generic%22%3A+true%2C+%22http_headers%22%3A+%7B%22Referer%22%3A+%22https%3A%2F%2Fwww.digitalconcerthall.com%2Fen%2Ffilm%2F388%22%7D%7D\r\n[generic] 388: Downloading webpage\r\nWARNING: [generic] URL could be a direct video link, returning it as such.\r\n[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, filesize, fs_approx, tbr, vbr, abr, asr, proto, vext, aext, hasaud, source, id\r\n[debug] Default format spec: bestvideo*+bestaudio/best\r\n[info] 388: Downloading 1 format(s): 0\r\n[debug] Invoking http downloader on \"https://world-vod.dchdns.net/preview/388-t/preview.mp4\"\r\n[download] Destination: The Berliner Philharmoniker and Frank Peter Zimmermann [388].mp4\r\n[download] 100% of   16.16MiB in 00:00:07 at 2.05MiB/s\n```\n\n", "before_files": [{"content": "from .common import InfoExtractor\n\nfrom ..utils import (\n    ExtractorError,\n    parse_resolution,\n    traverse_obj,\n    try_get,\n    urlencode_postdata,\n)\n\n\nclass DigitalConcertHallIE(InfoExtractor):\n    IE_DESC = 'DigitalConcertHall extractor'\n    _VALID_URL = r'https?://(?:www\\.)?digitalconcerthall\\.com/(?P<language>[a-z]+)/concert/(?P<id>[0-9]+)'\n    _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token'\n    _ACCESS_TOKEN = None\n    _NETRC_MACHINE = 'digitalconcerthall'\n    _TESTS = [{\n        'note': 'Playlist with only one video',\n        'url': 'https://www.digitalconcerthall.com/en/concert/53201',\n        'info_dict': {\n            'id': '53201-1',\n            'ext': 'mp4',\n            'composer': 'Kurt Weill',\n            'title': '[Magic Night]',\n            'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\\.jpg$',\n            'upload_date': '20210624',\n            'timestamp': 1624548600,\n            'duration': 2798,\n            'album_artist': 'Members of the Berliner Philharmoniker / Simon R\u00f6ssler',\n        },\n        'params': {'skip_download': 'm3u8'},\n    }, {\n        'note': 'Concert with several works and an interview',\n        'url': 'https://www.digitalconcerthall.com/en/concert/53785',\n        'info_dict': {\n            'id': '53785',\n            'album_artist': 'Berliner Philharmoniker / Kirill Petrenko',\n            'title': 'Kirill Petrenko conducts Mendelssohn and Shostakovich',\n        },\n        'params': {'skip_download': 'm3u8'},\n        'playlist_count': 3,\n    }]\n\n    def _perform_login(self, username, password):\n        token_response = self._download_json(\n            self._OAUTH_URL,\n            None, 'Obtaining token', errnote='Unable to obtain token', data=urlencode_postdata({\n                'affiliate': 'none',\n                'grant_type': 'device',\n                'device_vendor': 'unknown',\n                'app_id': 'dch.webapp',\n                'app_version': '1.0.0',\n                'client_secret': '2ySLN+2Fwb',\n            }), headers={\n                'Content-Type': 'application/x-www-form-urlencoded',\n            })\n        self._ACCESS_TOKEN = token_response['access_token']\n        try:\n            self._download_json(\n                self._OAUTH_URL,\n                None, note='Logging in', errnote='Unable to login', data=urlencode_postdata({\n                    'grant_type': 'password',\n                    'username': username,\n                    'password': password,\n                }), headers={\n                    'Content-Type': 'application/x-www-form-urlencoded',\n                    'Referer': 'https://www.digitalconcerthall.com',\n                    'Authorization': f'Bearer {self._ACCESS_TOKEN}'\n                })\n        except ExtractorError:\n            self.raise_login_required(msg='Login info incorrect')\n\n    def _real_initialize(self):\n        if not self._ACCESS_TOKEN:\n            self.raise_login_required(method='password')\n\n    def _entries(self, items, language, **kwargs):\n        for item in items:\n            video_id = item['id']\n            stream_info = self._download_json(\n                self._proto_relative_url(item['_links']['streams']['href']), video_id, headers={\n                    'Accept': 'application/json',\n                    'Authorization': f'Bearer {self._ACCESS_TOKEN}',\n                    'Accept-Language': language\n                })\n\n            m3u8_url = traverse_obj(\n                stream_info, ('channel', lambda k, _: k.startswith('vod_mixed'), 'stream', 0, 'url'), get_all=False)\n            formats = self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', 'm3u8_native', fatal=False)\n\n            yield {\n                'id': video_id,\n                'title': item.get('title'),\n                'composer': item.get('name_composer'),\n                'url': m3u8_url,\n                'formats': formats,\n                'duration': item.get('duration_total'),\n                'timestamp': traverse_obj(item, ('date', 'published')),\n                'description': item.get('short_description') or stream_info.get('short_description'),\n                **kwargs,\n                'chapters': [{\n                    'start_time': chapter.get('time'),\n                    'end_time': try_get(chapter, lambda x: x['time'] + x['duration']),\n                    'title': chapter.get('text'),\n                } for chapter in item['cuepoints']] if item.get('cuepoints') else None,\n            }\n\n    def _real_extract(self, url):\n        language, video_id = self._match_valid_url(url).group('language', 'id')\n        if not language:\n            language = 'en'\n\n        thumbnail_url = self._html_search_regex(\n            r'(https?://images\\.digitalconcerthall\\.com/cms/thumbnails/.*\\.jpg)',\n            self._download_webpage(url, video_id), 'thumbnail')\n        thumbnails = [{\n            'url': thumbnail_url,\n            **parse_resolution(thumbnail_url)\n        }]\n\n        vid_info = self._download_json(\n            f'https://api.digitalconcerthall.com/v2/concert/{video_id}', video_id, headers={\n                'Accept': 'application/json',\n                'Accept-Language': language\n            })\n        album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '')\n\n        return {\n            '_type': 'playlist',\n            'id': video_id,\n            'title': vid_info.get('title'),\n            'entries': self._entries(traverse_obj(vid_info, ('_embedded', ..., ...)), language,\n                                     thumbnails=thumbnails, album_artist=album_artist),\n            'thumbnails': thumbnails,\n            'album_artist': album_artist,\n        }\n", "path": "yt_dlp/extractor/digitalconcerthall.py"}], "after_files": [{"content": "from .common import InfoExtractor\n\nfrom ..utils import (\n    ExtractorError,\n    parse_resolution,\n    traverse_obj,\n    try_get,\n    urlencode_postdata,\n)\n\n\nclass DigitalConcertHallIE(InfoExtractor):\n    IE_DESC = 'DigitalConcertHall extractor'\n    _VALID_URL = r'https?://(?:www\\.)?digitalconcerthall\\.com/(?P<language>[a-z]+)/(?P<type>film|concert)/(?P<id>[0-9]+)'\n    _OAUTH_URL = 'https://api.digitalconcerthall.com/v2/oauth2/token'\n    _ACCESS_TOKEN = None\n    _NETRC_MACHINE = 'digitalconcerthall'\n    _TESTS = [{\n        'note': 'Playlist with only one video',\n        'url': 'https://www.digitalconcerthall.com/en/concert/53201',\n        'info_dict': {\n            'id': '53201-1',\n            'ext': 'mp4',\n            'composer': 'Kurt Weill',\n            'title': '[Magic Night]',\n            'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\\.jpg$',\n            'upload_date': '20210624',\n            'timestamp': 1624548600,\n            'duration': 2798,\n            'album_artist': 'Members of the Berliner Philharmoniker / Simon R\u00f6ssler',\n        },\n        'params': {'skip_download': 'm3u8'},\n    }, {\n        'note': 'Concert with several works and an interview',\n        'url': 'https://www.digitalconcerthall.com/en/concert/53785',\n        'info_dict': {\n            'id': '53785',\n            'album_artist': 'Berliner Philharmoniker / Kirill Petrenko',\n            'title': 'Kirill Petrenko conducts Mendelssohn and Shostakovich',\n        },\n        'params': {'skip_download': 'm3u8'},\n        'playlist_count': 3,\n    }, {\n        'url': 'https://www.digitalconcerthall.com/en/film/388',\n        'info_dict': {\n            'id': '388',\n            'ext': 'mp4',\n            'title': 'The Berliner Philharmoniker and Frank Peter Zimmermann',\n            'description': 'md5:cfe25a7044fa4be13743e5089b5b5eb2',\n            'thumbnail': r're:^https?://images.digitalconcerthall.com/cms/thumbnails.*\\.jpg$',\n            'upload_date': '20220714',\n            'timestamp': 1657785600,\n            'album_artist': 'Frank Peter Zimmermann / Benedikt von Bernstorff / Jakob von Bernstorff',\n        },\n        'params': {'skip_download': 'm3u8'},\n    }]\n\n    def _perform_login(self, username, password):\n        token_response = self._download_json(\n            self._OAUTH_URL,\n            None, 'Obtaining token', errnote='Unable to obtain token', data=urlencode_postdata({\n                'affiliate': 'none',\n                'grant_type': 'device',\n                'device_vendor': 'unknown',\n                'app_id': 'dch.webapp',\n                'app_version': '1.0.0',\n                'client_secret': '2ySLN+2Fwb',\n            }), headers={\n                'Content-Type': 'application/x-www-form-urlencoded',\n            })\n        self._ACCESS_TOKEN = token_response['access_token']\n        try:\n            self._download_json(\n                self._OAUTH_URL,\n                None, note='Logging in', errnote='Unable to login', data=urlencode_postdata({\n                    'grant_type': 'password',\n                    'username': username,\n                    'password': password,\n                }), headers={\n                    'Content-Type': 'application/x-www-form-urlencoded',\n                    'Referer': 'https://www.digitalconcerthall.com',\n                    'Authorization': f'Bearer {self._ACCESS_TOKEN}'\n                })\n        except ExtractorError:\n            self.raise_login_required(msg='Login info incorrect')\n\n    def _real_initialize(self):\n        if not self._ACCESS_TOKEN:\n            self.raise_login_required(method='password')\n\n    def _entries(self, items, language, type_, **kwargs):\n        for item in items:\n            video_id = item['id']\n            stream_info = self._download_json(\n                self._proto_relative_url(item['_links']['streams']['href']), video_id, headers={\n                    'Accept': 'application/json',\n                    'Authorization': f'Bearer {self._ACCESS_TOKEN}',\n                    'Accept-Language': language\n                })\n\n            m3u8_url = traverse_obj(\n                stream_info, ('channel', lambda k, _: k.startswith('vod_mixed'), 'stream', 0, 'url'), get_all=False)\n            formats = self._extract_m3u8_formats(m3u8_url, video_id, 'mp4', 'm3u8_native', fatal=False)\n\n            yield {\n                'id': video_id,\n                'title': item.get('title'),\n                'composer': item.get('name_composer'),\n                'url': m3u8_url,\n                'formats': formats,\n                'duration': item.get('duration_total'),\n                'timestamp': traverse_obj(item, ('date', 'published')),\n                'description': item.get('short_description') or stream_info.get('short_description'),\n                **kwargs,\n                'chapters': [{\n                    'start_time': chapter.get('time'),\n                    'end_time': try_get(chapter, lambda x: x['time'] + x['duration']),\n                    'title': chapter.get('text'),\n                } for chapter in item['cuepoints']] if item.get('cuepoints') and type_ == 'concert' else None,\n            }\n\n    def _real_extract(self, url):\n        language, type_, video_id = self._match_valid_url(url).group('language', 'type', 'id')\n        if not language:\n            language = 'en'\n\n        thumbnail_url = self._html_search_regex(\n            r'(https?://images\\.digitalconcerthall\\.com/cms/thumbnails/.*\\.jpg)',\n            self._download_webpage(url, video_id), 'thumbnail')\n        thumbnails = [{\n            'url': thumbnail_url,\n            **parse_resolution(thumbnail_url)\n        }]\n\n        vid_info = self._download_json(\n            f'https://api.digitalconcerthall.com/v2/{type_}/{video_id}', video_id, headers={\n                'Accept': 'application/json',\n                'Accept-Language': language\n            })\n        album_artist = ' / '.join(traverse_obj(vid_info, ('_links', 'artist', ..., 'name')) or '')\n        videos = [vid_info] if type_ == 'film' else traverse_obj(vid_info, ('_embedded', ..., ...))\n\n        return {\n            '_type': 'playlist',\n            'id': video_id,\n            'title': vid_info.get('title'),\n            'entries': self._entries(videos, language, thumbnails=thumbnails, album_artist=album_artist, type_=type_),\n            'thumbnails': thumbnails,\n            'album_artist': album_artist,\n        }\n", "path": "yt_dlp/extractor/digitalconcerthall.py"}]}