Repository: yt-dlp/yt-dlp

Issue:
NBC extractor not saving video clips
### DO NOT REMOVE OR SKIP THE ISSUE TEMPLATE

- [X] I understand that I will be **blocked** if I remove or skip any mandatory\* field

### Checklist

- [X] I'm reporting a broken site
- [X] I've verified that I'm running yt-dlp version **2023.01.06** ([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 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

USA

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

The nbc.py extractor isn't saving short video clips. It saves a file with extension "unknown_video" as if it were a video file and tries to add metadata to it. That file, however, is actually the master m3u8 file.


### 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] Copy the WHOLE output (starting with `[debug] Command-line config`) and insert it below

### Complete Verbose Output

```shell
[debug] Command-line config: ['-vU', 'https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439']
[debug] User config "C:\msys64\home\User/yt-dlp.conf": ['--write-info-json', '--console-title', '-c', '-i', '-w', '--write-sub', '--write-auto-sub', '--all-subs', '--write-description', '--write-all-thumbnails', '--add-metadata', '--write-annotations', '--no-post-overwrites', '-o', '%(title)s [%(id)s, %(format_id)s, %(width)sx%(height)s].%(ext)s', '--abort-on-unavailable-fragment', '--retries', '20', '--fragment-retries', '20', '--hls-prefer-native', '--no-cache-dir', '-S', 'tbr,vbr,abr', '--ap-mso', 'PRIVATE', '--ap-username', 'PRIVATE', '--ap-password', 'PRIVATE']
[debug] Encodings: locale cp1252, fs utf-8, pref cp1252, out cp1252 (No VT), error cp1252 (No VT), screen cp1252 (No VT)
[debug] yt-dlp version 2023.01.06 [6becd25] (pip)
[debug] Python 3.9.7 (CPython AMD64 64bit) - PRIVATE (OpenSSL 1.1.1l  24 Aug 2021)
[debug] exe versions: ffmpeg 4.4 (setts), ffprobe 4.4, phantomjs 2.1.1, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.11.0, brotli-1.0.9, certifi-2021.05.30, mutagen-1.45.1, sqlite3-2.6.0, websockets-10.0
[debug] Proxy map: {}
[debug] Loaded 1760 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2023.01.06, Current version: 2023.01.06
yt-dlp is up to date (2023.01.06)
[NBC] Extracting URL: https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439
[NBC] 3646439: Downloading JSON metadata
[NBC] 3646439: Downloading JSON metadata
[ThePlatform] Extracting URL: http://link.theplatform.com/s/NnzsPC/media/guid/2410887629/3646439?mbr=true&manifest=m3u&switch=HLSServiceSecure#__youtubedl_smuggle=%7B%22force_smil_url%22%3A+true%7D
[ThePlatform] 3646439: Downloading SMIL data
[ThePlatform] 3646439: Checking video URL
[ThePlatform] 3646439: Downloading JSON metadata
[info] 3646439: Downloading subtitles: en
[debug] Sort order given by user: tbr, vbr, abr
[debug] Formats sorted by: hasvid, ie_pref, tbr, vbr, abr, lang, quality, res, fps, hdr:12(7), vcodec:vp9.2(10), channels, acodec, filesize, fs_approx, asr, proto, vext, aext, hasaud, source, id
[debug] Default format spec: bestvideo*+bestaudio/best
[info] 3646439: Downloading 1 format(s): http-4096
[info] Writing video description to: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].description
[info] Writing video subtitles to: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].en.tt
[debug] Invoking http downloader on "http://mpxstatic-nbcmpx.nbcuni.com/caption/856/19/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_anvver_3.tt"
[debug] File locking is not supported. Proceeding without locking
[download] Destination: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].en.tt
[download] 100% of   38.46KiB in 00:00:00 at 392.46KiB/s
[info] Downloading video thumbnail 0 ...
[info] Writing video thumbnail 0 to: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].jpg
[info] Writing video metadata as JSON to: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].info.json
WARNING: There are no annotations to write.
[debug] Invoking http downloader on "https://hls-manifest.apps.nbcuni.com/manifest/hls/3646439?brand=nbc&cacheVersion=x_RqYLP9_Jad&userData=1673508510000:cdedf4f24246d36fec9b9f98a6550fd3ba5439932eadf2d2e1c114a7435b04d6"
[download] Destination: Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].unknown_video
[download] 100% of    3.55KiB in 00:00:00 at 22.06KiB/s
[Metadata] Adding metadata to "Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].unknown_video"
[debug] ffmpeg command line: ffmpeg -y -loglevel "repeat+info" -i "file:Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].unknown_video" -i "file:Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].meta" -map 0 -dn -ignore_unknown -c copy -map_metadata 1 -write_id3v1 1 -metadata "title=Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes" -metadata "date=20180107" -metadata "description=Oprah Winfrey receives the Cecil B. de Mille Award at the 75th Annual Golden Globe Awards." -metadata "synopsis=Oprah Winfrey receives the Cecil B. de Mille Award at the 75th Annual Golden Globe Awards." -metadata "purl=https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439" -metadata "comment=https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439" -metadata "artist=NBCU-COM" -metadata "show=The Golden Globe Awards" -metadata "season_number=75" -metadata "episode_id=Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes" -metadata "episode_sort=1" -movflags "+faststart" "file:Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].temp.unknown_video"
[debug] ffmpeg version 4.4 Copyright (c) 2000-2021 the FFmpeg developers
  built with gcc 10.3.0 (Rev5, Built by MSYS2 project)
  configuration: --prefix=/mingw64 --target-os=mingw32 --arch=x86_64 --disable-debug --enable-amf --enable-dxva2 --enable-d3d11va --enable-fontconfig --enable-gnutls --enable-gpl --enable-libaom --enable-libass --enable-libbluray --enable-libcaca --enable-libcelt --enable-libdav1d --enable-libfreetype --enable-libgsm --enable-libmfx --enable-libmodplug --enable-libmp3lame --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libopenjpeg --enable-libopus --enable-librtmp --enable-libsoxr --enable-libspeex --enable-libsrt --enable-libtheora --enable-libvorbis --enable-libx264 --enable-libx265 --enable-libxvid --enable-libvpx --enable-libwebp --enable-libxml2 --enable-nvenc --enable-openal --enable-pic --enable-postproc --enable-runtime-cpudetect --enable-swresample --enable-version3 --enable-vulkan --enable-zlib --disable-doc --enable-frei0r --logfile=config.log --enable-shared
  libavutil      56. 70.100 / 56. 70.100
  libavcodec     58.134.100 / 58.134.100
  libavformat    58. 76.100 / 58. 76.100
  libavdevice    58. 13.100 / 58. 13.100
  libavfilter     7.110.100 /  7.110.100
  libswscale      5.  9.100 /  5.  9.100
  libswresample   3.  9.100 /  3.  9.100
  libpostproc    55.  9.100 / 55.  9.100
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=4296000,CODECS="avc1.640028",RESOLUTION=1920x1080,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_4200_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=2596000,CODECS="avc1.64001f",RESOLUTION=1280x720,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_2500_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1896000,CODECS="avc1.64001f",RESOLUTION=960x540,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1800_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=1296000,CODECS="avc1.64001f",RESOLUTION=960x540,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1200_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=796000,CODECS="avc1.64001e",RESOLUTION=640x360,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_700_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=496000,CODECS="avc1.640015",RESOLUTION=448x252,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_400_iframe.m3u8"')
[hls @ 0000000000481d80] Skip ('#EXT-X-I-FRAME-STREAM-INF:BANDWIDTH=296000,CODECS="avc1.640015",RESOLUTION=448x252,URI="https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_200_iframe.m3u8"')
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_4200.m3u8' for reading
[https @ 000000000049d240] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_4200.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_2500.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_2500.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1800.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1800.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1200.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1200.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_700.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_700.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_400.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_400.m3u8]
[hls @ 0000000000481d80] Opening 'https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_200.m3u8' for reading
[https @ 0000000000489580] Protocol 'https' not on whitelist 'file,crypto,data'!
[hls @ 0000000000481d80] parse_playlist error Invalid argument [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_200.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_4200.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_2500.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1800.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_1200.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_700.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_400.m3u8]
[hls @ 0000000000481d80] Empty segment [https://nbchls-prod.nbcuni.com/tve-adstitch/2228/18/01/07/3646439/180107_3646439_Oprah_Winfrey_Receives_Cecil_B__de_Mille_Awa_1515395548_200.m3u8]
Input #0, hls, from 'file:Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].unknown_video':
  Duration: N/A, bitrate: N/A
  Program 0
    Metadata:
      variant_bitrate : 4542800
  Program 1
    Metadata:
      variant_bitrate : 2757800
  Program 2
    Metadata:
      variant_bitrate : 2022800
  Program 3
    Metadata:
      variant_bitrate : 1392800
  Program 4
    Metadata:
      variant_bitrate : 867800
  Program 5
    Metadata:
      variant_bitrate : 552800
  Program 6
    Metadata:
      variant_bitrate : 342800
Input #1, ffmetadata, from 'file:Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes [3646439, http-4096, 1920x1080].meta':
  Duration: 00:09:30.00, start: 0.000000, bitrate: 0 kb/s
  Chapters:
    Chapter #1:0: start 0.000000, end 570.000000
      Metadata:
        title           : <Untitled Chapter 1>
Stream map '0' matches no streams.
To ignore this, add a trailing '?' to the map.

ERROR: To ignore this, add a trailing '?' to the map.
Traceback (most recent call last):
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/YoutubeDL.py", line 3451, in run_pp
    files_to_delete, infodict = pp.run(infodict)
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/postprocessor/common.py", line 24, in run
    ret = func(self, info, *args, **kwargs)
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/postprocessor/common.py", line 129, in wrapper
    return func(self, info)
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/postprocessor/ffmpeg.py", line 706, in run
    self.run_ffmpeg_multiple_files(
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/postprocessor/ffmpeg.py", line 324, in run_ffmpeg_multiple_files
    return self.real_run_ffmpeg(
  File "C:/msys64/mingw64/lib/python3.9/site-packages/yt_dlp/postprocessor/ffmpeg.py", line 362, in real_run_ffmpeg
    raise FFmpegPostProcessorError(stderr.strip().splitlines()[-1])
yt_dlp.postprocessor.ffmpeg.FFmpegPostProcessorError: To ignore this, add a trailing '?' to the map.
```



Discussion:
This needs a provider account and/or being in region to reproduce and debug fully.

However, the problem originates in `_parse_smil_formats()` where the URL from the log

https://hls-manifest.apps.nbcuni.com/manifest/hls/3646439?brand=nbc&cacheVersion=x_RqYLP9_Jad&userData=1673508510000:cdedf4f24246d36fec9b9f98a6550fd3ba5439932eadf2d2e1c114a7435b04d6

is not being recognised as M3U8 by the `determine_ext()` function.

Maybe the `ext` value (`= medium.get('ext')`) sent by the site should be checked? Or a URL with `/manifest/hls/` should be recognised as M3U8?

Or, additional processing could be done in `ThePlatformBaseIE._extract_theplatform_smil()` when adding the SMIL formats, eg, after looking at the `Content-Type` from a `HEAD` request.
> This needs a provider account and/or being in region to reproduce and debug fully.

The video clip doesn't need a provider.
https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439
It's geo-blocked from the UK, but possibly a provider account might unblock it.
> It's geo-blocked from the UK, but possibly a provider account might unblock it.

Maybe, maybe not. Just use a VPN.

To make matters worse, newer video clips don't follow the older URL scheme-

[generic] Extracting URL: https://www.nbc.com/quantum-leap/video/bens-first-leap-nbcs-quantum-leap/NBCE125189978
[generic] NBCE125189978: Downloading webpage
WARNING: [generic] Falling back on generic information extractor
[generic] NBCE125189978: Extracting information
ERROR: Unsupported URL: https://www.nbc.com/quantum-leap/video/bens-first-leap-nbcs-quantum-leap/NBCE125189978

Yes, but that's straightforward (at least according to the metadata -- I didn't watch it):
```diff
-    _VALID_URL = r'https?(?P<permalink>://(?:www\.)?nbc\.com/(?:classic-tv/)?[^/]+/video/[^/]+/(?P<id>n?\d+))'
+    _VALID_URL = r'https?(?P<permalink>://(?:www\.)?nbc\.com/(?:classic-tv/)?[^/]+/video/[^/]+/(?:NBC[A-Z])?(?P<id>n?\d+))'
```
Or if the final component only ever has `E` after `NBC`, replace `[A-Z]` with `E`.

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
@@ -32,6 +32,7 @@
     FormatSorter,
     GeoRestrictedError,
     GeoUtils,
+    HEADRequest,
     LenientJSONDecoder,
     RegexNotFoundError,
     RetryManager,
@@ -80,6 +81,7 @@
     update_Request,
     update_url_query,
     url_basename,
+    urlhandle_detect_ext,
     url_or_none,
     urljoin,
     variadic,
@@ -2311,7 +2313,8 @@ def _parse_smil_formats(self, smil, smil_url, video_id, namespace=None, f4m_para
             height = int_or_none(medium.get('height'))
             proto = medium.get('proto')
             ext = medium.get('ext')
-            src_ext = determine_ext(src)
+            src_ext = determine_ext(src, default_ext=None) or ext or urlhandle_detect_ext(
+                self._request_webpage(HEADRequest(src), video_id, note='Requesting extension info', fatal=False))
             streamer = medium.get('streamer') or base
 
             if proto == 'rtmp' or streamer.startswith('rtmp'):
diff --git a/yt_dlp/extractor/nbc.py b/yt_dlp/extractor/nbc.py
--- a/yt_dlp/extractor/nbc.py
+++ b/yt_dlp/extractor/nbc.py
@@ -8,24 +8,26 @@
 from ..compat import compat_urllib_parse_unquote
 from ..utils import (
     ExtractorError,
+    HEADRequest,
+    RegexNotFoundError,
+    UserNotLive,
+    clean_html,
     int_or_none,
     parse_age_limit,
     parse_duration,
-    RegexNotFoundError,
     smuggle_url,
-    str_or_none,
     traverse_obj,
     try_get,
-    unified_strdate,
+    unescapeHTML,
     unified_timestamp,
     update_url_query,
     url_basename,
-    variadic,
+    xpath_attr,
 )
 
 
 class NBCIE(ThePlatformIE):  # XXX: Do not subclass from concrete IE
-    _VALID_URL = r'https?(?P<permalink>://(?:www\.)?nbc\.com/(?:classic-tv/)?[^/]+/video/[^/]+/(?P<id>n?\d+))'
+    _VALID_URL = r'https?(?P<permalink>://(?:www\.)?nbc\.com/(?:classic-tv/)?[^/]+/video/[^/]+/(?P<id>(?:NBCE|n)?\d+))'
 
     _TESTS = [
         {
@@ -38,10 +40,18 @@ class NBCIE(ThePlatformIE):  # XXX: Do not subclass from concrete IE
                 'timestamp': 1424246400,
                 'upload_date': '20150218',
                 'uploader': 'NBCU-COM',
+                'episode': 'Jimmy Fallon Surprises Fans at Ben & Jerry\'s',
+                'episode_number': 86,
+                'season': 'Season 2',
+                'season_number': 2,
+                'series': 'Tonight Show: Jimmy Fallon',
+                'duration': 237.0,
+                'chapters': 'count:1',
+                'tags': 'count:4',
+                'thumbnail': r're:https?://.+\.jpg',
             },
             'params': {
-                # m3u8 download
-                'skip_download': True,
+                'skip_download': 'm3u8',
             },
         },
         {
@@ -55,11 +65,7 @@ class NBCIE(ThePlatformIE):  # XXX: Do not subclass from concrete IE
                 'upload_date': '20141206',
                 'uploader': 'NBCU-COM',
             },
-            'params': {
-                # m3u8 download
-                'skip_download': True,
-            },
-            'skip': 'Only works from US',
+            'skip': 'page not found',
         },
         {
             # HLS streams requires the 'hdnea3' cookie
@@ -73,10 +79,59 @@ class NBCIE(ThePlatformIE):  # XXX: Do not subclass from concrete IE
                 'upload_date': '20090315',
                 'uploader': 'NBCU-COM',
             },
+            'skip': 'page not found',
+        },
+        {
+            # manifest url does not have extension
+            'url': 'https://www.nbc.com/the-golden-globe-awards/video/oprah-winfrey-receives-cecil-b-de-mille-award-at-the-2018-golden-globes/3646439',
+            'info_dict': {
+                'id': '3646439',
+                'ext': 'mp4',
+                'title': 'Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes',
+                'episode': 'Oprah Winfrey Receives Cecil B. de Mille Award at the 2018 Golden Globes',
+                'episode_number': 1,
+                'season': 'Season 75',
+                'season_number': 75,
+                'series': 'The Golden Globe Awards',
+                'description': 'Oprah Winfrey receives the Cecil B. de Mille Award at the 75th Annual Golden Globe Awards.',
+                'uploader': 'NBCU-COM',
+                'upload_date': '20180107',
+                'timestamp': 1515312000,
+                'duration': 570.0,
+                'tags': 'count:8',
+                'thumbnail': r're:https?://.+\.jpg',
+                'chapters': 'count:1',
+            },
+            'params': {
+                'skip_download': 'm3u8',
+            },
+        },
+        {
+            # new video_id format
+            'url': 'https://www.nbc.com/quantum-leap/video/bens-first-leap-nbcs-quantum-leap/NBCE125189978',
+            'info_dict': {
+                'id': 'NBCE125189978',
+                'ext': 'mp4',
+                'title': 'Ben\'s First Leap | NBC\'s Quantum Leap',
+                'description': 'md5:a82762449b7ec4bb83291a7b355ebf8e',
+                'uploader': 'NBCU-COM',
+                'series': 'Quantum Leap',
+                'season': 'Season 1',
+                'season_number': 1,
+                'episode': 'Ben\'s First Leap | NBC\'s Quantum Leap',
+                'episode_number': 1,
+                'duration': 170.171,
+                'chapters': [],
+                'timestamp': 1663956155,
+                'upload_date': '20220923',
+                'tags': 'count:10',
+                'age_limit': 0,
+                'thumbnail': r're:https?://.+\.jpg',
+            },
+            'expected_warnings': ['Ignoring subtitle tracks'],
             'params': {
-                'skip_download': True,
+                'skip_download': 'm3u8',
             },
-            'skip': 'Only works from US',
         },
         {
             'url': 'https://www.nbc.com/classic-tv/charles-in-charge/video/charles-in-charge-pilot/n3310',
@@ -600,32 +655,36 @@ class NBCStationsIE(InfoExtractor):
 
     _TESTS = [{
         'url': 'https://www.nbclosangeles.com/news/local/large-structure-fire-in-downtown-la-prompts-smoke-odor-advisory/2968618/',
-        'md5': '462041d91bd762ef5a38b7d85d6dc18f',
         'info_dict': {
             'id': '2968618',
             'ext': 'mp4',
             'title': 'Large Structure Fire in Downtown LA Prompts Smoke Odor Advisory',
-            'description': None,
+            'description': 'md5:417ed3c2d91fe9d301e6db7b0942f182',
             'timestamp': 1661135892,
-            'upload_date': '20220821',
+            'upload_date': '20220822',
             'uploader': 'NBC 4',
-            'uploader_id': 'KNBC',
+            'channel_id': 'KNBC',
             'channel': 'nbclosangeles',
         },
+        'params': {
+            'skip_download': 'm3u8',
+        },
     }, {
         'url': 'https://www.telemundoarizona.com/responde/huracan-complica-reembolso-para-televidente-de-tucson/2247002/',
-        'md5': '0917dcf7885be1023a9220630d415f67',
         'info_dict': {
             'id': '2247002',
             'ext': 'mp4',
-            'title': 'Huracán complica que televidente de Tucson reciba reembolso',
+            'title': 'Huracán complica que televidente de Tucson reciba  reembolso',
             'description': 'md5:af298dc73aab74d4fca6abfb12acb6cf',
             'timestamp': 1660886507,
             'upload_date': '20220819',
             'uploader': 'Telemundo Arizona',
-            'uploader_id': 'KTAZ',
+            'channel_id': 'KTAZ',
             'channel': 'telemundoarizona',
         },
+        'params': {
+            'skip_download': 'm3u8',
+        },
     }]
 
     _RESOLUTIONS = {
@@ -644,48 +703,39 @@ def _real_extract(self, url):
             r'<script>var\s*nbc\s*=', webpage, 'NBC JSON data', video_id)
         pdk_acct = nbc_data.get('pdkAcct') or 'Yh1nAC'
         fw_ssid = traverse_obj(nbc_data, ('video', 'fwSSID'))
-        fw_network_id = traverse_obj(nbc_data, ('video', 'fwNetworkID'), default='382114')
 
-        video_data = self._parse_json(self._html_search_regex(
-            r'data-videos="([^"]*)"', webpage, 'video data', default='{}'), video_id)
-        video_data = variadic(video_data)[0]
-        video_data.update(self._parse_json(self._html_search_regex(
-            r'data-meta="([^"]*)"', webpage, 'metadata', default='{}'), video_id))
+        video_data = self._search_json(
+            r'data-videos="\[', webpage, 'video data', video_id, default={}, transform_source=unescapeHTML)
+        video_data.update(self._search_json(
+            r'data-meta="', webpage, 'metadata', video_id, default={}, transform_source=unescapeHTML))
+        if not video_data:
+            raise ExtractorError('No video metadata found in webpage', expected=True)
 
-        formats = []
+        info, formats, subtitles = {}, [], {}
+        is_live = int_or_none(video_data.get('mpx_is_livestream')) == 1
+        query = {
+            'formats': 'MPEG-DASH none,M3U none,MPEG-DASH none,MPEG4,MP3',
+            'format': 'SMIL',
+            'fwsitesection': fw_ssid,
+            'fwNetworkID': traverse_obj(nbc_data, ('video', 'fwNetworkID'), default='382114'),
+            'pprofile': 'ots_desktop_html',
+            'sensitive': 'false',
+            'w': '1920',
+            'h': '1080',
+            'mode': 'LIVE' if is_live else 'on-demand',
+            'vpaid': 'script',
+            'schema': '2.0',
+            'sdk': 'PDK 6.1.3',
+        }
 
-        if video_data.get('mpx_is_livestream') == '1':
-            live = True
-            player_id = traverse_obj(
-                video_data, 'mpx_m3upid', ('video', 'meta', 'mpx_m3upid'), 'mpx_pid',
-                ('video', 'meta', 'mpx_pid'), 'pid_streaming_web_medium')
-            query = {
-                'mbr': 'true',
-                'assetTypes': 'LegacyRelease',
-                'fwsitesection': fw_ssid,
-                'fwNetworkID': fw_network_id,
-                'pprofile': 'ots_desktop_html',
-                'sensitive': 'false',
-                'w': '1920',
-                'h': '1080',
-                'rnd': '1660303',
-                'mode': 'LIVE',
-                'format': 'SMIL',
-                'tracking': 'true',
-                'formats': 'M3U+none,MPEG-DASH+none,MPEG4,MP3',
-                'vpaid': 'script',
-                'schema': '2.0',
-                'SDK': 'PDK+6.1.3',
-            }
-            info = {
-                'title': f'{channel} livestream',
-            }
+        if is_live:
+            player_id = traverse_obj(video_data, ((None, ('video', 'meta')), (
+                'mpx_m3upid', 'mpx_pid', 'pid_streaming_web_medium')), get_all=False)
+            info['title'] = f'{channel} livestream'
 
         else:
-            live = False
-            player_id = traverse_obj(
-                video_data, ('video', 'meta', 'pid_streaming_web_high'), 'pid_streaming_web_high',
-                ('video', 'meta', 'mpx_pid'), 'mpx_pid')
+            player_id = traverse_obj(video_data, (
+                (None, ('video', 'meta')), ('pid_streaming_web_high', 'mpx_pid')), get_all=False)
 
             date_string = traverse_obj(video_data, 'date_string', 'date_gmt')
             if date_string:
@@ -693,63 +743,58 @@ def _real_extract(self, url):
                     r'datetime="([^"]+)"', date_string, 'date string', fatal=False)
             else:
                 date_string = traverse_obj(
-                    nbc_data, ('dataLayer', 'adobe', 'prop70'), ('dataLayer', 'adobe', 'eVar70'),
-                    ('dataLayer', 'adobe', 'eVar59'))
+                    nbc_data, ('dataLayer', 'adobe', ('prop70', 'eVar70', 'eVar59')), get_all=False)
 
-            video_url = traverse_obj(video_data, ('video', 'meta', 'mp4_url'), 'mp4_url')
+            video_url = traverse_obj(video_data, ((None, ('video', 'meta')), 'mp4_url'), get_all=False)
             if video_url:
-                height = url_basename(video_url).split('-')[1].split('p')[0]
+                height = self._search_regex(r'\d+-(\d+)p', url_basename(video_url), 'height', default=None)
                 formats.append({
                     'url': video_url,
                     'ext': 'mp4',
                     'width': int_or_none(self._RESOLUTIONS.get(height)),
                     'height': int_or_none(height),
-                    'format_id': f'http-{height}',
+                    'format_id': 'http-mp4',
                 })
 
-            query = {
-                'mbr': 'true',
-                'assetTypes': 'LegacyRelease',
-                'fwsitesection': fw_ssid,
-                'fwNetworkID': fw_network_id,
-                'format': 'redirect',
-                'manifest': 'm3u',
-                'Tracking': 'true',
-                'Embedded': 'true',
-                'formats': 'MPEG4',
-            }
-            info = {
-                'title': video_data.get('title') or traverse_obj(
-                    nbc_data, ('dataLayer', 'contenttitle'), ('dataLayer', 'title'),
-                    ('dataLayer', 'adobe', 'prop22'), ('dataLayer', 'id')),
-                'description': traverse_obj(video_data, 'summary', 'excerpt', 'video_hero_text'),
-                'upload_date': str_or_none(unified_strdate(date_string)),
-                'timestamp': int_or_none(unified_timestamp(date_string)),
-            }
-
-        if not player_id:
-            raise ExtractorError(
-                'No video player ID or livestream player ID found in webpage', expected=True)
-
-        headers = {'Origin': f'https://www.{channel}.com'}
-        manifest, urlh = self._download_webpage_handle(
-            f'https://link.theplatform.com/s/{pdk_acct}/{player_id}', video_id,
-            headers=headers, query=query, note='Downloading manifest')
-        if live:
-            manifest_url = self._search_regex(r'<video src="([^"]*)', manifest, 'manifest URL')
-        else:
-            manifest_url = urlh.geturl()
+            info.update({
+                'title': video_data.get('title') or traverse_obj(nbc_data, (
+                    'dataLayer', (None, 'adobe'), ('contenttitle', 'title', 'prop22')), get_all=False),
+                'description':
+                    traverse_obj(video_data, 'summary', 'excerpt', 'video_hero_text')
+                    or clean_html(traverse_obj(nbc_data, ('dataLayer', 'summary'))),
+                'timestamp': unified_timestamp(date_string),
+            })
 
-        formats.extend(self._extract_m3u8_formats(
-            manifest_url, video_id, 'mp4', headers=headers, m3u8_id='hls',
-            fatal=live, live=live, errnote='No HLS formats found'))
+        smil = None
+        if player_id and fw_ssid:
+            smil = self._download_xml(
+                f'https://link.theplatform.com/s/{pdk_acct}/{player_id}', video_id,
+                note='Downloading SMIL data', query=query, fatal=is_live)
+        if smil:
+            manifest_url = xpath_attr(smil, './/{*}video', 'src', fatal=is_live)
+            subtitles = self._parse_smil_subtitles(smil, '*')
+            fmts, subs = self._extract_m3u8_formats_and_subtitles(
+                manifest_url, video_id, 'mp4', m3u8_id='hls', fatal=is_live,
+                live=is_live, errnote='No HLS formats found')
+            formats.extend(fmts)
+            self._merge_subtitles(subs, target=subtitles)
+
+        if not formats:
+            self.raise_no_formats('No video content found in webpage', expected=True)
+        elif is_live:
+            try:
+                self._request_webpage(
+                    HEADRequest(formats[0]['url']), video_id, note='Checking live status')
+            except ExtractorError:
+                raise UserNotLive(video_id=channel)
 
         return {
-            'id': str_or_none(video_id),
+            'id': video_id,
             'channel': channel,
-            'uploader': str_or_none(nbc_data.get('on_air_name')),
-            'uploader_id': str_or_none(nbc_data.get('callLetters')),
+            'channel_id': nbc_data.get('callLetters'),
+            'uploader': nbc_data.get('on_air_name'),
             'formats': formats,
-            'is_live': live,
+            'subtitles': subtitles,
+            'is_live': is_live,
             **info,
         }


Test patch: