ronantakizawa/codereview-bench huggingface dataset:
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:

from .brightcove import BrightcoveNewIE
from .common import InfoExtractor


class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt/[\w\-/]+/detalhe/(?P<id>[\w\-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_PLAYER = 'chhIqzukMq'

Review comment (refactor):
```suggestion
from .brightcove import BrightcoveNewIE
from .common import InfoExtractor
```

Code after:
from .brightcove import BrightcoveNewIE
from .common import InfoExtractor


class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt(?:/[\w-]+)+/detalhe/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nowcanal.py (Python)

Code before:

from .brightcove import BrightcoveNewIE
from .common import InfoExtractor


class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt/[\w\-/]+/detalhe/(?P<id>[\w\-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_PLAYER = 'chhIqzukMq'
    _BC_ACCOUNT = '6108484330001'

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

Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt(?:/[\w-]+)+/detalhe/(?P<id>[\w-]+)'
```

Code after:
from .brightcove import BrightcoveNewIE
from .common import InfoExtractor


class NowCanalIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?nowcanal\.pt(?:/[\w-]+)+/detalhe/(?P<id>[\w-]+)'
    _TESTS = [{
        'url': 'https://www.nowcanal.pt/ultimas/detalhe/pedro-sousa-hjulmand-pode-ter-uma-saida-limpa-do-sporting-daqui-a-um-ano',
        'md5': '047f17cb783e66e467d703e704bbc95d',
        'info_dict': {
            'id': '6376598467112',
            'ext': 'mp4',
            'title': 'Pedro Sousa «Hjulmand pode ter uma saída limpa do Sporting daqui a um ano»',
            'description': '',
            'uploader_id': '6108484330001',
            'duration': 65.237,
            'thumbnail': r're:^https://.+\.jpg',
            'timestamp': 1754440620,
            'upload_date': '20250806',
            'tags': ['now'],
        },
    }, {
        'url': 'https://www.nowcanal.pt/programas/frente-a-frente/detalhe/frente-a-frente-eva-cruzeiro-ps-e-rita-matias-chega',
        'only_matching': True,
    }]

    _BC_URL_TMPL = 'https://players.brightcove.net/6108484330001/chhIqzukMq_default/index.html?videoId={}'

    def _real_extract(self, url):
        display_id = self._match_id(url)
        webpage = self._download_webpage(url, display_id)
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/idagio.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import traverse_obj, unified_timestamp


class IdagioTrackIE(InfoExtractor):
    """
    This extractor is only used internally to extract the info about tracks contained in every recording, album or
    playlist
    """
    _VALID_URL = r'https?://(?:www\.)?api\.idagio\.com/v2\.0/metadata/tracks/(?P<id>[0-9]+)'
    _TESTS = [{
        'url': 'https://api.idagio.com/v2.0/metadata/tracks/30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Variations on an Original Theme op. 36: Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Variations on an Original Theme op. 36: Theme. Andante',
            'track_id': '30576943',
            'timestamp': 1554474370029,
        },
    }, {
        'url': 'https://api.idagio.com/v2.0/metadata/tracks/20514478',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'Sonata for Piano No. 14 in C sharp minor op. 27/2: I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
            'artists': [],

Review comment (suggestion):
imo. we should not match the API URL, but the URL of the individual track (i.e. `https://app.idagio.com/recordings/30576934?trackId=30576943`)

Code after:
from .common import InfoExtractor
from ..utils import int_or_none, unified_timestamp, url_or_none
from ..utils.traversal import traverse_obj


class IdagioTrackIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Theme. Andante',
            'timestamp': 1554474370,
            'upload_date': '20190405',
        },
    }, {
        'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
            'artists': [],
            'genres': ['Keyboard', 'Sonata (Keyboard)'],
            'track': 'I. Adagio sostenuto',
            'timestamp': 1518076337,
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/idagio.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import int_or_none, traverse_obj, unified_timestamp, url_or_none


class IdagioTrackIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/[0-9]+\?trackId=(?P<id>[0-9]+)(&[a-zA-Z0-9_-]+=[a-zA-Z0-9_-]+)*'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Theme. Andante',
            'timestamp': 1554474370,
            'upload_date': '20190405',
        },
    }, {
        'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
            'artists': [],

Review comment (suggestion):
No need to match the trailing part, also should support the trackId not being the first query paramter
```suggestion
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
```

Code after:
from .common import InfoExtractor
from ..utils import int_or_none, unified_timestamp, url_or_none
from ..utils.traversal import traverse_obj


class IdagioTrackIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Theme. Andante',
            'timestamp': 1554474370,
            'upload_date': '20190405',
        },
    }, {
        'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/idagio.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import int_or_none, unified_timestamp, url_or_none
from ..utils.traversal import traverse_obj


class IdagioTrackIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com(?:/[a-z]+)?/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Theme. Andante',
            'timestamp': 1554474370,
            'upload_date': '20190405',
        },
    }, {
        'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
            'genres': ['Keyboard', 'Sonata (Keyboard)'],

Review comment (suggestion):
```suggestion
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com(?:/[a-z]{2})?/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
```

Code after:
from .common import InfoExtractor
from ..utils import int_or_none, unified_timestamp, url_or_none
from ..utils.traversal import traverse_obj


class IdagioTrackIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?app\.idagio\.com(?:/[a-z]{2})?/recordings/\d+\?(?:[^#]+&)?trackId=(?P<id>\d+)'
    _TESTS = [{
        'url': 'https://app.idagio.com/recordings/30576934?trackId=30576943',
        'md5': '15148bd71804b2450a2508931a116b56',
        'info_dict': {
            'id': '30576943',
            'ext': 'mp3',
            'title': 'Theme. Andante',
            'duration': 82,
            'composers': ['Edward Elgar'],
            'artists': ['Vasily Petrenko', 'Royal Liverpool Philharmonic Orchestra'],
            'genres': ['Orchestral', 'Other Orchestral Music'],
            'track': 'Theme. Andante',
            'timestamp': 1554474370,
            'upload_date': '20190405',
        },
    }, {
        'url': 'https://app.idagio.com/recordings/20514467?trackId=20514478&utm_source=pcl',
        'md5': '3acef2ea0feadf889123b70e5a1e7fa7',
        'info_dict': {
            'id': '20514478',
            'ext': 'mp3',
            'title': 'I. Adagio sostenuto',
            'duration': 316,
            'composers': ['Ludwig van Beethoven'],
            'genres': ['Keyboard', 'Sonata (Keyboard)'],
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/dplay.py (Python)

Code before:
import json
import uuid

from .common import InfoExtractor
from ..networking.exceptions import HTTPError
from ..utils import (
    ExtractorError,
    determine_ext,
    float_or_none,
    int_or_none,
    remove_start,
    strip_or_none,
    traverse_obj,
    try_get,
    unified_timestamp,
)


class DPlayBaseIE(InfoExtractor):
    _PATH_REGEX = r'/(?P<id>[^/]+/[^/?#]+)'
    _auth_token_cache = {}

    def _get_auth(self, disco_base, display_id, realm, needs_device_id=True):
        key = (disco_base, realm)
        st = self._get_cookies(disco_base).get('st')
        token = (st and st.value) or self._auth_token_cache.get(key)

        if not token:
            query = {'realm': realm}
            if needs_device_id:
                query['deviceId'] = uuid.uuid4().hex
            token = self._download_json(
                disco_base + 'token', display_id, 'Downloading token',
                query=query)['data']['attributes']['token']

            # Save cache only if cookies are not being set
            if not self._get_cookies(disco_base).get('st'):
                self._auth_token_cache[key] = token

        return f'Bearer {token}'


Review comment (suggestion):
```suggestion
    try_get,
    unified_timestamp,
)
from ..utils.traversal import traverse_obj
```

Code after:
import json
import uuid

from .common import InfoExtractor
from ..networking.exceptions import HTTPError
from ..utils import (
    ExtractorError,
    determine_ext,
    float_or_none,
    int_or_none,
    remove_start,
    strip_or_none,
    try_get,
    unified_timestamp,
)
from ..utils.traversal import traverse_obj


class DPlayBaseIE(InfoExtractor):
    _PATH_REGEX = r'/(?P<id>[^/]+/[^/?#]+)'
    _auth_token_cache = {}

    def _get_auth(self, disco_base, display_id, realm, needs_device_id=True):
        key = (disco_base, realm)
        st = self._get_cookies(disco_base).get('st')
        token = (st and st.value) or self._auth_token_cache.get(key)

        if not token:
            query = {'realm': realm}
            if needs_device_id:
                query['deviceId'] = uuid.uuid4().hex
            token = self._download_json(
                disco_base + 'token', display_id, 'Downloading token',
                query=query)['data']['attributes']['token']

            # Save cache only if cookies are not being set
            if not self._get_cookies(disco_base).get('st'):
                self._auth_token_cache[key] = token

        return f'Bearer {token}'
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nascar.py (Python)

Code before:
            'timestamp': 1501995600,
            'upload_date': '20170806',
            'tags': ['watkins glen', 'race #22', '2017', 'martin truex jr.', 'cup'],
            'chapters': 'count:13',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        content_data = self._search_nextjs_data(
            webpage, video_id)['props']['pageProps']['contentData']

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(content_data['input']['src'], video_id),
            **traverse_obj(content_data, {
                'title': ('input', 'name', {str}),
                'description': ('input', 'description', {str}),
                'thumbnail': ('input', 'thumbnail', {url_or_none}),
                'tags': ('input', 'settings', 'tags', ..., {str}),
                'timestamp': ('input', 'start_time', {parse_iso8601}),
                'chapters': ('overlay', 'data', 'timelines', 0, 'events', ..., {
                    'start_time': ('timestamp', {float_or_none}),
                    'title': ('name', {str}),
                }),
            }),
        }


Review comment (suggestion):
```suggestion
                'chapters': ('overlay', 'data', 'timelines', 0, 'events', lambda _, v: float(v['timestamp']) is not None, {
                    'start_time': ('timestamp', {float_or_none}),
                    'title': ('name', {str}),
                }),
```

Code after:
            'ext': 'mp4',
            'title': 'I Love New York 355 at the Glen 2017',
            'thumbnail': 'https://va.aws.nascar.com/IMAGES/CUP_2017_22_WATKINSGLEN_THUMB_NCD.jpg',
            'timestamp': 1501995600,
            'upload_date': '20170806',
            'tags': ['watkins glen', 'race #22', '2017', 'martin truex jr.', 'cup'],
            'chapters': 'count:13',
        },
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        webpage = self._download_webpage(url, video_id)
        content_data = self._search_nextjs_data(
            webpage, video_id)['props']['pageProps']['contentData']

        return {
            'id': video_id,
            'formats': self._extract_m3u8_formats(content_data['input']['src'], video_id, 'mp4'),
            **traverse_obj(content_data, {
                'title': ('input', 'name', {str}),
                'description': ('input', 'description', {str}, filter),
                'thumbnail': ('input', 'thumbnail', {url_or_none}),
                'tags': ('input', 'settings', 'tags', ..., {str}),
                'timestamp': ('input', 'start_time', {parse_iso8601}),
                'chapters': ('overlay', 'data', 'timelines', 0, 'events', lambda _, v: float(v['timestamp']) is not None, {
                    'start_time': ('timestamp', {float_or_none}),
                    'title': ('name', {str}),
                }),
            }),
        }
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/nascar.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import float_or_none, parse_iso8601, traverse_obj, url_or_none


class NascarClassicsIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?classics\.nascar\.com/video/(?P<id>[\w~-]+)'
    _TESTS = [{
        'url': 'https://classics.nascar.com/video/Ka5qGuxzZ~SIvJii7uAC~wszPshklHN',
        'md5': '81d712eccffa7169c328281b8cc28f77',
        'info_dict': {
            'id': 'Ka5qGuxzZ~SIvJii7uAC~wszPshklHN',
            'ext': 'mp4',
            'title': 'Cook Out 400 2023',
            'thumbnail': 'https://va.aws.nascar.com/IMAGES/CUP_2023_22_RICHMOND_THUMB_NCD.jpg',
            'description': '',
            'timestamp': 1690732800,
            'upload_date': '20230730',
            'tags': ['2023', 'race #22', 'richmond', 'chris buescher', 'cup'],
            'chapters': 'count:18',
        },
    }, {
        'url': 'https://classics.nascar.com/video/UASvPDOwEha~SIvJii7uAC~wszPshklHN',
        'md5': 'a5e8d6ec6005da3857d25ba2df5e7133',
        'info_dict': {
            'id': 'UASvPDOwEha~SIvJii7uAC~wszPshklHN',
            'ext': 'mp4',
            'title': 'I Love New York 355 at the Glen 2017',

Review comment (suggestion):
```suggestion
from ..utils import (
    float_or_none,
    parse_iso8601,
    url_or_none,
)
from ..utils.traversal import traverse_obj
```

Code after:
from .common import InfoExtractor
from ..utils import (
    float_or_none,
    parse_iso8601,
    url_or_none,
)
from ..utils.traversal import traverse_obj


class NascarClassicsIE(InfoExtractor):
    _VALID_URL = r'https?://(?:www\.)?classics\.nascar\.com/video/(?P<id>[\w~-]+)'
    _TESTS = [{
        'url': 'https://classics.nascar.com/video/Ka5qGuxzZ~SIvJii7uAC~wszPshklHN',
        'md5': '81d712eccffa7169c328281b8cc28f77',
        'info_dict': {
            'id': 'Ka5qGuxzZ~SIvJii7uAC~wszPshklHN',
            'ext': 'mp4',
            'title': 'Cook Out 400 2023',
            'thumbnail': 'https://va.aws.nascar.com/IMAGES/CUP_2023_22_RICHMOND_THUMB_NCD.jpg',
            'timestamp': 1690732800,
            'upload_date': '20230730',
            'tags': ['2023', 'race #22', 'richmond', 'chris buescher', 'cup'],
            'chapters': 'count:18',
        },
    }, {
        'url': 'https://classics.nascar.com/video/UASvPDOwEha~SIvJii7uAC~wszPshklHN',
        'md5': 'a5e8d6ec6005da3857d25ba2df5e7133',
Repository: yt-dlp/yt-dlp
File: yt_dlp/extractor/digiteka.py (Python)

Code before:
from .common import InfoExtractor
from ..utils import int_or_none, traverse_obj, url_or_none


class DigitekaIE(InfoExtractor):
    _VALID_URL = r'''(?x)
        https?://(?:www\.)?(?:digiteka\.net|ultimedia\.com)/
        (?:
            deliver/
            (?P<embed_type>
                generic|
                musique
            )
            (?:/[^/]+)*/
            (?:
                src|
                article
            )|
            default/index/video
            (?P<site_type>
                generic|
                music
            )
            /id
        )/(?P<id>[\d+a-z]+)'''
    _EMBED_REGEX = [r'<(?:iframe|script)[^>]+src=["\'](?P<url>(?:https?:)?//(?:www\.)?ultimedia\.com/deliver/(?:generic|musique)(?:/[^/]+)*/(?:src|article)/[\d+a-z]+)']
    _TESTS = [{

Review comment (suggestion):
```suggestion
from ..utils import int_or_none, url_or_none
from ..utils.traversal import traverse_obj
```

Code after:
from .common import InfoExtractor
from ..utils import int_or_none, url_or_none
from ..utils.traversal import traverse_obj


class DigitekaIE(InfoExtractor):
    _VALID_URL = r'''(?x)
        https?://(?:www\.)?(?:digiteka\.net|ultimedia\.com)/
        (?:
            deliver/
            (?P<embed_type>
                generic|
                musique
            )
            (?:/[^/]+)*/
            (?:
                src|
                article
            )|
            default/index/video
            (?P<site_type>
                generic|
                music
            )
            /id
        )/(?P<id>[\d+a-z]+)'''
    _EMBED_REGEX = [r'<(?:iframe|script)[^>]+src=["\'](?P<url>(?:https?:)?//(?:www\.)?ultimedia\.com/deliver/(?:generic|musique)(?:/[^/]+)*/(?:src|article)/[\d+a-z]+)']