1 from .common
import InfoExtractor
12 class AcFunVideoBaseIE(InfoExtractor
):
13 def _extract_metadata(self
, video_id
, video_info
):
14 playjson
= self
._parse
_json
(video_info
['ksPlayJson'], video_id
)
16 formats
, subtitles
= [], {}
17 for video
in traverse_obj(playjson
, ('adaptationSet', 0, 'representation')):
18 fmts
, subs
= self
._extract
_m
3u8_formats
_and
_subtitles
(video
['url'], video_id
, 'mp4', fatal
=False)
20 self
._merge
_subtitles
(subs
, target
=subtitles
)
23 'fps': float_or_none(video
.get('frameRate')),
24 'width': int_or_none(video
.get('width')),
25 'height': int_or_none(video
.get('height')),
26 'tbr': float_or_none(video
.get('avgBitrate')),
27 **parse_codecs(video
.get('codecs', ''))
33 'subtitles': subtitles
,
34 'duration': float_or_none(video_info
.get('durationMillis'), 1000),
35 'timestamp': int_or_none(video_info
.get('uploadTime'), 1000),
36 'http_headers': {'Referer': 'https://www.acfun.cn/'}
,
40 class AcFunVideoIE(AcFunVideoBaseIE
):
41 _VALID_URL
= r
'https?://www\.acfun\.cn/v/ac(?P<id>[_\d]+)'
44 'url': 'https://www.acfun.cn/v/ac35457073',
49 'timestamp': 1656403967,
51 'description': '“赶紧回去!班主任查班了!”',
53 'uploader_id': '51246077',
54 'thumbnail': r
're:^https?://.*\.(jpg|jpeg)',
55 'upload_date': '20220628',
62 # example for len(video_list) > 1
63 'url': 'https://www.acfun.cn/v/ac35468952_2',
67 'title': '【动画剧集】Rocket & Groot Season 1(2022)/火箭浣熊与格鲁特第1季 P02 S01E02 十拿九穩',
70 'uploader_id': '37259967',
71 'upload_date': '20220629',
72 'timestamp': 1656479962,
77 'thumbnail': r
're:^https?://.*\.(jpg|jpeg)',
78 'description': 'md5:67583aaf3a0f933bd606bc8a2d3ebb17',
82 def _real_extract(self
, url
):
83 video_id
= self
._match
_id
(url
)
85 webpage
= self
._download
_webpage
(url
, video_id
)
86 json_all
= self
._search
_json
(r
'window.videoInfo\s*=', webpage
, 'videoInfo', video_id
)
88 title
= json_all
.get('title')
89 video_list
= json_all
.get('videoList') or []
90 video_internal_id
= traverse_obj(json_all
, ('currentVideoInfo', 'id'))
91 if video_internal_id
and len(video_list
) > 1:
92 part_idx
, part_video_info
= next(
93 (idx
+ 1, v
) for (idx
, v
) in enumerate(video_list
)
94 if v
['id'] == video_internal_id
)
95 title
= f
'{title} P{part_idx:02d} {part_video_info["title"]}'
98 **self
._extract
_metadata
(video_id
, json_all
['currentVideoInfo']),
100 'thumbnail': json_all
.get('coverUrl'),
101 'description': json_all
.get('description'),
102 'uploader': traverse_obj(json_all
, ('user', 'name')),
103 'uploader_id': traverse_obj(json_all
, ('user', 'href')),
104 'tags': traverse_obj(json_all
, ('tagList', ..., 'name')),
105 'view_count': int_or_none(json_all
.get('viewCount')),
106 'like_count': int_or_none(json_all
.get('likeCountShow')),
107 'comment_count': int_or_none(json_all
.get('commentCountShow')),
111 class AcFunBangumiIE(AcFunVideoBaseIE
):
112 _VALID_URL
= r
'https?://www\.acfun\.cn/bangumi/(?P<id>aa[_\d]+)'
115 'url': 'https://www.acfun.cn/bangumi/aa6002917_36188_1745457?ac=2',
117 'id': 'aa6002917_36188_1745457__2',
119 'title': '【7月】租借女友 水原千鹤角色曲『DATE』特别PV',
120 'upload_date': '20200916',
121 'timestamp': 1600243813,
125 'url': 'https://www.acfun.cn/bangumi/aa5023171_36188_1750645',
127 'id': 'aa5023171_36188_1750645',
129 'title': '红孩儿之趴趴蛙寻石记 第5话 ',
131 'season': '红孩儿之趴趴蛙寻石记',
132 'season_id': 5023171,
133 'season_number': 1, # series has only 1 season
134 'episode': 'Episode 5',
136 'upload_date': '20181223',
137 'timestamp': 1545552185,
138 'thumbnail': r
're:^https?://.*\.(jpg|jpeg|png)',
139 'comment_count': int,
142 'url': 'https://www.acfun.cn/bangumi/aa6065485_36188_1885061',
144 'id': 'aa6065485_36188_1885061',
146 'title': '叽歪老表(第二季) 第5话 坚不可摧',
147 'season': '叽歪老表(第二季)',
149 'season_id': 6065485,
152 'upload_date': '20220324',
153 'timestamp': 1648082786,
155 'thumbnail': r
're:^https?://.*\.(jpg|jpeg|png)',
156 'comment_count': int,
160 def _real_extract(self
, url
):
161 video_id
= self
._match
_id
(url
)
162 ac_idx
= parse_qs(url
).get('ac', [None])[-1]
163 video_id
= f
'{video_id}{format_field(ac_idx, None, "__%s")}'
165 webpage
= self
._download
_webpage
(url
, video_id
)
166 json_bangumi_data
= self
._search
_json
(r
'window.bangumiData\s*=', webpage
, 'bangumiData', video_id
)
169 video_info
= json_bangumi_data
['hlVideoInfo']
171 **self
._extract
_metadata
(video_id
, video_info
),
172 'title': video_info
.get('title'),
175 video_info
= json_bangumi_data
['currentVideoInfo']
177 season_id
= json_bangumi_data
.get('bangumiId')
178 season_number
= season_id
and next((
179 idx
for idx
, v
in enumerate(json_bangumi_data
.get('relatedBangumis') or [], 1)
180 if v
.get('id') == season_id
), 1)
182 json_bangumi_list
= self
._search
_json
(
183 r
'window\.bangumiList\s*=', webpage
, 'bangumiList', video_id
, fatal
=False)
184 video_internal_id
= int_or_none(traverse_obj(json_bangumi_data
, ('currentVideoInfo', 'id')))
185 episode_number
= video_internal_id
and next((
186 idx
for idx
, v
in enumerate(json_bangumi_list
.get('items') or [], 1)
187 if v
.get('videoId') == video_internal_id
), None)
190 **self
._extract
_metadata
(video_id
, video_info
),
191 'title': json_bangumi_data
.get('showTitle'),
192 'thumbnail': json_bangumi_data
.get('image'),
193 'season': json_bangumi_data
.get('bangumiTitle'),
194 'season_id': season_id
,
195 'season_number': season_number
,
196 'episode': json_bangumi_data
.get('title'),
197 'episode_number': episode_number
,
198 'comment_count': int_or_none(json_bangumi_data
.get('commentCount')),