Repository: yt-dlp/yt-dlp

Issue:
VrtNu download fails on some videos
### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2021.12.27**. ([update instructions](https://github.com/yt-dlp/yt-dlp#update))
- [X] I've checked that all provided URLs are alive and playable in a browser
- [X] I've checked that all URLs and arguments with special characters are [properly quoted or escaped](https://github.com/ytdl-org/youtube-dl#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 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

Belgium

### Description

Although most downloads on vrtnu (with credentials) still work, one series fails: (run from local git, but same output from ytdlp)

```
[debug] Command-line config: ['https://www.vrt.be/vrtnu/a-z/raymond-goethals--magie-in-marseille/1/raymond-goethals--magie-in-marseille-s1a1/', '-v', '--netrc']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, err utf-8, pref UTF-8
[debug] yt-dlp version 2021.12.27 [6223f67a8] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'SamplePluginPP']
[debug] Git HEAD: e540c56f3
[debug] Python version 3.9.7 (CPython 64bit) - Linux-5.13.0-22-generic-x86_64-with-glibc2.34
[debug] exe versions: ffmpeg 4.4 (setts), ffprobe 4.4, rtmpdump 2.4
[debug] Optional libraries: Cryptodome, secretstorage, sqlite
[debug] Proxy map: {}
[VrtNU] Logging in
[VrtNU] Requesting XSRF Token
[VrtNU] Performing login
[debug] [VrtNU] Extracting URL: https://www.vrt.be/vrtnu/a-z/raymond-goethals--magie-in-marseille/1/raymond-goethals--magie-in-marseille-s1a1/
[VrtNU] raymond-goethals--magie-in-marseille-s1a1: Downloading webpage
[debug] [Canvas] Extracting URL: https://mediazone.vrt.be/api/v1/vrtvideo/assets/pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: refreshtoken: Retrieve vrtnutoken
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: Downloading token
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: Downloading video JSON
ERROR: [Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: None
  File "/home/xyz/Development/yt-dlp/yt_dlp/extractor/common.py", line 599, in extract
    ie_result = self._real_extract(url)
  File "/home/xyz/Development/yt-dlp/yt_dlp/extractor/canvas.py", line 85, in _real_extract
    raise ExtractorError(data.get('message') or code, expected=True)
```

I debugged this issue, and apparently, this video has an empty `title` element in its json: 
`{'duration': 3121060, 'skinType': 'vod', 'title': '', 'shortDescription': None, 'drm': 'vrt|2021-12-28T.....Z|.../...', 'drmExpired': '2021-12-28...', 'aspectRatio': '16:9', 'posterImageUrl': None, 'channelId': None, 'targetUrls': [{'type': 'mpeg_dash', 'url': 'https://remix-cf.lwc.vrtcdn.be/remix/0603b9c1-b117-4caf-a4c1-xxx/remix.ism/.mpd'}, {'type': 'hls_aes', 'url': 'https://remix-cf.lwc.vrtcdn.be/remix/0603b9c1-b117-4caf-a4c1-xxx/remix_aes.ism/.m3u8'}, {'type': 'hls', 'url': 'https://remix-cf.lwc.vrtcdn.be/remix/0603b9c1-b117-4caf-a4c1-xx/remix.ism/.m3u8'}], 'playlist': {'content': [{'eventType': 'ONBOARDING', 'duration': 3000, 'skippable': False}, {'eventType': 'STANDARD', 'duration': 3121060, 'skippable': True}]}}`
 
The test on https://github.com/yt-dlp/yt-dlp/blob/aeec0e44e243dc625c8ff19964a624188d43e84b/yt_dlp/extractor/canvas.py#L79  seems to be the culprit. I think the test is not needed as issues with logon will be catched more early during the Token-logon steps. 


### Verbose log

```shell
[debug] Command-line config: ['https://www.vrt.be/vrtnu/a-z/raymond-goethals--magie-in-marseille/1/raymond-goethals--magie-in-marseille-s1a1/', '-v', '--netrc']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8, err utf-8, pref UTF-8
[debug] yt-dlp version 2021.12.27 [6223f67a8] (source)
[debug] Lazy loading extractors is disabled
[debug] Plugins: ['SamplePluginIE', 'SamplePluginPP']
[debug] Git HEAD: e540c56f3
[debug] Python version 3.9.7 (CPython 64bit) - Linux-5.13.0-22-generic-x86_64-with-glibc2.34
[debug] exe versions: ffmpeg 4.4 (setts), ffprobe 4.4, rtmpdump 2.4
[debug] Optional libraries: Cryptodome, secretstorage, sqlite
[debug] Proxy map: {}
[VrtNU] Logging in
[VrtNU] Requesting XSRF Token
[VrtNU] Performing login
[debug] [VrtNU] Extracting URL: https://www.vrt.be/vrtnu/a-z/raymond-goethals--magie-in-marseille/1/raymond-goethals--magie-in-marseille-s1a1/
[VrtNU] raymond-goethals--magie-in-marseille-s1a1: Downloading webpage
[debug] [Canvas] Extracting URL: https://mediazone.vrt.be/api/v1/vrtvideo/assets/pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: refreshtoken: Retrieve vrtnutoken
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: Downloading token
[Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: Downloading video JSON
ERROR: [Canvas] pbs-pub-975eb3d7-86af-4a92-81cc-80074a58c8ff$vid-2602567b-2db5-4b8d-a533-51f24688bd5c: None
  File "/home/xyz/Development/yt-dlp/yt_dlp/extractor/common.py", line 599, in extract
    ie_result = self._real_extract(url)
  File "/home/xyz/Development/yt-dlp/yt_dlp/extractor/canvas.py", line 85, in _real_extract
    raise ExtractorError(data.get('message') or code, expected=True)
```



Discussion:

Resolving patch:
diff --git a/yt_dlp/extractor/canvas.py b/yt_dlp/extractor/canvas.py
--- a/yt_dlp/extractor/canvas.py
+++ b/yt_dlp/extractor/canvas.py
@@ -76,7 +76,7 @@ def _real_extract(self, url):
                     'vrtPlayerToken': vrtPlayerToken,
                     'client': 'null',
                 }, expected_status=400)
-            if not data.get('title'):
+            if 'title' not in data:
                 code = data.get('code')
                 if code == 'AUTHENTICATION_REQUIRED':
                     self.raise_login_required()
@@ -84,7 +84,8 @@ def _real_extract(self, url):
                     self.raise_geo_restricted(countries=['BE'])
                 raise ExtractorError(data.get('message') or code, expected=True)
 
-        title = data['title']
+        # Note: The title may be an empty string
+        title = data['title'] or f'{site_id} {video_id}'
         description = data.get('description')
 
         formats = []


Test patch: