Repository: yt-dlp/yt-dlp

Issue:
[Reddit] Unable to download videos inside Reddit text posts.
### 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 **2022.11.11** ([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)
- [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

### Provide a description that is worded well enough to be understood

yt-dlp doesn't download any videos on Reddit text posts that contain multiple videos, it should download all videos. The command `yt-dlp "https://www.reddit.com/r/KamenRider/comments/wzqkxp/finale_kamen_rider_revice_episode_50_family_to/"` returns the following:

```
[Reddit] wzqkxp: Downloading JSON metadata
ERROR: [Reddit] wzqkxp: No media found
```

### 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
yt-dlp -vU "https://www.reddit.com/r/KamenRider/comments/wzqkxp/finale_kamen_rider_revice_episode_50_family_to/"

[debug] Command-line config: ['-vU', 'https://www.reddit.com/r/KamenRider/comments/wzqkxp/finale_kamen_rider_revice_episode_50_family_to/']
[debug] Encodings: locale UTF-8, fs utf-8, pref UTF-8, out utf-8 (No ANSI), error utf-8, screen utf-8 (No ANSI)
[debug] yt-dlp version 2022.11.11 [8b64402] (pip)
[debug] Python 3.9.13 (CPython arm64 64bit) - macOS-13.0.1-arm64-arm-64bit (OpenSSL 1.1.1o  3 May 2022)
[debug] exe versions: ffmpeg 5.0.1 (setts), ffprobe 5.0.1, rtmpdump 2.4
[debug] Optional libraries: Cryptodome-3.14.1, brotli-None, certifi-2022.09.24, mutagen-1.45.1, secretstorage-3.3.3, sqlite3-2.6.0, websockets-10.1
[debug] Proxy map: {}
[debug] Loaded 1723 extractors
[debug] Fetching release info: https://api.github.com/repos/yt-dlp/yt-dlp/releases/latest
Latest version: 2022.11.11, Current version: 2022.11.11
yt-dlp is up to date (2022.11.11)
[debug] [Reddit] Extracting URL: https://www.reddit.com/r/KamenRider/comments/wzqkxp/finale_kamen_rider_revice_episode_50_family_to/
[Reddit] wzqkxp: Downloading JSON metadata
ERROR: [Reddit] wzqkxp: No media found
  File "/opt/homebrew/lib/python3.9/site-packages/yt_dlp/extractor/common.py", line 674, in extract
    ie_result = self._real_extract(url)
  File "/opt/homebrew/lib/python3.9/site-packages/yt_dlp/extractor/reddit.py", line 107, in _real_extract
    raise ExtractorError('No media found', expected=True)
```



Discussion:

Resolving patch:
diff --git a/yt_dlp/extractor/reddit.py b/yt_dlp/extractor/reddit.py
--- a/yt_dlp/extractor/reddit.py
+++ b/yt_dlp/extractor/reddit.py
@@ -1,15 +1,15 @@
 import random
-from urllib.parse import urlparse
+import urllib.parse
 
 from .common import InfoExtractor
 from ..utils import (
     ExtractorError,
-    int_or_none,
     float_or_none,
+    int_or_none,
+    traverse_obj,
     try_get,
     unescapeHTML,
     url_or_none,
-    traverse_obj
 )
 
 
@@ -56,6 +56,14 @@ class RedditIE(InfoExtractor):
             'comment_count': int,
             'age_limit': 0,
         },
+    }, {
+        # videos embedded in reddit text post
+        'url': 'https://www.reddit.com/r/KamenRider/comments/wzqkxp/finale_kamen_rider_revice_episode_50_family_to/',
+        'playlist_count': 2,
+        'info_dict': {
+            'id': 'wzqkxp',
+            'title': 'md5:72d3d19402aa11eff5bd32fc96369b37',
+        },
     }, {
         'url': 'https://www.reddit.com/r/videos/comments/6rrwyj',
         'only_matching': True,
@@ -102,10 +110,6 @@ def _real_extract(self, url):
         data = data[0]['data']['children'][0]['data']
         video_url = data['url']
 
-        # Avoid recursing into the same reddit URL
-        if 'reddit.com/' in video_url and '/%s/' % video_id in video_url:
-            raise ExtractorError('No media found', expected=True)
-
         over_18 = data.get('over_18')
         if over_18 is True:
             age_limit = 18
@@ -148,6 +152,32 @@ def add_thumbnail(src):
             'age_limit': age_limit,
         }
 
+        parsed_url = urllib.parse.urlparse(video_url)
+
+        # Check for embeds in text posts, or else raise to avoid recursing into the same reddit URL
+        if 'reddit.com' in parsed_url.netloc and f'/{video_id}/' in parsed_url.path:
+            entries = []
+            for media in traverse_obj(data, ('media_metadata', ...), expected_type=dict):
+                if not media.get('id') or media.get('e') != 'RedditVideo':
+                    continue
+                formats = []
+                if media.get('hlsUrl'):
+                    formats.extend(self._extract_m3u8_formats(
+                        unescapeHTML(media['hlsUrl']), video_id, 'mp4', m3u8_id='hls', fatal=False))
+                if media.get('dashUrl'):
+                    formats.extend(self._extract_mpd_formats(
+                        unescapeHTML(media['dashUrl']), video_id, mpd_id='dash', fatal=False))
+                if formats:
+                    entries.append({
+                        'id': media['id'],
+                        'display_id': video_id,
+                        'formats': formats,
+                        **info,
+                    })
+            if entries:
+                return self.playlist_result(entries, video_id, info.get('title'))
+            raise ExtractorError('No media found', expected=True)
+
         # Check if media is hosted on reddit:
         reddit_video = traverse_obj(data, (('media', 'secure_media'), 'reddit_video'), get_all=False)
         if reddit_video:
@@ -189,7 +219,6 @@ def add_thumbnail(src):
                 'duration': int_or_none(reddit_video.get('duration')),
             }
 
-        parsed_url = urlparse(video_url)
         if parsed_url.netloc == 'v.redd.it':
             self.raise_no_formats('This video is processing', expected=True, video_id=video_id)
             return {


Test patch: