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

Code before:
    unified_strdate,
    urlencode_postdata,
)


class ADNBaseIE(InfoExtractor):
    IE_DESC = 'Animation Digital Network'
    _NETRC_MACHINE = 'animationdigitalnetwork'
    _BASE = 'animationdigitalnetwork.fr'
    _API_BASE_URL = 'https://gw.api.' + _BASE + '/'
    _PLAYER_BASE_URL = _API_BASE_URL + 'player/'
    _HEADERS = {}
    _LOGIN_ERR_MESSAGE = 'Unable to log in'
    _RSA_KEY = (0x9B42B08905199A5CCE2026274399CA560ECB209EE9878A708B1C0812E1BB8CB5D1FB7441861147C1A1F2F3A0476DD63A9CAC20D3E983613346850AA6CB38F16DC7D720FD7D86FC6E5B3D5BBC72E14CD0BF9E869F2CEA2CCAD648F1DCE38F1FF916CEFB2D339B64AA0264372344BC775E265E8A852F88144AB0BD9AA06C1A4ABB, 65537)
    _POS_ALIGN_MAP = {
        'start': 1,
        'end': 3,
    }
    _LINE_ALIGN_MAP = {
        'middle': 8,
        'end': 4,
    }


class ADNIE(ADNBaseIE):
    _VALID_URL = r'https?://(?:www\.)?(?:animation|anime)digitalnetwork\.(?P<lang>fr|de)/video/[^/]+/(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://animationdigitalnetwork.fr/video/fruits-basket/9841-episode-1-a-ce-soir',
        'md5': '1c9ef066ceb302c86f80c2b371615261',
        'info_dict': {
            'id': '9841',
            'ext': 'mp4',
            'title': 'Fruits Basket - Episode 1',
            'description': 'md5:14be2f72c3c96809b0ca424b0097d336',
            'series': 'Fruits Basket',
            'duration': 1437,
            'release_date': '20190405',
            'comment_count': int,
            'average_rating': float,
            'season_number': 1,
            'episode': 'À ce soir !',
            'episode_number': 1,
            'thumbnail': str,
            'season': 'Season 1',
        },
        'skip': 'Only available in French and German speaking Europe',
    }, {
        'url': 'http://animedigitalnetwork.fr/video/blue-exorcist-kyoto-saga/7778-episode-1-debut-des-hostilites',
        'only_matching': True,
    }, {
        'url': 'https://animationdigitalnetwork.de/video/the-eminence-in-shadow/23550-folge-1',

Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://(?:www\.)?(?:animation|anime)digitalnetwork\.(?P<lang>fr|de)/video/[^/?#]+/(?P<id>\d+)'
```

Code after:
    urlencode_postdata,
)
from ..utils.traversal import traverse_obj


class ADNBaseIE(InfoExtractor):
    IE_DESC = 'Animation Digital Network'
    _NETRC_MACHINE = 'animationdigitalnetwork'
    _BASE = 'animationdigitalnetwork.fr'
    _API_BASE_URL = f'https://gw.api.{_BASE}/'
    _PLAYER_BASE_URL = f'{_API_BASE_URL}player/'
    _HEADERS = {}
    _LOGIN_ERR_MESSAGE = 'Unable to log in'
    _RSA_KEY = (0x9B42B08905199A5CCE2026274399CA560ECB209EE9878A708B1C0812E1BB8CB5D1FB7441861147C1A1F2F3A0476DD63A9CAC20D3E983613346850AA6CB38F16DC7D720FD7D86FC6E5B3D5BBC72E14CD0BF9E869F2CEA2CCAD648F1DCE38F1FF916CEFB2D339B64AA0264372344BC775E265E8A852F88144AB0BD9AA06C1A4ABB, 65537)
    _POS_ALIGN_MAP = {
        'start': 1,
        'end': 3,
    }
    _LINE_ALIGN_MAP = {
        'middle': 8,
        'end': 4,
    }


class ADNIE(ADNBaseIE):
    _VALID_URL = r'https?://(?:www\.)?(?:animation|anime)digitalnetwork\.(?P<lang>fr|de)/video/[^/?#]+/(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://animationdigitalnetwork.fr/video/fruits-basket/9841-episode-1-a-ce-soir',
        'md5': '1c9ef066ceb302c86f80c2b371615261',
        'info_dict': {
            'id': '9841',
            'ext': 'mp4',
            'title': 'Fruits Basket - Episode 1',
            'description': 'md5:14be2f72c3c96809b0ca424b0097d336',
            'series': 'Fruits Basket',
            'duration': 1437,
            'release_date': '20190405',
            'comment_count': int,
            'average_rating': float,
            'season_number': 1,
            'episode': 'À ce soir !',
            'episode_number': 1,
            'thumbnail': str,
            'season': 'Season 1',
        },
        'skip': 'Only available in French and German speaking Europe',
    }, {
        'url': 'http://animedigitalnetwork.fr/video/blue-exorcist-kyoto-saga/7778-episode-1-debut-des-hostilites',
        'only_matching': True,
    }, {
        'url': 'https://animationdigitalnetwork.de/video/the-eminence-in-shadow/23550-folge-1',