]> jfr.im git - yt-dlp.git/blobdiff - yt_dlp/extractor/youtube.py
[youtube:tab] Reload with unavailable videos for all playlists
[yt-dlp.git] / yt_dlp / extractor / youtube.py
index 547f5b171dd9e55a36e348cf5d2f7c9fd2292116..4c9da101f5a09739296e41c620a86072b49cb75d 100644 (file)
@@ -128,7 +128,7 @@ def req(url, f_req, note, errnote):
                 })
 
         def warn(message):
-            self._downloader.report_warning(message)
+            self.report_warning(message)
 
         lookup_req = [
             username,
@@ -1739,7 +1739,7 @@ def extract_thread(parent_renderer):
                     # See: https://github.com/ytdl-org/youtube-dl/issues/28194
                     last_error = 'Incomplete data received'
                     if count >= retries:
-                        self._downloader.report_error(last_error)
+                        raise ExtractorError(last_error)
 
             if not response:
                 break
@@ -2050,7 +2050,7 @@ def feed_entry(name):
 
         if not formats:
             if not self._downloader.params.get('allow_unplayable_formats') and streaming_data.get('licenseInfos'):
-                raise ExtractorError(
+                self.raise_no_formats(
                     'This video is DRM protected.', expected=True)
             pemr = try_get(
                 playability_status,
@@ -2065,11 +2065,10 @@ def feed_entry(name):
                     if not countries:
                         regions_allowed = search_meta('regionsAllowed')
                         countries = regions_allowed.split(',') if regions_allowed else None
-                    self.raise_geo_restricted(
-                        subreason, countries)
+                    self.raise_geo_restricted(subreason, countries, metadata_available=True)
                 reason += '\n' + subreason
             if reason:
-                raise ExtractorError(reason, expected=True)
+                self.raise_no_formats(reason, expected=True)
 
         self._sort_formats(formats)
 
@@ -2642,6 +2641,16 @@ class YoutubeTabIE(YoutubeBaseInfoExtractor):
         'expected_warnings': [
             'YouTube said: INFO - Unavailable videos are hidden',
         ]
+    }, {
+        'note': 'Playlist with unavailable videos in a later page',
+        'url': 'https://www.youtube.com/playlist?list=UU8l9frL61Yl5KFOl87nIm2w',
+        'info_dict': {
+            'title': 'Uploads from BlankTV',
+            'id': 'UU8l9frL61Yl5KFOl87nIm2w',
+            'uploader': 'BlankTV',
+            'uploader_id': 'UC8l9frL61Yl5KFOl87nIm2w',
+        },
+        'playlist_mincount': 20000,
     }, {
         # https://github.com/ytdl-org/youtube-dl/issues/21844
         'url': 'https://www.youtube.com/playlist?list=PLzH6n4zXuckpfMu_4Ff8E7Z1behQks5ba',
@@ -3303,7 +3312,7 @@ def _real_extract_alerts():
                 warnings.append([alert_type, alert_message])
 
         for alert_type, alert_message in (warnings + errors[:-1]):
-            self._downloader.report_warning('YouTube said: %s - %s' % (alert_type, alert_message))
+            self.report_warning('YouTube said: %s - %s' % (alert_type, alert_message))
         if errors:
             raise ExtractorError('YouTube said: %s' % errors[-1][1], expected=expected)
 
@@ -3312,7 +3321,10 @@ def _reload_with_unavailable_videos(self, item_id, data, webpage):
         Get playlist with unavailable videos if the 'show unavailable videos' button exists.
         """
         sidebar_renderer = try_get(
-            data, lambda x: x['sidebar']['playlistSidebarRenderer']['items'], list) or []
+            data, lambda x: x['sidebar']['playlistSidebarRenderer']['items'], list)
+        if not sidebar_renderer:
+            return
+        browse_id = params = None
         for item in sidebar_renderer:
             if not isinstance(item, dict):
                 continue
@@ -3331,22 +3343,22 @@ def _reload_with_unavailable_videos(self, item_id, data, webpage):
                     nav_item_renderer, lambda x: x['navigationEndpoint']['browseEndpoint'], dict) or {}
                 browse_id = browse_endpoint.get('browseId')
                 params = browse_endpoint.get('params')
-                if not browse_id or not params:
-                    return
-                ytcfg = self._extract_ytcfg(item_id, webpage)
-                headers = self._generate_api_headers(
-                    ytcfg, account_syncid=self._extract_account_syncid(ytcfg),
-                    identity_token=self._extract_identity_token(webpage, item_id=item_id),
-                    visitor_data=try_get(
-                        self._extract_context(ytcfg), lambda x: x['client']['visitorData'], compat_str))
-                query = {
-                    'params': params,
-                    'browseId': browse_id
-                }
-                return self._extract_response(
-                    item_id=item_id, headers=headers, query=query,
-                    check_get_keys='contents', fatal=False,
-                    note='Downloading API JSON with unavailable videos')
+                break
+
+            ytcfg = self._extract_ytcfg(item_id, webpage)
+            headers = self._generate_api_headers(
+                ytcfg, account_syncid=self._extract_account_syncid(ytcfg),
+                identity_token=self._extract_identity_token(webpage, item_id=item_id),
+                visitor_data=try_get(
+                    self._extract_context(ytcfg), lambda x: x['client']['visitorData'], compat_str))
+            query = {
+                'params': params or 'wgYCCAA=',
+                'browseId': browse_id or 'VL%s' % item_id
+            }
+            return self._extract_response(
+                item_id=item_id, headers=headers, query=query,
+                check_get_keys='contents', fatal=False,
+                note='Downloading API JSON with unavailable videos')
 
     def _extract_response(self, item_id, query, note='Downloading API JSON', headers=None,
                           ytcfg=None, check_get_keys=None, ep='browse', fatal=True):
@@ -3414,7 +3426,7 @@ def _extract_webpage(self, url, item_id):
             if data.get('contents') or data.get('currentVideoEndpoint'):
                 break
             if count >= retries:
-                self._downloader.report_error(last_error)
+                raise ExtractorError(last_error)
         return webpage, data
 
     def _real_extract(self, url):
@@ -3426,7 +3438,7 @@ def _real_extract(self, url):
         mobj = re.match(r'(?P<pre>%s)(?P<post>/?(?![^#?]).*$)' % self._VALID_URL, url)
         mobj = mobj.groupdict() if mobj else {}
         if mobj and not mobj.get('not_channel'):
-            self._downloader.report_warning(
+            self.report_warning(
                 'A channel/user page was given. All the channel\'s videos will be downloaded. '
                 'To download only the videos in the home page, add a "/featured" to the URL')
             url = '%s/videos%s' % (mobj.get('pre'), mobj.get('post') or '')
@@ -3441,7 +3453,7 @@ def _real_extract(self, url):
                 # If there is neither video or playlist ids,
                 # youtube redirects to home page, which is undesirable
                 raise ExtractorError('Unable to recognize tab page')
-            self._downloader.report_warning('A video URL was given without video ID. Trying to download playlist %s' % playlist_id)
+            self.report_warning('A video URL was given without video ID. Trying to download playlist %s' % playlist_id)
             url = 'https://www.youtube.com/playlist?list=%s' % playlist_id
 
         if video_id and playlist_id:
@@ -3469,7 +3481,7 @@ def _real_extract(self, url):
             data, lambda x: x['currentVideoEndpoint']['watchEndpoint']['videoId'],
             compat_str) or video_id
         if video_id:
-            self._downloader.report_warning('Unable to recognize playlist. Downloading just video %s' % video_id)
+            self.report_warning('Unable to recognize playlist. Downloading just video %s' % video_id)
             return self.url_result(video_id, ie=YoutubeIE.ie_key(), video_id=video_id)
 
         raise ExtractorError('Unable to recognize tab page')