Repository: yt-dlp/yt-dlp

Issue:
NPR Music Tiny Desk Sporadically Broken
### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2021.12.01**. ([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)
- [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

United States

### Description

I've found an instance of a [NPR Tiny Desk Concert](https://www.npr.org/series/tiny-desk-concerts/) that does not work.

Most concerts — such as [this one](https://www.npr.org/2021/10/15/1045251626/camila-cabello-tiny-desk-home-concert) — work no sweat.

Oddly, [this one](https://www.npr.org/2021/10/26/1048372074/ed-sheeran-tiny-desk-home-concert) does not. It plays just fine in Safari.

### Verbose log

```shell
[debug] Command-line config: ['-Uv', 'https://www.npr.org/2021/10/26/1048372074/ed-sheeran-tiny-desk-home-concert']
[debug] Encodings: locale UTF-8, fs utf-8, out utf-8 (No ANSI), err utf-8, pref UTF-8
[debug] yt-dlp version 2021.12.01 [91f071af6]
[debug] Python version 3.10.0 (CPython 64bit) - macOS-12.0.1-arm64-arm-64bit
[debug] exe versions: ffmpeg 4.4.1 (setts), ffprobe 4.4.1, rtmpdump 2.4
[debug] Optional libraries: Cryptodome, mutagen, sqlite, websockets
[debug] Proxy map: {}
[debug] [Npr] Extracting URL: https://www.npr.org/2021/10/26/1048372074/ed-sheeran-tiny-desk-home-concert
WARNING: [Npr] Failed to download m3u8 information: HTTP Error 404: Not Found
ERROR: [Npr] 1048372074: Unable to download SMIL file: HTTP Error 404: Not Found (caused by <HTTPError 404: 'Not Found'>); please report this issue on  https://github.com/yt-dlp/yt-dlp . Make sure you are using the latest version; see  https://github.com/yt-dlp/yt-dlp  on how to update. Be sure to call yt-dlp with the --verbose flag and include its complete output. (caused by <HTTPError 404: 'Not Found'>); please report this issue on  https://github.com/yt-dlp/yt-dlp . Make sure you are using the latest version; see  https://github.com/yt-dlp/yt-dlp  on how to update. Be sure to call yt-dlp with the --verbose flag and include its complete output.
  File "/opt/homebrew/Cellar/yt-dlp/2021.12.1/libexec/lib/python3.10/site-packages/yt_dlp/extractor/common.py", line 715, in _request_webpage
    return self._downloader.urlopen(url_or_request)
  File "/opt/homebrew/Cellar/yt-dlp/2021.12.1/libexec/lib/python3.10/site-packages/yt_dlp/YoutubeDL.py", line 3385, in urlopen
    return self._opener.open(req, timeout=self._socket_timeout)
  File "/opt/homebrew/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/urllib/request.py", line 525, in open
    response = meth(req, response)
  File "/opt/homebrew/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/urllib/request.py", line 634, in http_response
    response = self.parent.error(
  File "/opt/homebrew/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/urllib/request.py", line 563, in error
    return self._call_chain(*args)
  File "/opt/homebrew/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/urllib/request.py", line 496, in _call_chain
    result = func(*args)
  File "/opt/homebrew/Cellar/python@3.10/3.10.0_2/Frameworks/Python.framework/Versions/3.10/lib/python3.10/urllib/request.py", line 643, in http_error_default
    raise HTTPError(req.full_url, code, msg, hdrs, fp)
```



Discussion:
i checked and it fails because the website returns a cookie consent webpage instead of the page the extractor expects...
   Looks like most (or perhaps all) SMIL links returned by api.npr.org
   are 404s.

   Currently, the `_extract_smil_formats` call in `NprIE` does not
   pass `fatal=False`. Consequently, the call fails and makes the 
   download fail.

   If `fatal=False` is passed to `_extract_smil_formats`, the download
   works:

```bash
$ python -m yt_dlp https://www.npr.org/2021/10/26/1048372074/ed-sheeran-tiny-desk-home-concert
[Npr] 1048372074: Downloading JSON metadata
[Npr] 1048379421: Downloading m3u8 information
WARNING: [Npr] Failed to download m3u8 information: HTTP Error 404: Not Found
[Npr] 1048379421: Downloading SMIL file
WARNING: [Npr] Unable to download SMIL file: HTTP Error 404: Not Found
[Npr] hlsUrl: Downloading m3u8 information
[download] Downloading playlist: Ed Sheeran: Tiny Desk (Home) Concert
[Npr] playlist Ed Sheeran: Tiny Desk (Home) Concert: Collected 1 videos; downloading 1 of them
[download] Downloading video 1 of 1
[info] 1048379421: Downloading 1 format(s): hls-3740
[hlsnative] Downloading m3u8 manifest
[hlsnative] Total fragments: 338
[download] Destination: Ed Sheeran - Tiny Desk (Home) Concert [1048379421].mp4
[download] 100% of 618.08MiB in 10:16
[FixupM3u8] Fixing MPEG-TS in MP4 container of "Ed Sheeran - Tiny Desk (Home) Concert [1048379421].mp4"
[download] Finished downloading playlist: Ed Sheeran: Tiny Desk (Home) Concert
```

   Here's the patch:

```diff
diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py
index e15763953..6cd2551bf 100644
--- a/yt_dlp/extractor/common.py
+++ b/yt_dlp/extractor/common.py
@@ -2332,7 +2332,7 @@ class InfoExtractor(object):
 
         if smil is False:
             assert not fatal
-            return []
+            return [], {}
 
         namespace = self._parse_smil_namespace(smil)
 
diff --git a/yt_dlp/extractor/npr.py b/yt_dlp/extractor/npr.py
index 9d1122f0c..49f062d7a 100644
--- a/yt_dlp/extractor/npr.py
+++ b/yt_dlp/extractor/npr.py
@@ -91,7 +91,8 @@ class NprIE(InfoExtractor):
                     elif format_id == 'smil':
                         smil_formats = self._extract_smil_formats(
                             format_url, media_id, transform_source=lambda s: s.replace(
-                                'rtmp://flash.npr.org/ondemand/', 'https://ondemand.npr.org/'))
+                                'rtmp://flash.npr.org/ondemand/', 'https://ondemand.npr.org/'),
+                            fatal=False)
                         self._check_formats(smil_formats, media_id)
                         formats.extend(smil_formats)
                     else:
```

   Does this look good? Should I go ahead and open a PR?
> Should I go ahead and open a PR?

please do

Resolving patch:
diff --git a/yt_dlp/extractor/common.py b/yt_dlp/extractor/common.py
--- a/yt_dlp/extractor/common.py
+++ b/yt_dlp/extractor/common.py
@@ -2332,7 +2332,7 @@ def _extract_smil_formats_and_subtitles(self, smil_url, video_id, fatal=True, f4
 
         if smil is False:
             assert not fatal
-            return []
+            return [], {}
 
         namespace = self._parse_smil_namespace(smil)
 
diff --git a/yt_dlp/extractor/npr.py b/yt_dlp/extractor/npr.py
--- a/yt_dlp/extractor/npr.py
+++ b/yt_dlp/extractor/npr.py
@@ -91,7 +91,8 @@ def _real_extract(self, url):
                     elif format_id == 'smil':
                         smil_formats = self._extract_smil_formats(
                             format_url, media_id, transform_source=lambda s: s.replace(
-                                'rtmp://flash.npr.org/ondemand/', 'https://ondemand.npr.org/'))
+                                'rtmp://flash.npr.org/ondemand/', 'https://ondemand.npr.org/'),
+                            fatal=False)
                         self._check_formats(smil_formats, media_id)
                         formats.extend(smil_formats)
                     else:


Test patch: