| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | # coding: utf-8 | 
					
						
							|  |  |  |  | from __future__ import unicode_literals | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  | import hashlib | 
					
						
							| 
									
										
										
										
											2015-10-17 23:12:58 +01:00
										 |  |  |  | import re | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | from .common import InfoExtractor | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  | from ..compat import ( | 
					
						
							|  |  |  |  |     compat_parse_qs, | 
					
						
							|  |  |  |  |     compat_urlparse, | 
					
						
							|  |  |  |  | ) | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | from ..utils import ( | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     ExtractorError, | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |     int_or_none, | 
					
						
							|  |  |  |  |     float_or_none, | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     parse_iso8601, | 
					
						
							|  |  |  |  |     smuggle_url, | 
					
						
							|  |  |  |  |     strip_jsonp, | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  |     unified_timestamp, | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     unsmuggle_url, | 
					
						
							| 
									
										
										
										
											2016-09-05 13:53:58 +08:00
										 |  |  |  |     urlencode_postdata, | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | ) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class BiliBiliIE(InfoExtractor): | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     _VALID_URL = r'https?://(?:www\.|bangumi\.|)bilibili\.(?:tv|com)/(?:video/av|anime/(?P<anime_id>\d+)/play#)(?P<id>\d+)' | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     _TESTS = [{ | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |         'url': 'http://www.bilibili.tv/video/av1074402/', | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |         'md5': '5f7d29e1a2872f3df0cf76b1f87d3788', | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |         'info_dict': { | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  |             'id': '1074402', | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             'ext': 'flv', | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |             'title': '【金坷垃】金泡沫', | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             'description': 'md5:ce18c2a2d2193f0df2917d270f2e5923', | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             'duration': 308.067, | 
					
						
							|  |  |  |  |             'timestamp': 1398012678, | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |             'upload_date': '20140420', | 
					
						
							| 
									
										
										
										
											2017-01-02 20:08:07 +08:00
										 |  |  |  |             'thumbnail': r're:^https?://.+\.jpg', | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |             'uploader': '菊子桑', | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             'uploader_id': '156160', | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     }, { | 
					
						
							|  |  |  |  |         # Tested in BiliBiliBangumiIE | 
					
						
							|  |  |  |  |         'url': 'http://bangumi.bilibili.com/anime/1869/play#40062', | 
					
						
							|  |  |  |  |         'only_matching': True, | 
					
						
							|  |  |  |  |     }, { | 
					
						
							|  |  |  |  |         'url': 'http://bangumi.bilibili.com/anime/5802/play#100643', | 
					
						
							|  |  |  |  |         'md5': '3f721ad1e75030cc06faf73587cfec57', | 
					
						
							|  |  |  |  |         'info_dict': { | 
					
						
							|  |  |  |  |             'id': '100643', | 
					
						
							|  |  |  |  |             'ext': 'mp4', | 
					
						
							|  |  |  |  |             'title': 'CHAOS;CHILD', | 
					
						
							|  |  |  |  |             'description': '如果你是神明,并且能够让妄想成为现实。那你会进行怎么样的妄想?是淫靡的世界?独裁社会?毁灭性的制裁?还是……2015年,涩谷。从6年前发生的大灾害“涩谷地震”之后复兴了的这个街区里新设立的私立高中...', | 
					
						
							|  |  |  |  |         }, | 
					
						
							|  |  |  |  |         'skip': 'Geo-restricted to China', | 
					
						
							| 
									
										
										
										
											2017-06-15 11:19:03 +08:00
										 |  |  |  |     }, { | 
					
						
							|  |  |  |  |         # Title with double quotes | 
					
						
							|  |  |  |  |         'url': 'http://www.bilibili.com/video/av8903802/', | 
					
						
							|  |  |  |  |         'info_dict': { | 
					
						
							|  |  |  |  |             'id': '8903802', | 
					
						
							|  |  |  |  |             'title': '阿滴英文|英文歌分享#6 "Closer', | 
					
						
							|  |  |  |  |             'description': '滴妹今天唱Closer給你聽! 有史以来,被推最多次也是最久的歌曲,其实歌词跟我原本想像差蛮多的,不过还是好听! 微博@阿滴英文', | 
					
						
							|  |  |  |  |         }, | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |         'playlist': [{ | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '8903802_part1', | 
					
						
							|  |  |  |  |                 'ext': 'flv', | 
					
						
							|  |  |  |  |                 'title': '阿滴英文|英文歌分享#6 "Closer', | 
					
						
							|  |  |  |  |                 'description': 'md5:3b1b9e25b78da4ef87e9b548b88ee76a', | 
					
						
							|  |  |  |  |                 'uploader': '阿滴英文', | 
					
						
							|  |  |  |  |                 'uploader_id': '65880958', | 
					
						
							|  |  |  |  |                 'timestamp': 1488382634, | 
					
						
							|  |  |  |  |                 'upload_date': '20170301', | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |             'params': { | 
					
						
							|  |  |  |  |                 'skip_download': True,  # Test metadata only | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |         }, { | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '8903802_part2', | 
					
						
							|  |  |  |  |                 'ext': 'flv', | 
					
						
							|  |  |  |  |                 'title': '阿滴英文|英文歌分享#6 "Closer', | 
					
						
							|  |  |  |  |                 'description': 'md5:3b1b9e25b78da4ef87e9b548b88ee76a', | 
					
						
							|  |  |  |  |                 'uploader': '阿滴英文', | 
					
						
							|  |  |  |  |                 'uploader_id': '65880958', | 
					
						
							|  |  |  |  |                 'timestamp': 1488382634, | 
					
						
							|  |  |  |  |                 'upload_date': '20170301', | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |             'params': { | 
					
						
							|  |  |  |  |                 'skip_download': True,  # Test metadata only | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |         }] | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     }] | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-02-17 05:00:16 +07:00
										 |  |  |  |     _APP_KEY = 'iVGUTjsxvpLeuDCf' | 
					
						
							|  |  |  |  |     _BILIBILI_KEY = 'aHRmhWMLkdeMuILqORnYZocwMBpMEOdt' | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |     def _report_error(self, result): | 
					
						
							|  |  |  |  |         if 'message' in result: | 
					
						
							|  |  |  |  |             raise ExtractorError('%s said: %s' % (self.IE_NAME, result['message']), expected=True) | 
					
						
							|  |  |  |  |         elif 'code' in result: | 
					
						
							|  |  |  |  |             raise ExtractorError('%s returns error %d' % (self.IE_NAME, result['code']), expected=True) | 
					
						
							|  |  |  |  |         else: | 
					
						
							|  |  |  |  |             raise ExtractorError('Can\'t extract Bangumi episode ID') | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-17 23:12:58 +01:00
										 |  |  |  |     def _real_extract(self, url): | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |         url, smuggled_data = unsmuggle_url(url, {}) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         mobj = re.match(self._VALID_URL, url) | 
					
						
							|  |  |  |  |         video_id = mobj.group('id') | 
					
						
							|  |  |  |  |         anime_id = mobj.group('anime_id') | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |         webpage = self._download_webpage(url, video_id) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |         if 'anime/' not in url: | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             cid = self._search_regex( | 
					
						
							| 
									
										
										
										
											2018-06-14 22:40:30 +07:00
										 |  |  |  |                 r'\bcid(?:["\']:|=)(\d+)', webpage, 'cid', | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |                 default=None | 
					
						
							|  |  |  |  |             ) or compat_parse_qs(self._search_regex( | 
					
						
							| 
									
										
										
										
											2018-04-01 02:06:14 +07:00
										 |  |  |  |                 [r'EmbedPlayer\([^)]+,\s*"([^"]+)"\)', | 
					
						
							|  |  |  |  |                  r'EmbedPlayer\([^)]+,\s*\\"([^"]+)\\"\)', | 
					
						
							|  |  |  |  |                  r'<iframe[^>]+src="https://secure\.bilibili\.com/secure,([^"]+)"'], | 
					
						
							| 
									
										
										
										
											2016-07-29 23:21:50 +08:00
										 |  |  |  |                 webpage, 'player parameters'))['cid'][0] | 
					
						
							|  |  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |             if 'no_bangumi_tip' not in smuggled_data: | 
					
						
							|  |  |  |  |                 self.to_screen('Downloading episode %s. To download all videos in anime %s, re-run youtube-dl with %s' % ( | 
					
						
							|  |  |  |  |                     video_id, anime_id, compat_urlparse.urljoin(url, '//bangumi.bilibili.com/anime/%s' % anime_id))) | 
					
						
							|  |  |  |  |             headers = { | 
					
						
							|  |  |  |  |                 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', | 
					
						
							| 
									
										
										
										
											2018-01-06 20:27:26 +01:00
										 |  |  |  |                 'Referer': url | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |             } | 
					
						
							|  |  |  |  |             headers.update(self.geo_verification_headers()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-09-05 13:53:58 +08:00
										 |  |  |  |             js = self._download_json( | 
					
						
							|  |  |  |  |                 'http://bangumi.bilibili.com/web_api/get_source', video_id, | 
					
						
							|  |  |  |  |                 data=urlencode_postdata({'episode_id': video_id}), | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  |                 headers=headers) | 
					
						
							|  |  |  |  |             if 'result' not in js: | 
					
						
							|  |  |  |  |                 self._report_error(js) | 
					
						
							| 
									
										
										
										
											2016-07-29 23:21:50 +08:00
										 |  |  |  |             cid = js['result']['cid'] | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-06 20:27:26 +01:00
										 |  |  |  |         headers = { | 
					
						
							|  |  |  |  |             'Referer': url | 
					
						
							|  |  |  |  |         } | 
					
						
							|  |  |  |  |         headers.update(self.geo_verification_headers()) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |         entries = [] | 
					
						
							| 
									
										
										
										
											2015-04-30 18:23:35 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |         RENDITIONS = ('qn=80&quality=80&type=', 'quality=2&type=mp4') | 
					
						
							|  |  |  |  |         for num, rendition in enumerate(RENDITIONS, start=1): | 
					
						
							|  |  |  |  |             payload = 'appkey=%s&cid=%s&otype=json&%s' % (self._APP_KEY, cid, rendition) | 
					
						
							|  |  |  |  |             sign = hashlib.md5((payload + self._BILIBILI_KEY).encode('utf-8')).hexdigest() | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             video_info = self._download_json( | 
					
						
							| 
									
										
										
										
											2018-03-16 03:18:53 +07:00
										 |  |  |  |                 'http://interface.bilibili.com/v2/playurl?%s&sign=%s' % (payload, sign), | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |                 video_id, note='Downloading video info page', | 
					
						
							|  |  |  |  |                 headers=headers, fatal=num == len(RENDITIONS)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if not video_info: | 
					
						
							|  |  |  |  |                 continue | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             if 'durl' not in video_info: | 
					
						
							|  |  |  |  |                 if num < len(RENDITIONS): | 
					
						
							|  |  |  |  |                     continue | 
					
						
							|  |  |  |  |                 self._report_error(video_info) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |             for idx, durl in enumerate(video_info['durl']): | 
					
						
							|  |  |  |  |                 formats = [{ | 
					
						
							|  |  |  |  |                     'url': durl['url'], | 
					
						
							|  |  |  |  |                     'filesize': int_or_none(durl['size']), | 
					
						
							|  |  |  |  |                 }] | 
					
						
							|  |  |  |  |                 for backup_url in durl.get('backup_url', []): | 
					
						
							|  |  |  |  |                     formats.append({ | 
					
						
							|  |  |  |  |                         'url': backup_url, | 
					
						
							|  |  |  |  |                         # backup URLs have lower priorities | 
					
						
							|  |  |  |  |                         'preference': -2 if 'hd.mp4' in backup_url else -3, | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 for a_format in formats: | 
					
						
							|  |  |  |  |                     a_format.setdefault('http_headers', {}).update({ | 
					
						
							|  |  |  |  |                         'Referer': url, | 
					
						
							|  |  |  |  |                     }) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 self._sort_formats(formats) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |                 entries.append({ | 
					
						
							|  |  |  |  |                     'id': '%s_part%s' % (video_id, idx), | 
					
						
							|  |  |  |  |                     'duration': float_or_none(durl.get('length'), 1000), | 
					
						
							|  |  |  |  |                     'formats': formats, | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |                 }) | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             break | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |         title = self._html_search_regex( | 
					
						
							|  |  |  |  |             ('<h1[^>]+\btitle=(["\'])(?P<title>(?:(?!\1).)+)\1', | 
					
						
							|  |  |  |  |              '(?s)<h1[^>]*>(?P<title>.+?)</h1>'), webpage, 'title', | 
					
						
							|  |  |  |  |             group='title') | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |         description = self._html_search_meta('description', webpage) | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  |         timestamp = unified_timestamp(self._html_search_regex( | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             r'<time[^>]+datetime="([^"]+)"', webpage, 'upload time', | 
					
						
							|  |  |  |  |             default=None) or self._html_search_meta( | 
					
						
							|  |  |  |  |             'uploadDate', webpage, 'timestamp', default=None)) | 
					
						
							| 
									
										
										
										
											2016-09-05 13:53:58 +08:00
										 |  |  |  |         thumbnail = self._html_search_meta(['og:image', 'thumbnailUrl'], webpage) | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         # TODO 'view_count' requires deobfuscating Javascript | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |         info = { | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  |             'id': video_id, | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |             'title': title, | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             'description': description, | 
					
						
							|  |  |  |  |             'timestamp': timestamp, | 
					
						
							| 
									
										
										
										
											2016-07-29 23:21:50 +08:00
										 |  |  |  |             'thumbnail': thumbnail, | 
					
						
							| 
									
										
										
										
											2016-08-28 22:06:31 +08:00
										 |  |  |  |             'duration': float_or_none(video_info.get('timelength'), scale=1000), | 
					
						
							| 
									
										
										
										
											2014-04-21 13:45:27 +02:00
										 |  |  |  |         } | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |         uploader_mobj = re.search( | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |             r'<a[^>]+href="(?:https?:)?//space\.bilibili\.com/(?P<id>\d+)"[^>]*>(?P<name>[^<]+)', | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             webpage) | 
					
						
							|  |  |  |  |         if uploader_mobj: | 
					
						
							|  |  |  |  |             info.update({ | 
					
						
							|  |  |  |  |                 'uploader': uploader_mobj.group('name'), | 
					
						
							|  |  |  |  |                 'uploader_id': uploader_mobj.group('id'), | 
					
						
							|  |  |  |  |             }) | 
					
						
							| 
									
										
										
										
											2018-03-16 00:19:17 +07:00
										 |  |  |  |         if not info.get('uploader'): | 
					
						
							|  |  |  |  |             info['uploader'] = self._html_search_meta( | 
					
						
							|  |  |  |  |                 'author', webpage, 'uploader', default=None) | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  |         for entry in entries: | 
					
						
							|  |  |  |  |             entry.update(info) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |         if len(entries) == 1: | 
					
						
							|  |  |  |  |             return entries[0] | 
					
						
							|  |  |  |  |         else: | 
					
						
							| 
									
										
										
										
											2016-06-02 19:27:57 +08:00
										 |  |  |  |             for idx, entry in enumerate(entries): | 
					
						
							|  |  |  |  |                 entry['id'] = '%s_part%d' % (video_id, (idx + 1)) | 
					
						
							|  |  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             return { | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |                 '_type': 'multi_video', | 
					
						
							| 
									
										
										
										
											2015-10-17 23:12:58 +01:00
										 |  |  |  |                 'id': video_id, | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |                 'title': title, | 
					
						
							|  |  |  |  |                 'description': description, | 
					
						
							| 
									
										
										
										
											2015-10-17 17:28:09 +01:00
										 |  |  |  |                 'entries': entries, | 
					
						
							| 
									
										
										
										
											2016-05-29 01:26:00 +08:00
										 |  |  |  |             } | 
					
						
							| 
									
										
										
										
											2017-02-02 21:51:31 +08:00
										 |  |  |  | 
 | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  | class BiliBiliBangumiIE(InfoExtractor): | 
					
						
							|  |  |  |  |     _VALID_URL = r'https?://bangumi\.bilibili\.com/anime/(?P<id>\d+)' | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     IE_NAME = 'bangumi.bilibili.com' | 
					
						
							|  |  |  |  |     IE_DESC = 'BiliBili番剧' | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     _TESTS = [{ | 
					
						
							|  |  |  |  |         'url': 'http://bangumi.bilibili.com/anime/1869', | 
					
						
							|  |  |  |  |         'info_dict': { | 
					
						
							|  |  |  |  |             'id': '1869', | 
					
						
							|  |  |  |  |             'title': '混沌武士', | 
					
						
							|  |  |  |  |             'description': 'md5:6a9622b911565794c11f25f81d6a97d2', | 
					
						
							|  |  |  |  |         }, | 
					
						
							|  |  |  |  |         'playlist_count': 26, | 
					
						
							|  |  |  |  |     }, { | 
					
						
							|  |  |  |  |         'url': 'http://bangumi.bilibili.com/anime/1869', | 
					
						
							|  |  |  |  |         'info_dict': { | 
					
						
							|  |  |  |  |             'id': '1869', | 
					
						
							|  |  |  |  |             'title': '混沌武士', | 
					
						
							|  |  |  |  |             'description': 'md5:6a9622b911565794c11f25f81d6a97d2', | 
					
						
							|  |  |  |  |         }, | 
					
						
							|  |  |  |  |         'playlist': [{ | 
					
						
							|  |  |  |  |             'md5': '91da8621454dd58316851c27c68b0c13', | 
					
						
							|  |  |  |  |             'info_dict': { | 
					
						
							|  |  |  |  |                 'id': '40062', | 
					
						
							|  |  |  |  |                 'ext': 'mp4', | 
					
						
							|  |  |  |  |                 'title': '混沌武士', | 
					
						
							|  |  |  |  |                 'description': '故事发生在日本的江户时代。风是一个小酒馆的打工女。一日,酒馆里来了一群恶霸,虽然他们的举动令风十分不满,但是毕竟风只是一届女流,无法对他们采取什么行动,只能在心里嘟哝。这时,酒家里又进来了个“不良份子...', | 
					
						
							|  |  |  |  |                 'timestamp': 1414538739, | 
					
						
							|  |  |  |  |                 'upload_date': '20141028', | 
					
						
							|  |  |  |  |                 'episode': '疾风怒涛 Tempestuous Temperaments', | 
					
						
							|  |  |  |  |                 'episode_number': 1, | 
					
						
							|  |  |  |  |             }, | 
					
						
							|  |  |  |  |         }], | 
					
						
							|  |  |  |  |         'params': { | 
					
						
							|  |  |  |  |             'playlist_items': '1', | 
					
						
							|  |  |  |  |         }, | 
					
						
							|  |  |  |  |     }] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     @classmethod | 
					
						
							|  |  |  |  |     def suitable(cls, url): | 
					
						
							|  |  |  |  |         return False if BiliBiliIE.suitable(url) else super(BiliBiliBangumiIE, cls).suitable(url) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |     def _real_extract(self, url): | 
					
						
							|  |  |  |  |         bangumi_id = self._match_id(url) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         # Sometimes this API returns a JSONP response | 
					
						
							|  |  |  |  |         season_info = self._download_json( | 
					
						
							|  |  |  |  |             'http://bangumi.bilibili.com/jsonp/seasoninfo/%s.ver' % bangumi_id, | 
					
						
							|  |  |  |  |             bangumi_id, transform_source=strip_jsonp)['result'] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         entries = [{ | 
					
						
							|  |  |  |  |             '_type': 'url_transparent', | 
					
						
							|  |  |  |  |             'url': smuggle_url(episode['webplay_url'], {'no_bangumi_tip': 1}), | 
					
						
							|  |  |  |  |             'ie_key': BiliBiliIE.ie_key(), | 
					
						
							|  |  |  |  |             'timestamp': parse_iso8601(episode.get('update_time'), delimiter=' '), | 
					
						
							|  |  |  |  |             'episode': episode.get('index_title'), | 
					
						
							|  |  |  |  |             'episode_number': int_or_none(episode.get('index')), | 
					
						
							|  |  |  |  |         } for episode in season_info['episodes']] | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         entries = sorted(entries, key=lambda entry: entry.get('episode_number')) | 
					
						
							|  |  |  |  | 
 | 
					
						
							|  |  |  |  |         return self.playlist_result( | 
					
						
							|  |  |  |  |             entries, bangumi_id, | 
					
						
							|  |  |  |  |             season_info.get('bangumi_title'), season_info.get('evaluate')) |