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

Code before:
                time.sleep(sleep_interval)
        else:
            self._downloader._first_webpage_request = False

        if note is None:
            self.report_download_webpage(video_id)
        elif note is not False:
            if video_id is None:
                self.to_screen(str(note))
            else:
                self.to_screen(f'{video_id}: {note}')

        # Some sites check X-Forwarded-For HTTP header in order to figure out
        # the origin of the client behind proxy. This allows bypassing geo
        # restriction by faking this header's value to IP that belongs to some
        # geo unrestricted country. We will do so once we encounter any
        # geo restriction error.
        if self._x_forwarded_for_ip:
            headers = (headers or {}).copy()
            headers.setdefault('X-Forwarded-For', self._x_forwarded_for_ip)

        extensions = None
        if impersonate is not None:
            target = ImpersonateTarget.from_str(':' if impersonate is True else impersonate)
            if force_impersonate or self._downloader._impersonate_target_available(target):
                extensions = {'impersonate': target}

        try:
            return self._downloader.urlopen(self._create_request(url_or_request, data, headers, query, extensions))
        except network_exceptions as err:
            if isinstance(err, HTTPError):
                if self.__can_accept_status_code(err, expected_status):
                    return err.response

            if errnote is False:
                return False
            if errnote is None:
                errnote = 'Unable to download webpage'

            errmsg = f'{errnote}: {error_to_compat_str(err)}'
            if fatal:
                raise ExtractorError(errmsg, cause=err)
            else:
                self.report_warning(errmsg)
                return False

    def _download_webpage_handle(self, url_or_request, video_id, note=None, errnote=None, fatal=True,
                                 encoding=None, data=None, headers={}, query={}, expected_status=None,
                                 impersonate=None, force_impersonate=False):
        """
        Return a tuple (page content as string, URL handle).

Review comment (bug):
> Something else we could consider is allowing a preferred order of multiple impersonate targets for a particular request, though I don't know of any sites where that would be necessary.

This is trivial to support if needed

```suggestion
        impersonate = tuple(map(ImpersonateTarget.from_str,
                                [':'] if impersonate is True else impersonate))
        extensions = {'impersonate': next(
            filter(self._downloader._impersonate_target_available, impersonate),
            impersonate[0] if force_impersonate and impersonate else None)}
       if impersonate and not extensions['impersonate']:
           self.write_debug('None of the impersonation targets are available')
```

Code after:
                time.sleep(sleep_interval)
        else:
            self._downloader._first_webpage_request = False

        if note is None:
            self.report_download_webpage(video_id)
        elif note is not False:
            if video_id is None:
                self.to_screen(str(note))
            else:
                self.to_screen(f'{video_id}: {note}')

        # Some sites check X-Forwarded-For HTTP header in order to figure out
        # the origin of the client behind proxy. This allows bypassing geo
        # restriction by faking this header's value to IP that belongs to some
        # geo unrestricted country. We will do so once we encounter any
        # geo restriction error.
        if self._x_forwarded_for_ip:
            headers = (headers or {}).copy()
            headers.setdefault('X-Forwarded-For', self._x_forwarded_for_ip)

        extensions = {}

        if impersonate in (True, ''):
            impersonate = ImpersonateTarget()
        requested_targets = [
            t if isinstance(t, ImpersonateTarget) else ImpersonateTarget.from_str(t)
            for t in variadic(impersonate)
        ] if impersonate else []

        available_target = next(filter(self._downloader._impersonate_target_available, requested_targets), None)
        if available_target:
            extensions['impersonate'] = available_target
        elif requested_targets:
            message = 'The extractor is attempting impersonation, but '
            message += (
                'no impersonate target is available' if not str(impersonate)
                else f'none of these impersonate targets are available: "{", ".join(map(str, requested_targets))}"')
            info_msg = ('see  https://github.com/yt-dlp/yt-dlp#impersonation  '
                        'for information on installing the required dependencies')
            if require_impersonation:
                raise ExtractorError(f'{message}; {info_msg}', expected=True)
            self.report_warning(f'{message}; if you encounter errors, then {info_msg}', only_once=True)

        try:
            return self._downloader.urlopen(self._create_request(url_or_request, data, headers, query, extensions))
        except network_exceptions as err:
            if isinstance(err, HTTPError):
                if self.__can_accept_status_code(err, expected_status):
                    return err.response