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

Code before:
        yt_query.update(self._generate_player_context(sts))
        return self._extract_response(
            item_id=video_id, ep='player', query=yt_query,
            ytcfg=player_ytcfg, headers=headers, fatal=False,
            default_client=client,
            note='Downloading %s player API JSON' % client.replace('_', ' ').strip()
        ) or None

    def _get_requested_clients(self, url, smuggled_data):
        requested_clients = []
        allowed_clients = sorted(
            [client for client in INNERTUBE_CLIENTS.keys() if client[:1] != '_'],
            key=lambda client: INNERTUBE_CLIENTS[client]['priority'], reverse=True)
        for client in self._configuration_arg('player_client'):
            if client in allowed_clients:
                requested_clients.append(client)
            elif client == 'all':
                requested_clients.extend(allowed_clients)
            else:
                self.report_warning(f'Skipping unsupported client {client}')

        if not requested_clients:
            requested_clients = ['android', 'web']

            # Try web studio client if session cookies provided (bypass for "AGE_VERIFICATION_REQUIRED")
            if self._get_cookies('https://www.youtube.com').get("__Secure-3PAPISID") is not None:
                requested_clients.append("web_studio")

        if smuggled_data.get('is_music_url') or self.is_music_url(url):
            requested_clients.extend(
                f'{client}_music' for client in requested_clients if not client.endswith('_music'))

        return orderedSet(requested_clients)

    def _extract_player_ytcfg(self, client, video_id):
        url = {
            'web_music': 'https://music.youtube.com',
            'web_embedded': f'https://www.youtube.com/embed/{video_id}?html5=1'
        }.get(client)
        if not url:
            return {}
        webpage = self._download_webpage(url, video_id, fatal=False, note=f'Downloading {client} config')
        return self.extract_ytcfg(video_id, webpage) or {}

    def _extract_player_responses(self, clients, video_id, webpage, master_ytcfg, player_url, identity_token):
        initial_pr = None
        if webpage:
            initial_pr = self._extract_yt_initial_variable(
                webpage, self._YT_INITIAL_PLAYER_RESPONSE_RE,
                video_id, 'initial player response')


Review comment (refactor):
Probably put this in `_extract_player_responses` where it checks for age_gate:
https://github.com/yt-dlp/yt-dlp/blob/d24734daeaf7a13c304fbdf285622a5a6477f3ef/yt_dlp/extractor/youtube.py#L2485-L2488

Maybe something like: If we detect the response is age gated, check if the previous client was an agegate client & that we are supplying cookies, if so, add the relevant creator client.

Also an easier way to check for cookies is to call `_generate_sapisidhash_header` - if it returns something, user has provided working cookies.

Code after:
    def _is_unplayable(player_response):
        return traverse_obj(player_response, ('playabilityStatus', 'status')) == 'UNPLAYABLE'

    def _extract_player_response(self, client, video_id, master_ytcfg, player_ytcfg, identity_token, player_url, initial_pr):

        session_index = self._extract_session_index(player_ytcfg, master_ytcfg)
        syncid = self._extract_account_syncid(player_ytcfg, master_ytcfg, initial_pr)
        sts = self._extract_signature_timestamp(video_id, player_url, master_ytcfg, fatal=False)
        headers = self.generate_api_headers(
            player_ytcfg, identity_token, syncid,
            default_client=client, session_index=session_index)

        yt_query = {'videoId': video_id}
        yt_query.update(self._generate_player_context(sts))
        return self._extract_response(
            item_id=video_id, ep='player', query=yt_query,
            ytcfg=player_ytcfg, headers=headers, fatal=False,
            default_client=client,
            note='Downloading %s player API JSON' % client.replace('_', ' ').strip()
        ) or None

    def _get_requested_clients(self, url, smuggled_data):
        requested_clients = []
        allowed_clients = sorted(
            [client for client in INNERTUBE_CLIENTS.keys() if client[:1] != '_'],
            key=lambda client: INNERTUBE_CLIENTS[client]['priority'], reverse=True)
        for client in self._configuration_arg('player_client'):
            if client in allowed_clients:
                requested_clients.append(client)
            elif client == 'all':
                requested_clients.extend(allowed_clients)
            else:
                self.report_warning(f'Skipping unsupported client {client}')
        if not requested_clients:
            requested_clients = ['android', 'web']

        if smuggled_data.get('is_music_url') or self.is_music_url(url):
            requested_clients.extend(
                f'{client}_music' for client in requested_clients if f'{client}_music' in INNERTUBE_CLIENTS)

        return orderedSet(requested_clients)

    def _extract_player_ytcfg(self, client, video_id):
        url = {
            'web_music': 'https://music.youtube.com',
            'web_embedded': f'https://www.youtube.com/embed/{video_id}?html5=1'
        }.get(client)
        if not url:
            return {}
        webpage = self._download_webpage(url, video_id, fatal=False, note=f'Downloading {client} config')
        return self.extract_ytcfg(video_id, webpage) or {}