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

Code before:
            **traverse_obj(data, {
                'title': ('liveInfo', 'title', {str}),
                'comment_count': ('liveInfo', 'comments', {int_or_none}),
                'view_count': ('liveInfo', 'visitor', {int_or_none}),
                'timestamp': ('liveInfo', 'created', {int_or_none}),
                'uploader': ('broadcasterInfo', 'name', {str}),
            }),
            'formats': [{
                'format_id': 'hls',
                'url': data['liveInfo']['hls'],
                'ext': 'mp4',
                'protocol': 'm3u8',
            }],
            'is_live': True,
            '__post_extractor': self.extract_comments(video_id=video_id),
        }

    def _get_comments(self, video_id):
        yield from traverse_obj(self._download_json(
            f'https://mixch.tv/api-web/lives/{video_id}/messages', video_id,
            note='Downloading comments', errnote='Failed to download comments'), (..., {
                'author': ('name', {str_or_none}),
                'author_id': ('user_id', {int_or_none}),
                'id': ('message_id', {str_or_none}),
                'text': ('body', {str_or_none}),
                'timestamp': ('created', {int_or_none}),
            }))


class MixchArchiveIE(InfoExtractor):
    IE_NAME = 'mixch:archive'
    _VALID_URL = r'https?://(?:www\.)?mixch\.tv/archive/(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://mixch.tv/archive/421',
        'skip': 'paid video, no DRM. expires at Jan 23',
        'info_dict': {
            'id': '421',
            'ext': 'mp4',
            'title': '96NEKO SHOW TIME',
        }
    }, {
        'url': 'https://mixch.tv/archive/1213',
        'skip': 'paid video, no DRM. expires at Dec 31, 2023',
        'info_dict': {
            'id': '1213',
            'ext': 'mp4',
            'title': '【特別トーク番組アーカイブス】Merm4id×燐舞曲 2nd LIVE「VERSUS」',
            'release_date': '20231201',
            'thumbnail': str,
        }

Review comment (security):
* It is better to have `id=None` than `id=""`.
* `author_id` should be returned as as a `str`, not `int`.
* `{TYPE_or_none}` converts the data into `TYPE` while `{TYPE}` verifies the data is `TYPE` without converting

Considering these, I believe this is the proper impl:
```suggestion
                'author': ('name', {str}),
                'author_id': ('user_id', {str_or_none}),
                'id': ('message_id', {str}, {lambda x: x or None),
                'text': ('body', {str}),
                'timestamp': ('created', {int}),
```
Correct?

Code after:
            **traverse_obj(data, {
                'title': ('liveInfo', 'title', {str}),
                'comment_count': ('liveInfo', 'comments', {int_or_none}),
                'view_count': ('liveInfo', 'visitor', {int_or_none}),
                'timestamp': ('liveInfo', 'created', {int_or_none}),
                'uploader': ('broadcasterInfo', 'name', {str}),
            }),
            'formats': [{
                'format_id': 'hls',
                'url': data['liveInfo']['hls'],
                'ext': 'mp4',
                'protocol': 'm3u8',
            }],
            'is_live': True,
            '__post_extractor': self.extract_comments(video_id),
        }

    def _get_comments(self, video_id):
        yield from traverse_obj(self._download_json(
            f'https://mixch.tv/api-web/lives/{video_id}/messages', video_id,
            note='Downloading comments', errnote='Failed to download comments'), (..., {
                'author': ('name', {str}),
                'author_id': ('user_id', {str_or_none}),
                'id': ('message_id', {str}, {lambda x: x or None}),
                'text': ('body', {str}),
                'timestamp': ('created', {int}),
            }))


class MixchArchiveIE(InfoExtractor):
    IE_NAME = 'mixch:archive'
    _VALID_URL = r'https?://(?:www\.)?mixch\.tv/archive/(?P<id>\d+)'

    _TESTS = [{
        'url': 'https://mixch.tv/archive/421',
        'skip': 'paid video, no DRM. expires at Jan 23',
        'info_dict': {
            'id': '421',
            'ext': 'mp4',
            'title': '96NEKO SHOW TIME',
        }
    }, {
        'url': 'https://mixch.tv/archive/1213',
        'skip': 'paid video, no DRM. expires at Dec 31, 2023',
        'info_dict': {
            'id': '1213',
            'ext': 'mp4',
            'title': '【特別トーク番組アーカイブス】Merm4id×燐舞曲 2nd LIVE「VERSUS」',
            'release_date': '20231201',
            'thumbnail': str,
        }