Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/youtube.py (Python)

Code before:

        return webpage, data

    def _extract_data(self, url, item_id, ytcfg=None, fatal=True, webpage_fatal=False, default_client='web'):
        data = None
        if 'webpage' not in self._configuration_arg('skip'):
            webpage, data = self._extract_webpage(url, item_id, fatal=webpage_fatal)
            ytcfg = ytcfg or self.extract_ytcfg(item_id, webpage)
        if not data:
            if not ytcfg and self.is_authenticated:
                msg = 'Lists that require authentication may not extract correctly without a successful webpage download.'
                if 'authcheck' not in self._configuration_arg('skip') and fatal:
                    raise ExtractorError(
                        msg + ' If you are not downloading private content, or your cookies are only for the first account and channel,'
                              ' pass "--extractor-args youtubetab:skip=authcheck" to skip this check',
                        expected=True)
                self.report_warning(msg, only_once=True)
            data = self._extract_tab_endpoint(url, item_id, ytcfg, fatal=fatal, default_client=default_client)
        return data, ytcfg

    def _extract_tab_endpoint(self, url, item_id, ytcfg=None, fatal=True, default_client='web'):
        headers = self.generate_api_headers(ytcfg=ytcfg, default_client=default_client)
        resolve_response = self._extract_response(
            item_id=item_id, query={'url': url}, check_get_keys='endpoint', headers=headers, ytcfg=ytcfg, fatal=fatal,
            ep='navigation/resolve_url', note='Downloading API parameters API JSON', default_client=default_client
        )
        endpoints = {'browseEndpoint': 'browse', 'watchEndpoint': 'next'}
        for ep_key, ep in endpoints.items():
            params = try_get(resolve_response, lambda x: x['endpoint'][ep_key], dict)
            if params:
                return self._extract_response(
                    item_id=item_id, query=params, ep=ep, headers=headers,
                    ytcfg=ytcfg, fatal=fatal, default_client=default_client,
                    check_get_keys=('contents', 'currentVideoEndpoint'))

    @staticmethod
    def _smuggle_data(entries, data):
        for entry in entries:
            if data:
                entry['url'] = smuggle_url(entry['url'], data)
            yield entry

    def _real_extract(self, url):
        url, smuggled_data = unsmuggle_url(url, {})
        if self.is_music_url(url):
            smuggled_data['is_music_url'] = True
        info_dict = self.__real_extract(url, smuggled_data)
        if info_dict.get('entries'):
            info_dict['entries'] = self._smuggle_data(info_dict['entries'], smuggled_data)
        return info_dict


Review comment (suggestion):
```suggestion
            ep='navigation/resolve_url', note='Downloading API parameters API JSON', default_client=default_client)
```

Code after:
            text = try_get(
                nav_item_renderer, lambda x: x['text']['simpleText'], compat_str)
            if not text or text.lower() != 'show unavailable videos':
                continue
            browse_endpoint = try_get(
                nav_item_renderer, lambda x: x['navigationEndpoint']['browseEndpoint'], dict) or {}
            browse_id = browse_endpoint.get('browseId')
            params = browse_endpoint.get('params')
            break

        headers = self.generate_api_headers(
            ytcfg=ytcfg, account_syncid=self._extract_account_syncid(ytcfg, data),
            visitor_data=self._extract_visitor_data(data, ytcfg))
        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, ytcfg=ytcfg,
            note='Downloading API JSON with unavailable videos')

    def _extract_webpage(self, url, item_id, fatal=True):
        retries = self.get_param('extractor_retries', 3)
        count = -1
        webpage = data = last_error = None
        while count < retries:
            count += 1
            # Sometimes youtube returns a webpage with incomplete ytInitialData
            # See: https://github.com/yt-dlp/yt-dlp/issues/116
            if last_error:
                self.report_warning('%s. Retrying ...' % last_error)
            try:
                webpage = self._download_webpage(
                    url, item_id,
                    note='Downloading webpage%s' % (' (retry #%d)' % count if count else '',))
                data = self.extract_yt_initial_data(item_id, webpage or '', fatal=fatal) or {}
            except ExtractorError as e:
                if isinstance(e.cause, network_exceptions):
                    if not isinstance(e.cause, compat_HTTPError) or e.cause.code not in (403, 429):
                        last_error = error_to_compat_str(e.cause or e.msg)
                        if count < retries:
                            continue
                if fatal:
                    raise
                self.report_warning(error_to_compat_str(e))
                break
            else:
                try:
                    self._extract_and_report_alerts(data)
                except ExtractorError as e: