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

Code before:
                'vcodec': 'none',
                'ext': 'mhtml',
                'protocol': 'mhtml',
                'url': 'about:invalid',
                'fragments': [{
                    'url': sheet,
                    # XXX: not entirely accurate; each spritesheet seems to be
                    # a 10×10 grid of thumbnails corresponding to approximately
                    # 2 seconds of the video; the last spritesheet may be shorter
                    'duration': 200,
                } for sheet in spritesheets]
            })

        return {
            'id': video_id,
            'title': (title + ' - %s' % subtitle if subtitle else title).strip(),
            'thumbnail': image,
            'duration': duration,
            'timestamp': timestamp,
            'is_live': is_live,
            'formats': formats,
            'subtitles': subtitles,
            'episode': subtitle if episode_number else None,
            'series': title if episode_number else None,
            'episode_number': int(episode_number) if episode_number else None,
            'season_number': int(season_number) if season_number else None,
        }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        video_id = mobj.group('id')
        catalog = mobj.group('catalog')

        if not video_id:
            qs = parse_qs(url)
            video_id = qs.get('idDiffusion', [None])[0]
            catalog = qs.get('catalogue', [None])[0]
            if not video_id:
                raise ExtractorError('Invalid URL', expected=True)

        return self._extract_video(video_id, catalog)


class FranceTVSiteIE(FranceTVBaseInfoExtractor):
    _VALID_URL = r'https?://(?:(?:www\.)?france\.tv|mobile\.france\.tv)/(?:[^/]+/)*(?P<id>[^/]+)\.html'

    _TESTS = [{
        'url': 'https://www.france.tv/france-2/13h15-le-dimanche/140921-les-mysteres-de-jesus.html',
        'info_dict': {
            'id': 'ec217ecc-0733-48cf-ac06-af1347b849d1',
            'ext': 'mp4',

Review comment (suggestion):
```suggestion
            'episode_number': int_or_none(episode_number),
            'season_number': int_or_none(season_number),
```
Import `int_or_none` from `..utils`

Code after:
            'thumbnail': image,
            'duration': duration,
            'timestamp': timestamp,
            'is_live': is_live,
            'formats': formats,
            'subtitles': subtitles,
            'episode': subtitle if episode_number else None,
            'series': title if episode_number else None,
            'episode_number': int_or_none(episode_number),
            'season_number': int_or_none(season_number),
        }

    def _real_extract(self, url):
        mobj = self._match_valid_url(url)
        video_id = mobj.group('id')
        catalog = mobj.group('catalog')

        if not video_id:
            qs = parse_qs(url)
            video_id = qs.get('idDiffusion', [None])[0]
            catalog = qs.get('catalogue', [None])[0]
            if not video_id:
                raise ExtractorError('Invalid URL', expected=True)

        return self._extract_video(video_id, catalog)


class FranceTVSiteIE(FranceTVBaseInfoExtractor):
    _VALID_URL = r'https?://(?:(?:www\.)?france\.tv|mobile\.france\.tv)/(?:[^/]+/)*(?P<id>[^/]+)\.html'

    _TESTS = [{
        'url': 'https://www.france.tv/france-2/13h15-le-dimanche/140921-les-mysteres-de-jesus.html',
        'info_dict': {
            'id': 'ec217ecc-0733-48cf-ac06-af1347b849d1',
            'ext': 'mp4',
            'title': '13h15, le dimanche... - Les mystères de Jésus',
            'timestamp': 1502623500,
            'duration': 2580,
            'thumbnail': r're:^https?://.*\.jpg$',
            'upload_date': '20170813',
        },
        'params': {
            'skip_download': True,
        },
        'add_ie': [FranceTVIE.ie_key()],
    }, {
        'url': 'https://www.france.tv/enfants/six-huit-ans/foot2rue/saison-1/3066387-duel-au-vieux-port.html',
        'info_dict': {
            'id': 'a9050959-eedd-4b4a-9b0d-de6eeaa73e44',
            'ext': 'mp4',
            'title': 'Foot2Rue - Duel au vieux port',