Repository: yt-dlp/yt-dlp

Issue:
StreamCZ extractor broken
### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2022.04.08** ([update instructions](https://github.com/yt-dlp/yt-dlp#update)) or later (specify commit)
- [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)
- [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

world

### Description

Broken support for stream.cz
Example: https://www.stream.cz/autobazar/vecerni-auto-271357

### Verbose log

```shell
C:\Users\xxx>yt-dlp.lnk https://www.stream.cz/autobazar/vecerni-auto-271357 -U -v
[debug] Command-line config: ['https://www.stream.cz/autobazar/vecerni-auto-271357', '-U', '-v']
[debug] User config "C:\Users\xxx\yt-dlp.conf": ['--user-agent', 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/94.0.4606.71 Safari/537.36', '--no-check-certificate', '-o', 'D:\\Downloads\\yt-dlp\\%(autonumber)03d_%(title)s.%(ext)s', '--no-mtime', '--format', 'bestvideo[ext=mp4][height<=1080][fps<=30]+bestaudio[ext=m4a]/best[ext=mp4][height<=1080][fps<=30]/best[height<=1080][fps<=30]/best', '--merge-output-format', 'mkv', '--ffmpeg-location', 'C:\\Apps\\ffmpeg\\bin\\ffmpeg.exe', '--all-subs', '-i', '--add-metadata', '--remux-video', 'mkv', '--add-header', 'accept-language: cs,fi;q=0.9,en-US;q=0.8,en;q=0.7,en-GB;q=0.6', '--add-header', 'sec-ch-ua: "Chromium";v="94", "Google Chrome";v="94", ";Not A Brand";v="99"', '--add-header', 'sec-ch-ua-arch: "x86"', '--add-header', 'sec-ch-ua-bitness: "64"', '--add-header', 'sec-ch-ua-full-version: "94.0.4606.71"', '--add-header', 'sec-ch-ua-mobile: ?0', '--add-header', 'sec-ch-ua-model: ""', '--add-header', 'sec-ch-ua-platform: "Windows"', '--add-header', 'sec-ch-ua-platform-version: "10.0.0"', '--add-header', 'sec-fetch-dest: document', '--add-header', 'sec-fetch-mode: navigate', '--add-header', 'sec-fetch-site: none', '--add-header', 'sec-fetch-user: ?1', '--add-header', 'service-worker-navigation-preload: true', '--add-header', 'upgrade-insecure-requests: 1', '--add-header', 'alt-svc: h3=":443"; ma=2592000,h3-29=":443"; ma=2592000,h3-T051=":443"; ma=2592000,h3-Q050=":443"; ma=2592000,h3-Q046=":443"; ma=2592000,h3-Q043=":443"; ma=2592000,quic=":443"; ma=2592000; v="46,43"', '--add-header', 'cache-control: no-cache, no-store, max-age=0, must-revalidate']
[debug] Encodings: locale cp1252, fs utf-8, out utf-8, err utf-8, pref cp1252
[debug] yt-dlp version 2022.04.08 [7884ade] (win_exe)
[debug] Python version 3.8.10 (CPython 64bit) - Windows-10-10.0.19044-SP0
[debug] Checking exe version: "C:\Apps\ffmpeg\bin\ffmpeg.exe" -bsfs
[debug] Checking exe version: "C:\Apps\ffmpeg\bin\ffprobe" -bsfs
[debug] exe versions: ffmpeg 4.4-full_build-www.gyan.dev (setts), ffprobe 4.4-full_build-www.gyan.dev
[debug] Optional libraries: brotli, certifi, Cryptodome, mutagen, sqlite, websockets
[debug] Proxy map: {}
Latest version: 2022.04.08, Current version: 2022.04.08
yt-dlp is up to date (2022.04.08)
[debug] [StreamCZ] Extracting URL: https://www.stream.cz/autobazar/vecerni-auto-271357
[StreamCZ] 271357: Downloading GraphQL result
[StreamCZ] 271357: Downloading playlist
ERROR: 'NoneType' object has no attribute 'items'
Traceback (most recent call last):
  File "yt_dlp\YoutubeDL.py", line 1408, in wrapper
  File "yt_dlp\YoutubeDL.py", line 1478, in __extract_info
  File "yt_dlp\extractor\common.py", line 641, in extract
  File "yt_dlp\extractor\streamcz.py", line 112, in _real_extract
  File "yt_dlp\extractor\streamcz.py", line 58, in _extract_formats
AttributeError: 'NoneType' object has no attribute 'items'
```



Discussion:
Error confirmed with yt-dlp; working with yt-dl git master:
```ShellSession
$ python -m youtube_dl -F -v 'https://www.stream.cz/autobazar/vecerni-auto-271357'
[debug] System config: [u'--prefer-ffmpeg']
[debug] User config: []
[debug] Custom config: []
[debug] Command-line args: [u'-F', u'-v', u'https://www.stream.cz/autobazar/vecerni-auto-271357']
[debug] Encodings: locale UTF-8, fs UTF-8, out UTF-8, pref UTF-8
[debug] youtube-dl version 2021.12.17
[debug] Git HEAD: fed9c8d17
[debug] Python version 2.7.17 (CPython) - Linux-4.4.0-210-generic-i686-with-Ubuntu-16.04-xenial
[debug] exe versions: avconv 4.3, avprobe 4.3, ffmpeg 4.3, ffprobe 4.3
[debug] Proxy map: {}
[StreamCZ] 271357: Downloading GraphQL result
[StreamCZ] 271357: Downloading playlist
[info] Available formats for 271357:
format code  extension  resolution note
240p-mp4     mp4        426x240     400k , avc1.42c015, mp4a.40.2
360p-mp4     mp4        640x360     800k , avc1.42c01e, mp4a.40.2
480p-mp4     mp4        854x480    1200k , avc1.42c01e, mp4a.40.2
720p-mp4     mp4        1280x720   2400k , avc1.42c01f, mp4a.40.2
1080p-mp4    mp4        1920x1080  4400k , avc1.42c028, mp4a.40.2 (best)
$
```
`traverse_obj()` needs a default `{}` (the function has a `default` parameter but the `... or ...` formulation is shorter unless you can remember that it's the 3rd parameter):
```py
--- old/yt-dlp/yt_dlp/extractor/streamcz.py
+++ new/yt-dlp/yt_dlp/extractor/streamcz.py
@@ -52,7 +52,7 @@
 
     def _extract_formats(self, spl_url, video):
         for ext, pref, streams in (
-                ('ts', -1, traverse_obj(video, ('http_stream', 'qualities'))),
+                ('ts', -1, traverse_obj(video, ('http_stream', 'qualities')) or {}),
                 ('mp4', 1, video.get('mp4'))):
             for format_id, stream in streams.items():
                 if not stream.get('url'):
```
```

> the function has a default parameter but the ... or ... formulation is shorter

If you use more complex traversal including `...`, `default` and `or` does different things. But yes, here they are equivalent

> unless you can remember that it's the 3rd parameter

It is a keyword only argument. 
Ofc, arg 2 is a vararg.

Resolving patch:
diff --git a/yt_dlp/extractor/streamcz.py b/yt_dlp/extractor/streamcz.py
--- a/yt_dlp/extractor/streamcz.py
+++ b/yt_dlp/extractor/streamcz.py
@@ -52,8 +52,8 @@ class StreamCZIE(InfoExtractor):
 
     def _extract_formats(self, spl_url, video):
         for ext, pref, streams in (
-                ('ts', -1, traverse_obj(video, ('http_stream', 'qualities'))),
-                ('mp4', 1, video.get('mp4'))):
+                ('ts', -1, traverse_obj(video, ('http_stream', 'qualities')) or {}),
+                ('mp4', 1, video.get('mp4') or {})):
             for format_id, stream in streams.items():
                 if not stream.get('url'):
                     continue


Test patch: