]>
Commit | Line | Data |
---|---|---|
2e7c8cab ZJ |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from .common import InfoExtractor | |
2e7c8cab ZJ |
5 | from ..utils import ( |
6 | ExtractorError, | |
d2e96a8e | 7 | qualities, |
2e7c8cab ZJ |
8 | ) |
9 | ||
d2e96a8e | 10 | |
2e7c8cab ZJ |
11 | class PandaTVIE(InfoExtractor): |
12 | IE_DESC = '熊猫TV' | |
35544690 XHS |
13 | _VALID_URL = r'https?://(?:www\.)?panda\.tv/(?P<id>[0-9]+)' |
14 | _TESTS = [{ | |
15 | 'url': 'http://www.panda.tv/66666', | |
2e7c8cab | 16 | 'info_dict': { |
35544690 | 17 | 'id': '66666', |
2e7c8cab | 18 | 'title': 're:.+', |
35544690 | 19 | 'uploader': '刘杀鸡', |
2e7c8cab ZJ |
20 | 'ext': 'flv', |
21 | 'is_live': True, | |
22 | }, | |
23 | 'params': { | |
24 | 'skip_download': True, | |
25 | }, | |
d2e96a8e | 26 | 'skip': 'Live stream is offline', |
35544690 XHS |
27 | }, { |
28 | 'url': 'https://www.panda.tv/66666', | |
29 | 'only_matching': True, | |
30 | }] | |
2e7c8cab ZJ |
31 | |
32 | def _real_extract(self, url): | |
33 | video_id = self._match_id(url) | |
34 | ||
35 | config = self._download_json( | |
33ffb645 | 36 | 'https://www.panda.tv/api_room?roomid=%s' % video_id, video_id) |
2e7c8cab ZJ |
37 | |
38 | error_code = config.get('errno', 0) | |
39 | if error_code is not 0: | |
d2e96a8e S |
40 | raise ExtractorError( |
41 | '%s returned error %s: %s' | |
42 | % (self.IE_NAME, error_code, config['errmsg']), | |
43 | expected=True) | |
2e7c8cab | 44 | |
d2e96a8e | 45 | data = config['data'] |
2e7c8cab ZJ |
46 | video_info = data['videoinfo'] |
47 | ||
48 | # 2 = live, 3 = offline | |
49 | if video_info.get('status') != '2': | |
50 | raise ExtractorError( | |
51 | 'Live stream is offline', expected=True) | |
52 | ||
53 | title = data['roominfo']['name'] | |
54 | uploader = data.get('hostinfo', {}).get('name') | |
55 | room_key = video_info['room_key'] | |
d2e96a8e S |
56 | stream_addr = video_info.get( |
57 | 'stream_addr', {'OD': '1', 'HD': '1', 'SD': '1'}) | |
2e7c8cab | 58 | |
d2e96a8e S |
59 | # Reverse engineered from web player swf |
60 | # (http://s6.pdim.gs/static/07153e425f581151.swf at the moment of | |
61 | # writing). | |
2e7c8cab ZJ |
62 | plflag0, plflag1 = video_info['plflag'].split('_') |
63 | plflag0 = int(plflag0) - 1 | |
64 | if plflag1 == '21': | |
65 | plflag0 = 10 | |
66 | plflag1 = '4' | |
67 | live_panda = 'live_panda' if plflag0 < 1 else '' | |
68 | ||
69 | quality_key = qualities(['OD', 'HD', 'SD']) | |
70 | suffix = ['_small', '_mid', ''] | |
71 | formats = [] | |
72 | for k, v in stream_addr.items(): | |
d2e96a8e S |
73 | if v != '1': |
74 | continue | |
75 | quality = quality_key(k) | |
76 | if quality <= 0: | |
77 | continue | |
78 | for pref, (ext, pl) in enumerate((('m3u8', '-hls'), ('flv', ''))): | |
79 | formats.append({ | |
33ffb645 | 80 | 'url': 'https://pl%s%s.live.panda.tv/live_panda/%s%s%s.%s' |
d2e96a8e S |
81 | % (pl, plflag1, room_key, live_panda, suffix[quality], ext), |
82 | 'format_id': '%s-%s' % (k, ext), | |
83 | 'quality': quality, | |
84 | 'source_preference': pref, | |
85 | }) | |
2e7c8cab ZJ |
86 | self._sort_formats(formats) |
87 | ||
88 | return { | |
89 | 'id': video_id, | |
90 | 'title': self._live_title(title), | |
91 | 'uploader': uploader, | |
92 | 'formats': formats, | |
93 | 'is_live': True, | |
94 | } |