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

Code before:
            'uploader': gif_data.get('userName'),
            'duration': int_or_none(gif_data.get('duration')),
            'view_count': int_or_none(gif_data.get('views')),
            'like_count': int_or_none(gif_data.get('likes')),
            'categories': gif_data.get('tags') or [],
            'tags': gif_data.get('tags'),
            'age_limit': 18,
            'formats': formats,
        }

    def _fetch_oauth_token(self, video_id):
        # These pages contain the OAuth token that is necessary to make API calls.
        index_page = self._download_webpage(f'https://www.redgifs.com/watch/{video_id}', video_id)
        index_js_uri = self._html_search_regex(r'href="?(/assets/js/index[.a-z0-9]*.js)"?\W',
                                               index_page, 'index_js_uri')
        index_js = self._download_webpage('https://www.redgifs.com/' + index_js_uri, video_id)

        # It turns out that a { followed by any valid JSON punctuation will always result in the
        # first two characters of the base64 encoding being "ey".
        #
        # Use this fact to find any such string constant of a reasonable length with the correct
        # punctuation for an oauth token
        oauth_token = self._html_search_regex(r'\w+[=:]"(ey[^"]+\.[^"]*\.[^"]{43,45})"',
                                              index_js.replace(' ', ''),
                                              'oauth_token')
        self._API_HEADERS['authorization'] = "Bearer " + oauth_token

    def _call_api(self, ep, video_id, *args, **kwargs):
        if 'authorization' not in self._API_HEADERS:
            self._fetch_oauth_token(video_id)
        assert 'authorization' in self._API_HEADERS

        headers = dict(self._API_HEADERS)
        headers['x-customheader'] = f'https://www.redgifs.com/watch/{video_id}'
        data = self._download_json(
            f'https://api.redgifs.com/v2/{ep}', video_id, headers=headers, *args, **kwargs)
        if 'error' in data:
            raise ExtractorError(f'RedGifs said: {data["error"]}', expected=True, video_id=video_id)
        return data

    def _fetch_page(self, ep, video_id, query, page):
        query['page'] = page + 1
        data = self._call_api(
            ep, video_id, query=query, note=f'Downloading JSON metadata page {page + 1}')

        for entry in data['gifs']:
            yield self._parse_gif_data(entry)

    def _prepare_api_query(self, query, fields):
        api_query = [
            (field_name, query.get(field_name, (default,))[0])

Review comment (security):
```suggestion
        index_page = self._download_webpage(f'https://www.redgifs.com/watch/{video_id}', video_id)
        index_js_uri = self._html_search_regex(
            r'href="?(/assets/js/index[.a-z0-9]*.js)"?\W',index_page, 'index_js_uri')
        index_js = self._download_webpage(f'https://www.redgifs.com/{index_js_uri}', video_id)

        # It turns out that a { followed by any valid JSON punctuation will always result in the
        # first two characters of the base64 encoding being "ey".
        # Use this fact to find any such string constant of a reasonable length with the correct
        # punctuation for an oauth token
        oauth_token = self._html_search_regex(
            r'\w+\s*[=:]\s*"(ey[^"]+\.[^"]*\.[^"]{43,45})"', index_js, 'oauth token')
        self._API_HEADERS['authorization'] = f'Bearer {oauth_token}'
```

Code after:
            'title': ' '.join(gif_data.get('tags') or []) or 'RedGifs',
            'timestamp': int_or_none(gif_data.get('createDate')),
            'uploader': gif_data.get('userName'),
            'duration': int_or_none(gif_data.get('duration')),
            'view_count': int_or_none(gif_data.get('views')),
            'like_count': int_or_none(gif_data.get('likes')),
            'categories': gif_data.get('tags') or [],
            'tags': gif_data.get('tags'),
            'age_limit': 18,
            'formats': formats,
        }

    def _fetch_oauth_token(self, video_id):
        # These pages contain the OAuth token that is necessary to make API calls.
        index_page = self._download_webpage(f'https://www.redgifs.com/watch/{video_id}', video_id)
        index_js_uri = self._html_search_regex(
            r'href="?(/assets/js/index[.a-z0-9]*.js)"?\W', index_page, 'index_js_uri')
        index_js = self._download_webpage(f'https://www.redgifs.com/{index_js_uri}', video_id)
        # It turns out that a { followed by any valid JSON punctuation will always result in the
        # first two characters of the base64 encoding being "ey".
        # Use this fact to find any such string constant of a reasonable length with the correct
        # punctuation for an oauth token
        oauth_token = self._html_search_regex(
            r'\w+\s*[=:]\s*"(ey[^"]+\.[^"]*\.[^"]{43,45})"', index_js, 'oauth token')
        self._API_HEADERS['authorization'] = f'Bearer {oauth_token}'

    def _call_api(self, ep, video_id, *args, **kwargs):
        if 'authorization' not in self._API_HEADERS:
            self._fetch_oauth_token(video_id)
        assert 'authorization' in self._API_HEADERS

        headers = dict(self._API_HEADERS)
        headers['x-customheader'] = f'https://www.redgifs.com/watch/{video_id}'
        data = self._download_json(
            f'https://api.redgifs.com/v2/{ep}', video_id, headers=headers, *args, **kwargs)
        if 'error' in data:
            raise ExtractorError(f'RedGifs said: {data["error"]}', expected=True, video_id=video_id)
        return data

    def _fetch_page(self, ep, video_id, query, page):
        query['page'] = page + 1
        data = self._call_api(
            ep, video_id, query=query, note=f'Downloading JSON metadata page {page + 1}')

        for entry in data['gifs']:
            yield self._parse_gif_data(entry)

    def _prepare_api_query(self, query, fields):
        api_query = [
            (field_name, query.get(field_name, (default,))[0])
            for field_name, default in fields.items()]