Repository: yt-dlp/yt-dlp

Issue:
buzzsprout.com feed leads to `.unknown_video` file extensions (not `.mp3`)
### 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 a new site support request
- [X] I've verified that I'm running yt-dlp version **2023.09.24** ([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 none of provided URLs [violate any copyrights](https://github.com/yt-dlp/yt-dlp/blob/master/CONTRIBUTING.md#is-the-website-primarily-used-for-piracy) or contain any [DRM](https://en.wikipedia.org/wiki/Digital_rights_management) to the best of my knowledge
- [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 am willing to share it if required

### Region

United States

### Example URLs

- Playlist: https://feeds.buzzsprout.com/2186249.rss
  - Source: https://taitc.buzzsprout.com/

### Provide a description that is worded well enough to be understood

[`https://feeds.buzzsprout.com/2186249.rss`](https://feeds.buzzsprout.com/2186249.rss) ([source](https://taitc.buzzsprout.com/)) _appears_ to provide `.mp3` files, but `yt-dlp` gets confused  and instead tries to construct `.unknown_video` files. I'm not sure if this is due to a malformed feed or a `yt-dlp` shortcoming (or both).

Ref: https://github.com/search?q=repo%3Ayt-dlp%2Fyt-dlp+unknown_video&type=issues, but I don't know that any apply here.

A(n unsatisfactory) work-around is to use `--output '<...>.mp3'`.

### 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~ _N/A_
- [X] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
<?xml version="1.0" encoding="UTF-8" ?>
<?xml-stylesheet href="https://feeds.buzzsprout.com/styles.xsl" type="text/xsl"?>
<rss version="2.0" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:podcast="https://podcastindex.org/namespace/1.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
  <atom:link href="https://feeds.buzzsprout.com/2186249.rss" rel="self" type="application/rss+xml" />
  <atom:link href="https://pubsubhubbub.appspot.com/" rel="hub" xmlns="http://www.w3.org/2005/Atom" />
  <title>The Answer Is Transaction Costs</title>
  <lastBuildDate>Mon, 02 Oct 2023 04:21:31 -0400</lastBuildDate>
  <link>https://taitc.buzzsprout.com</link>
  <language>en-us</language>
  <copyright>© 2023 The Answer Is Transaction Costs</copyright>
  <podcast:locked>yes</podcast:locked>
    <podcast:guid>ceed3bc6-fa65-56b5-8856-2628b9439b1f</podcast:guid>
    <itunes:author>Michael Munger</itunes:author>
  <itunes:type>episodic</itunes:type>
  <itunes:explicit>false</itunes:explicit>
  <description><![CDATA[<div><em>The real price of everything is the toil and trouble of acquiring it."&nbsp; </em>-Adam Smith (WoN, Bk I, Chapter 5)</div><div><br>In which the Knower of Important Things shows how transaction costs explain literally everything. Plus TWEJ,&nbsp; and answers to letters.<br><br>If YOU have questions, submit them to our email at taitc.email@gmail.com&nbsp;<br><br>And check out the Facebook page, to leave comments and answer comments from other listeners:&nbsp; https://www.facebook.com/profile.php?id=100092342062186</div>]]></description>
  <itunes:owner>
    <itunes:name>Michael Munger</itunes:name>
  </itunes:owner>
  <image>
     <url>https://storage.buzzsprout.com/variants/wr8v0tlx47m73dua8qj7kn1v0iab/60854458c4d1acdf4e1c2f79c4137142d85d78e379bdafbd69bd34c85f5819ad.jpg</url>
     <title>The Answer Is Transaction Costs</title>
     <link></link>
  </image>
  <itunes:image href="https://storage.buzzsprout.com/variants/wr8v0tlx47m73dua8qj7kn1v0iab/60854458c4d1acdf4e1c2f79c4137142d85d78e379bdafbd69bd34c85f5819ad.jpg" />
  <itunes:category text="Science">
    <itunes:category text="Social Sciences" />
  </itunes:category>
  <itunes:category text="News">
    <itunes:category text="Politics" />
  </itunes:category>
  <itunes:category text="Comedy" />
  <item>
    <itunes:title>Effective Altruism and the Transaction Costs of Maximizing Expected Value</itunes:title>
    <title>Effective Altruism and the Transaction Costs of Maximizing Expected Value</title>
    <description><![CDATA[<p>A thought-provoking conversation about Effective Altruism (EA) with technologist Ben Goldhaber, as we explore its intersections with utilitarianism and transaction costs. We&apos;ll try to navigate the tricky terrains of libertarianism and the more &quot;directed&quot; world of EA, balancing directional and destinationist solutions, and the role of strong leadership and community dynamics in maintaining this equilibrium. <br/><br/>We&apos;ll question the limits of utility maximization as a framework and ponder over the potential dangers it could pose if unchecked. Our discussion investigates how EA, rational thinking, and global development has influenced the field of AI alignment. <br/><br/>And my favorite new TWEJ, from @dtarias. In the first monthly edition of TAITC.<br/><br/>Some resources:</p><ul><li><a href='https://www.reddit.com/r/EffectiveAltruism/comments/vy11bz/my_charity_joke/'>The Reddit source for the TWEJ</a></li><li><a href='https://www.thebreakers.com/dining/sunday-brunch/'>Sunday Brunch, for $195, at the Breakers</a></li><li><a href='https://www.econtalk.org/peter-singer-on-the-life-you-can-save/'>EconTalk: Peter Singer</a></li><li><a href='https://www.econtalk.org/will-macaskill-on-longtermism-and-what-we-owe-the-future/'>EconTalk: Will McCaskill and Longtermism</a></li><li><a href='https://www.econtalk.org/erik-hoel-on-effective-altruism-utilitarianism-and-the-repugnant-conclusion/'>EconTalk: Eric Hoel and the Repugnant Conclusion</a></li><li><a href='https://kevinmunger.substack.com/p/everything-was-rational-and-nothing'>Kevin Munger--Everything Was Rational and Nothing Vibed</a></li><li><a href='https://iep.utm.edu/consequentialism-utilitarianism/'>Consequentialism: IEP</a></li><li><a href='https://forum.effectivealtruism.org/'>Effective Altruism Forum</a></li><li><a href='https://www.nytimes.com/2023/09/14/technology/sam-bankman-fried-ftx-twitter-thread.html'>SB-F on SB-F (New York Times)</a></li></ul><p><br/></p><h1>If you have questions or comments, or want to suggest a future topic, email the show at <a href='mailto:taitc.email@gmail.com'>taitc.email@gmail.com</a> !</h1> <p><br/>You can follow Mike Munger on Twitter at <a href='https://twitter.com/mungowitz'>@mungowitz </a></p> <p><br/></p>]]></description>
    <content:encoded><![CDATA[<p>A thought-provoking conversation about Effective Altruism (EA) with technologist Ben Goldhaber, as we explore its intersections with utilitarianism and transaction costs. We&apos;ll try to navigate the tricky terrains of libertarianism and the more &quot;directed&quot; world of EA, balancing directional and destinationist solutions, and the role of strong leadership and community dynamics in maintaining this equilibrium. <br/><br/>We&apos;ll question the limits of utility maximization as a framework and ponder over the potential dangers it could pose if unchecked. Our discussion investigates how EA, rational thinking, and global development has influenced the field of AI alignment. <br/><br/>And my favorite new TWEJ, from @dtarias. In the first monthly edition of TAITC.<br/><br/>Some resources:</p><ul><li><a href='https://www.reddit.com/r/EffectiveAltruism/comments/vy11bz/my_charity_joke/'>The Reddit source for the TWEJ</a></li><li><a href='https://www.thebreakers.com/dining/sunday-brunch/'>Sunday Brunch, for $195, at the Breakers</a></li><li><a href='https://www.econtalk.org/peter-singer-on-the-life-you-can-save/'>EconTalk: Peter Singer</a></li><li><a href='https://www.econtalk.org/will-macaskill-on-longtermism-and-what-we-owe-the-future/'>EconTalk: Will McCaskill and Longtermism</a></li><li><a href='https://www.econtalk.org/erik-hoel-on-effective-altruism-utilitarianism-and-the-repugnant-conclusion/'>EconTalk: Eric Hoel and the Repugnant Conclusion</a></li><li><a href='https://kevinmunger.substack.com/p/everything-was-rational-and-nothing'>Kevin Munger--Everything Was Rational and Nothing Vibed</a></li><li><a href='https://iep.utm.edu/consequentialism-utilitarianism/'>Consequentialism: IEP</a></li><li><a href='https://forum.effectivealtruism.org/'>Effective Altruism Forum</a></li><li><a href='https://www.nytimes.com/2023/09/14/technology/sam-bankman-fried-ftx-twitter-thread.html'>SB-F on SB-F (New York Times)</a></li></ul><p><br/></p><h1>If you have questions or comments, or want to suggest a future topic, email the show at <a href='mailto:taitc.email@gmail.com'>taitc.email@gmail.com</a> !</h1> <p><br/>You can follow Mike Munger on Twitter at <a href='https://twitter.com/mungowitz'>@mungowitz </a></p> <p><br/></p>]]></content:encoded>
    <itunes:author>Michael Munger</itunes:author>
    <enclosure url="https://www.buzzsprout.com/2186249/13634013-effective-altruism-and-the-transaction-costs-of-maximizing-expected-value.mp3" length="30982367" type="audio/mpeg" />
    <guid isPermaLink="false">Buzzsprout-13634013</guid>
    <pubDate>Tue, 26 Sep 2023 07:00:00 -0400</pubDate>
    <podcast:transcript url="https://feeds.buzzsprout.com/2186249/13634013/transcript" type="text/html" />
    <podcast:transcript url="https://feeds.buzzsprout.com/2186249/13634013/transcript.json" type="application/json" />
    <podcast:transcript url="https://feeds.buzzsprout.com/2186249/13634013/transcript.srt" type="application/srt" />
    <podcast:chapters url="https://feeds.buzzsprout.com/2186249/13634013/chapters.json" type="application/json" />
    <itunes:duration>2734</itunes:duration>
    <itunes:keywords></itunes:keywords>
    <itunes:episodeType>full</itunes:episodeType>
    <itunes:explicit>false</itunes:explicit>
  </item>
  <!-- ... -->
</channel>
</rss>
% yt-dlp -vU --playlist-end 1 https://feeds.buzzsprout.com/2186249.rss
[debug] Command-line config: ['-vU', '--playlist-end', '1', 'https://feeds.buzzsprout.com/2186249.rss']
[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.09.24 [088add956] (pip)
[debug] Python 3.10.12 (CPython x86_64 64bit) - Linux-6.4.6-76060406-generic-x86_64-with-glibc2.35 (OpenSSL 3.0.2 15 Mar 2022, glibc 2.35)
[debug] exe versions: ffmpeg 4.4.2 (setts), ffprobe 4.4.2, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.19.0, brotli-1.1.0, certifi-2023.07.22, mutagen-1.47.0, sqlite3-3.37.2, websockets-11.0.3
[debug] Proxy map: {}
[debug] Loaded 1886 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Available version: stable@2023.09.24, Current version: stable@2023.09.24
yt-dlp is up to date (stable@2023.09.24)
[generic] Extracting URL: https://feeds.buzzsprout.com/2186249.rss
[generic] 2186249: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] 2186249: Extracting information
[debug] Identified a RSS feed
[download] Downloading playlist: The Answer Is Transaction Costs
[generic] Playlist The Answer Is Transaction Costs: Downloading 1 items of 18
[download] Downloading item 1 of 1
[generic] Extracting URL: https://www.buzzsprout.com/2186249/13634013-effective-altruism-and-the-transaction-costs-of-maximizing-expected-value.mp3#__youtubedl_smuggle=%7B%22force_videoid%22%3A+%22Buzzsprout-13634013%22%7D
[generic] Buzzsprout-13634013: Downloading webpage
[redirect] Following redirect to https://audio.buzzsprout.com/2t276cu8i2578zpktouy2ys5olfc?response-content-disposition=inline&
[generic] Extracting URL: https://audio.buzzsprout.com/2t276cu8i2578zpktouy2ys5olfc?response-content-disposition=inline&#__youtubedl_smuggle=%7B%22force_videoid%22%3A+%22Buzzsprout-13634013%22%7D
[generic] Buzzsprout-13634013: Downloading webpage
[debug] Identified a direct video link
[debug] Formats sorted by: hasvid, ie_pref, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, size, br, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] Buzzsprout-13634013: Downloading 1 format(s): mpeg
[debug] Invoking http downloader on "https://audio.buzzsprout.com/2t276cu8i2578zpktouy2ys5olfc?response-content-disposition=inline&"
[download] Destination: Effective Altruism and the Transaction Costs of Maximizing Expected Value [Buzzsprout-13634013].unknown_video
[download] 100% of   29.55MiB in 00:00:02 at 13.69MiB/s
[download] Finished downloading playlist: The Answer Is Transaction Costs
```



Discussion:
Fixing the extension issue requires a dedicated extractor, making this a duplicate of #3019
Perhaps it's beyond my understanding, but I'm curious why `yt-dlp` fails to recognize the `.mp3` extension when `item.enclosure[url]` is `https://www.buzzsprout.com/2186249/13634013-effective-altruism-and-the-transaction-costs-of-maximizing-expected-value.mp3` and the content type of that asset is `audio/mpeg`?

```
% curl 2>&1 --head --location --verbose https://www.buzzsprout.com/2186249/13634013-effective-altruism-and-the-transaction-costs-of-maximizing-expected-value.mp3 | grep -Ei '^content-type: '
content-type: audio/mpeg; charset=utf-8
content-type: audio/mpeg
```
The generic RSS extraction code returns a URL result with the enclosure URL:
`https://www.buzzsprout.com/2186249/13634013-effective-altruism-and-the-transaction-costs-of-maximizing-expected-value.mp3`

which then redirects to this URL before being processed by the generic extractor again:
`https://audio.buzzsprout.com/2t276cu8i2578zpktouy2ys5olfc?response-content-disposition=inline&`

The generic extractor currently only determines ext from URL basename instead of considering `Content-Type` response headers.

So I suppose we could do this:

```diff
diff --git a/yt_dlp/extractor/generic.py b/yt_dlp/extractor/generic.py
index 33e71d1c5..55a0d034c 100644
--- a/yt_dlp/extractor/generic.py
+++ b/yt_dlp/extractor/generic.py
@@ -34,6 +34,7 @@
     unified_timestamp,
     unsmuggle_url,
     update_url_query,
+    urlhandle_detect_ext,
     url_or_none,
     urljoin,
     variadic,
@@ -2452,7 +2453,7 @@ def _real_extract(self, url):
             self.report_detected('direct video link')
             headers = smuggled_data.get('http_headers', {})
             format_id = str(m.group('format_id'))
-            ext = determine_ext(url)
+            ext = determine_ext(url, default_ext=None) or urlhandle_detect_ext(full_response)
             subtitles = {}
             if format_id.endswith('mpegurl') or ext == 'm3u8':
                 formats, subtitles = self._extract_m3u8_formats_and_subtitles(url, video_id, 'mp4', headers=headers)
@@ -2464,6 +2465,7 @@ def _real_extract(self, url):
                 formats = [{
                     'format_id': format_id,
                     'url': url,
+                    'ext': ext,
                     'vcodec': 'none' if m.group('type') == 'audio' else None
                 }]
                 info_dict['direct'] = True
```

which would get you this:
```
[info] Available formats for 2t276cu8i2578zpktouy2ys5olfc?response-content-disposition=inline&:
ID   EXT RESOLUTION │ PROTO │ VCODEC     ACODEC
────────────────────────────────────────────────
mpeg mp3 audio only │ https │ audio only unknown
```

Resolving patch:
diff --git a/yt_dlp/extractor/generic.py b/yt_dlp/extractor/generic.py
--- a/yt_dlp/extractor/generic.py
+++ b/yt_dlp/extractor/generic.py
@@ -34,6 +34,7 @@
     unified_timestamp,
     unsmuggle_url,
     update_url_query,
+    urlhandle_detect_ext,
     url_or_none,
     urljoin,
     variadic,
@@ -2459,7 +2460,7 @@ def _real_extract(self, url):
             self.report_detected('direct video link')
             headers = smuggled_data.get('http_headers', {})
             format_id = str(m.group('format_id'))
-            ext = determine_ext(url)
+            ext = determine_ext(url, default_ext=None) or urlhandle_detect_ext(full_response)
             subtitles = {}
             if format_id.endswith('mpegurl') or ext == 'm3u8':
                 formats, subtitles = self._extract_m3u8_formats_and_subtitles(url, video_id, 'mp4', headers=headers)
@@ -2471,6 +2472,7 @@ def _real_extract(self, url):
                 formats = [{
                     'format_id': format_id,
                     'url': url,
+                    'ext': ext,
                     'vcodec': 'none' if m.group('type') == 'audio' else None
                 }]
                 info_dict['direct'] = True


Test patch: