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

Code before:
import re

from .common import InfoExtractor
from ..utils import (
    float_or_none,
    int_or_none,
    traverse_obj,
)


class AcFunVideoIE(InfoExtractor):
    _VALID_URL = r'(?x)https?://(?:www\.acfun\.cn/v/)ac(?P<id>[_\d]+)'

    _TESTS = [{
        'url': 'https://www.acfun.cn/v/ac35457073',
        'info_dict': {
            'id': '35283657',
            'title': '【十五周年庆】文章区UP主祝AcFun生日快乐！',
            'duration': 455.21,
            'timestamp': 1655289827,
        },
        'params': {
            # m3u8 download
            'skip_download': True,
        },
        'skip': 'Geo-restricted to China',
    }]

    def parse_format(self, info, video_id):
        vcodec, acodec = None, None

        codec_str = info.get('codecs') or ''
        m = re.match('(?P<vc>[^,]+),(?P<ac>[^,]+)', codec_str)
        if m:
            vcodec = m.group("vc")
            acodec = m.group("ac")

        formats, _ = self._extract_m3u8_formats_and_subtitles(
            info['url'], video_id)

        # it seems AcFun do not have subtitles

        return {
            **formats[0],
            'fps': int_or_none(info.get('frameRate')),
            'width': int_or_none(info.get('width')),
            'height': int_or_none(info.get('height')),
            'vcodec': vcodec,
            'acodec': acodec,

Review comment (suggestion):
```suggestion
            'skip_download': 'm3u8',
```

Code after:
from .common import InfoExtractor
from ..utils import (
    float_or_none,
    format_field,
    int_or_none,
    traverse_obj,
    parse_codecs,
    parse_qs,
)


class AcFunVideoBaseIE(InfoExtractor):
    def _extract_metadata(self, video_id, video_info):
        playjson = self._parse_json(video_info['ksPlayJson'], video_id)

        formats, subtitles = [], {}
        for video in traverse_obj(playjson, ('adaptationSet', 0, 'representation')):
            fmts, subs = self._extract_m3u8_formats_and_subtitles(video['url'], video_id, 'mp4', fatal=False)
            formats.extend(fmts)
            self._merge_subtitles(subs, target=subtitles)
            for f in fmts:
                f.update({
                    'fps': float_or_none(video.get('frameRate')),
                    'width': int_or_none(video.get('width')),
                    'height': int_or_none(video.get('height')),
                    'tbr': float_or_none(video.get('avgBitrate')),
                    **parse_codecs(video.get('codecs', ''))
                })

        self._sort_formats(formats)
        return {
            'id': video_id,
            'formats': formats,
            'subtitles': subtitles,
            'duration': float_or_none(video_info.get('durationMillis'), 1000),
            'timestamp': int_or_none(video_info.get('uploadTime'), 1000),
            'http_headers': {'Referer': 'https://www.acfun.cn/'},
        }


class AcFunVideoIE(AcFunVideoBaseIE):
    _VALID_URL = r'https?://www\.acfun\.cn/v/ac(?P<id>[_\d]+)'

    _TESTS = [{
        'url': 'https://www.acfun.cn/v/ac35457073',
        'info_dict': {
            'id': '35457073',
            'ext': 'mp4',
            'duration': 174.208,