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

Code before:
                formats.extend(m3u8_formats)

        video = (self._download_json(
            self._API_BASE_URL + 'video/%s' % video_id, video_id,
            'Downloading additional video metadata', fatal=False) or {}).get('video') or {}
        show = video.get('show') or {}

        return {
            'id': video_id,
            'title': title,
            'description': strip_or_none(metas.get('summary') or video.get('summary')),
            'thumbnail': video_info.get('image') or player.get('image'),
            'formats': formats,
            'subtitles': self.extract_subtitles(sub_url, video_id),
            'episode': metas.get('subtitle') or video.get('name'),
            'episode_number': int_or_none(video.get('shortNumber')),
            'series': show.get('title'),
            'season_number': int_or_none(video.get('season')),
            'duration': int_or_none(video_info.get('duration') or video.get('duration')),
            'release_date': unified_strdate(video.get('releaseDate')),
            'average_rating': float_or_none(video.get('rating') or metas.get('rating')),
            'comment_count': int_or_none(video.get('commentsCount')),
        }


class ADNSeasonIE(ADNIE):
    _VALID_URL = r'https?://(?:www\.)?(?:animation|anime)digitalnetwork\.(fr|de)/video/(?P<id>[^/]+)/?$'
    _TESTS = [{
        'url': 'https://animationdigitalnetwork.fr/video/tokyo-mew-mew-new',
        'playlist_count': 12,
        'info_dict': {
            'id': 911,
            'title': 'Tokyo Mew Mew New',
        },
        # 'skip': 'Only available in DE, AT, CH, LU, LI',
    }]

    def _real_extract(self, url):
        video_show_slug = self._match_id(url)
        video_base_url = self._API_BASE_URL + 'show/%s/' % video_show_slug
        print(video_base_url)
        show = self._download_json(
            video_base_url, video_show_slug,
            'Downloading show JSON metadata',
            headers=self._HEADERS)['show']
        show_id = show['id']
        lang = self._get_distribution_language(url)
        episodes = self._download_json(
            self._API_BASE_URL + 'video/show/%s' % show_id, video_show_slug,
            'Downloading episode list', headers={
                'X-Target-Distribution': lang,

Review comment (bug):
Subclassing from another concrete extractor invites so many unexpected bugs. Create a `ADNBaseIE` with common methods from which both can be derived

Code after:
                    m3u8_url, video_id, 'mp4', 'm3u8_native',
                    m3u8_id=format_id, fatal=False)
                if format_id == 'vf':
                    for f in m3u8_formats:
                        f['language'] = 'fr'
                elif format_id == 'vde':
                    for f in m3u8_formats:
                        f['language'] = 'de'
                formats.extend(m3u8_formats)

        video = (self._download_json(
            self._API_BASE_URL + 'video/%s' % video_id, video_id,
            'Downloading additional video metadata', fatal=False) or {}).get('video') or {}
        show = video.get('show') or {}

        return {
            'id': video_id,
            'title': title,
            'description': strip_or_none(metas.get('summary') or video.get('summary')),
            'thumbnail': video_info.get('image') or player.get('image'),
            'formats': formats,
            'subtitles': self.extract_subtitles(sub_url, video_id),
            'episode': metas.get('subtitle') or video.get('name'),
            'episode_number': int_or_none(video.get('shortNumber')),
            'series': show.get('title'),
            'season_number': int_or_none(video.get('season')),
            'duration': int_or_none(video_info.get('duration') or video.get('duration')),
            'release_date': unified_strdate(video.get('releaseDate')),
            'average_rating': float_or_none(video.get('rating') or metas.get('rating')),
            'comment_count': int_or_none(video.get('commentsCount')),
        }


class ADNSeasonIE(ADNBaseIE):
    _VALID_URL = r'https?://(?:www\.)?(?:animation|anime)digitalnetwork\.(?P<lang>fr|de)/video/(?P<id>[^/?#]+)/?(?:$|[#?])'
    _TESTS = [{
        'url': 'https://animationdigitalnetwork.fr/video/tokyo-mew-mew-new',
        'playlist_count': 12,
        'info_dict': {
            'id': '911',
            'title': 'Tokyo Mew Mew New',
        },
        # 'skip': 'Only available in French end German speaking Europe',
    }]

    def _real_extract(self, url):
        lang, video_show_slug = self._match_valid_url(url).group('lang', 'id')
        show = self._download_json(
            f'{self._API_BASE_URL}show/{video_show_slug}/', video_show_slug,
            'Downloading show JSON metadata', headers=self._HEADERS)['show']
        show_id = str(show['id'])