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

Code before:
            'view_count': int,
            'thumbnail': r're:^https?://.*\.(?:jpe?g|png)$',
            'duration': 549,
            'description': 'md5:116f326579700f00eaaf5581aae1192e',
            'upload_date': '20250304',
        },
    }, {
        'url': 'https://17.live/ja/vod/27323042/0de11bac-9bea-40b8-9eab-0239a7d88079',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_valid_url(url).group('video_id')
        json_data = self._download_json(f'https://wap-api.17app.co/api/v1/vods/{video_id}', video_id)
        return traverse_obj(json_data, {
            'id': ('vodID', {str_or_none}),
            'title': ('title', {str_or_none}),
            'formats': ('vodURL', {lambda x: self._extract_m3u8_formats(x, video_id)}),
            'uploader': ('userInfo', 'displayName', {str_or_none}),
            'uploader_id': ('userInfo', 'userID', {str_or_none}),
            'like_count': ('likeCount', {int_or_none}),
            'view_count': ('viewCount', {int_or_none}),
            'thumbnail': ('imageURL', {url_or_none}),
            'duration': ('duration', {int_or_none}),
            'description': ('description', {str_or_none}),
            'upload_date': ('createdAt', {strftime_or_none}),
        })


Review comment (refactor):
- `{str}` checks type while `{str_or_none}` is a transformation that will convert dicts, lists, etc to string. You should really only use `{str_or_none}` when you need to convert an int value to string (and ideally you would check that it's int, e.g. `'numeric_id', {int}, {str_or_none}`)

- `createdAt` is already a unix timestamp, so let's extract as `timestamp` instead of converting to `upload_date`

- I'm generally not a big fan of using the `_extract_*_formats` methods in traversal transformations (mostly because transformations are *always* called), but I guess it's fine here since it's both always necessary and always fatal

```suggestion
            'id': ('vodID', {str}),
            'title': ('title', {str}),
            'formats': ('vodURL', {lambda x: self._extract_m3u8_formats(x, video_id)}),
            'uploader': ('userInfo', 'displayName', {str}),
            'uploader_id': ('userInfo', 'userID', {str}),
            'like_count': ('likeCount', {int_or_none}),
            'view_count': ('viewCount', {int_or_none}),
            'thumbnail': ('imageURL', {url_or_none}),
            'duration': ('duration', {int_or_none}),
            'description': ('description', {str}),
            'timestamp': ('createdAt', {int_or_none}),
```

Code after:
            'like_count': int,
            'view_count': int,
            'thumbnail': r're:https?://.+/.+\.(?:jpe?g|png)',
            'duration': 549,
            'description': 'md5:116f326579700f00eaaf5581aae1192e',
            'timestamp': 1741058645,
            'upload_date': '20250304',
        },
    }, {
        'url': 'https://17.live/ja/vod/27323042/0de11bac-9bea-40b8-9eab-0239a7d88079',
        'only_matching': True,
    }]

    def _real_extract(self, url):
        video_id = self._match_id(url)
        json_data = self._download_json(f'https://wap-api.17app.co/api/v1/vods/{video_id}', video_id)

        return traverse_obj(json_data, {
            'id': ('vodID', {str}),
            'title': ('title', {str}),
            'formats': ('vodURL', {lambda x: self._extract_m3u8_formats(x, video_id)}),
            'uploader': ('userInfo', 'displayName', {str}),
            'uploader_id': ('userInfo', 'roomID', {int}, {str_or_none}),
            'channel': ('userInfo', 'name', {str}),
            'channel_id': ('userInfo', 'userID', {str}),
            'like_count': ('likeCount', {int_or_none}),
            'view_count': ('viewCount', {int_or_none}),
            'thumbnail': ('imageURL', {url_or_none}),
            'duration': ('duration', {int_or_none}),
            'description': ('description', {str}),
            'timestamp': ('createdAt', {int_or_none}),
        })