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

Code before:
        'only_matching': True,
    }, {
        'url': 'francetv:NI_983319@Info-web',
        'only_matching': True,
    }, {
        'url': 'francetv:NI_983319',
        'only_matching': True,
    }, {
        'url': 'francetv:NI_657393@Regions',
        'only_matching': True,
    }, {
        # france-3 live
        'url': 'francetv:SIM_France3',
        'only_matching': True,
    }]

    def _extract_video(self, video_id, catalogue=None):
        # Videos are identified by idDiffusion so catalogue part is optional.
        # However when provided, some extra formats may be returned so we pass
        # it if available.
        is_live = None
        videos = []
        title = None
        subtitle = None
        episode = None
        series = None
        image = None
        duration = None
        timestamp = None
        spritesheets = None

        for device_type in ('desktop', 'mobile'):
            dinfo = self._download_json(
                'https://player.webservices.francetelevisions.fr/v1/videos/%s' % video_id,
                video_id, 'Downloading %s video JSON' % device_type, query={
                    'device_type': device_type,
                    'browser': 'chrome',
                }, fatal=False)

            if not dinfo:
                continue

            print(dinfo)

            video = dinfo.get('video')
            if video:
                videos.append(video)
                if duration is None:
                    duration = video.get('duration')
                if is_live is None:
                    is_live = video.get('is_live')

Review comment (suggestion):
```suggestion
        season_number = None
        episode_number = None
```

Code after:
    }]

    def _extract_video(self, video_id, catalogue=None):
        # Videos are identified by idDiffusion so catalogue part is optional.
        # However when provided, some extra formats may be returned so we pass
        # it if available.
        is_live = None
        videos = []
        title = None
        subtitle = None
        episode_number = None
        season_number = None
        image = None
        duration = None
        timestamp = None
        spritesheets = None

        for device_type in ('desktop', 'mobile'):
            dinfo = self._download_json(
                'https://player.webservices.francetelevisions.fr/v1/videos/%s' % video_id,
                video_id, 'Downloading %s video JSON' % device_type, query={
                    'device_type': device_type,
                    'browser': 'chrome',
                }, fatal=False)

            if not dinfo:
                continue

            video = dinfo.get('video')
            if video:
                videos.append(video)
                if duration is None:
                    duration = video.get('duration')
                if is_live is None:
                    is_live = video.get('is_live')
                if spritesheets is None:
                    spritesheets = video.get('spritesheets')

            meta = dinfo.get('meta')
            if meta:
                if title is None:
                    title = meta.get('title')
                # meta['pre_title'] contains season and episode number for series in format "S<ID> E<ID>"
                season_number, episode_number = self._search_regex(
                    r'S(\d+)\s*E(\d+)', meta.get('pre_title'), 'episode info', group=(1, 2), default=(None, None))
                if subtitle is None:
                    subtitle = meta.get('additional_title')
                if image is None:
                    image = meta.get('image_url')
                if timestamp is None:
                    timestamp = parse_iso8601(meta.get('broadcasted_at'))