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

Code before:
            'title': video_data.get('name'),
            'description': video_data.get('description'),
            'formats': formats,
            'subtitles': subtitles,
            'thumbnails': traverse_obj(
                video_data, ('extra_thumbs', ..., {'url': 'thumb_url', 'height': 'height', 'width': 'width'})),
            'series_id': series_id,
            'season_id': season_id,
            'season_number': season_number,
            'episode_number': video_data.get('item_order'),
            'is_live': video_data.get('entry_type') == 3,
        }

    def _extract_series_season(self, series_id, season_id, season_number):
        api_response = self._download_json(
            'https://eu-gateway.inmobly.com/feed', series_id, query={'season_id': season_id},
            headers={'Authorization': 'Bearer ' + self._USER_TOKEN})

        for episode in api_response['items']:
            yield self._extract_video(episode, series_id, season_id, season_number)

    def _real_extract(self, url):
        series_id = self._match_id(url)

        if self._USER_TOKEN is None:
            self._login('guest@inmobly.com', 'Test@gus1')

        api_response = self._download_json(
            'https://eu-gateway.inmobly.com/feed', series_id, query={'include_ids': series_id},
            headers={'Authorization': 'Bearer ' + self._USER_TOKEN})['items'][0]

        if not api_response.get('seasons'):
            return self._extract_video(api_response)

        return self.playlist_result(
            itertools.chain.from_iterable(
                self._extract_series_season(series_id, season['id'], season.get('order'))
                for season in api_response['seasons']),
            series_id, **traverse_obj(api_response, {
                'title': 'name',
                'description': 'description',
            }))


Review comment (suggestion):
```suggestion
            self._perform_login('guest@inmobly.com', 'Test@gus1')
```

Code after:
            'subtitles': subtitles,
            'thumbnails': traverse_obj(
                video_data, ('extra_thumbs', ..., {'url': 'thumb_url', 'height': 'height', 'width': 'width'})),
            'series_id': series_id,
            'season_id': season_id,
            'season_number': int_or_none(season_number),
            'episode_number': int_or_none(video_data.get('item_order')),
            'is_live': video_data.get('entry_type') == 3,
        }

    def _extract_series_seasons(self, seasons, series_id):
        for season in seasons:
            api_response = self._download_json(
                'https://eu-gateway.inmobly.com/feed', series_id, query={'season_id': season['id']},
                headers={'Authorization': f'Bearer {self._USER_TOKEN}'})

            season_number = season.get('order')
            for episode in api_response['items']:
                yield self._extract_video(episode, series_id, season['id'], season_number)

    def _real_extract(self, url):
        series_id = self._match_id(url)

        if self._USER_TOKEN is None:
            self._perform_login('guest@inmobly.com', 'Test@gus1')

        api_response = self._download_json(
            'https://eu-gateway.inmobly.com/feed', series_id, query={'include_ids': series_id},
            headers={'Authorization': f'Bearer {self._USER_TOKEN}'})['items'][0]

        if not api_response.get('seasons'):
            return self._extract_video(api_response)

        return self.playlist_result(
            self._extract_series_seasons(api_response['seasons'], series_id),
            series_id, **traverse_obj(api_response, {
                'title': 'name',
                'description': 'description',
            }))