]>
Commit | Line | Data |
---|---|---|
cd55c6cc | 1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | from .common import InfoExtractor | |
5 | from ..utils import ( | |
6 | ExtractorError, | |
7 | clean_html, | |
8 | compat_str, | |
9 | int_or_none, | |
10 | parse_iso8601, | |
11 | try_get, | |
12 | ) | |
13 | ||
14 | ||
15 | class BeamProLiveIE(InfoExtractor): | |
16 | IE_NAME = 'Beam:live' | |
17 | _VALID_URL = r'https?://(?:\w+.)?beam.pro/(?P<id>[^?]+)$' | |
18 | _API_CHANNEL = 'https://beam.pro/api/v1/channels/{0}' | |
19 | _API_MANIFEST = 'https://beam.pro/api/v1/channels/{0}/manifest.m3u8' | |
20 | _RATINGS = {'family': 0, 'teen': 13, '18+': 18} | |
21 | ||
22 | _TEST = { | |
23 | 'url': 'http://www.beam.pro/niterhayven', | |
24 | 'info_dict': { | |
25 | 'id': '261562', | |
26 | 'ext': 'mp4', | |
27 | 'uploader': 'niterhayven', | |
28 | 'timestamp': 1483477281, | |
29 | 'age_limit': 18, | |
30 | 'title': 'Introducing The Witcher 3 // The Grind Starts Now!', | |
31 | 'thumbnail': r're:https://.*\.jpg$', | |
32 | 'upload_date': '20170103', | |
33 | 'uploader_id': 373396, | |
34 | 'description': 'md5:0b161ac080f15fe05d18a07adb44a74d', | |
35 | 'is_live': True, | |
36 | }, | |
37 | 'skip': 'niterhayven is offline', | |
38 | 'params': { | |
39 | 'skip_download': True, | |
40 | }, | |
41 | } | |
42 | ||
43 | def _real_extract(self, url): | |
44 | channel_id = self._match_id(url) | |
45 | chan_data = self._download_json(self._API_CHANNEL.format(channel_id), channel_id) | |
46 | ||
47 | if not chan_data.get('online'): | |
48 | raise ExtractorError('{0} is offline'.format(channel_id), expected=True) | |
49 | ||
50 | formats = self._extract_m3u8_formats( | |
51 | self._API_MANIFEST.format(chan_data.get('id')), channel_id, ext='mp4') | |
52 | ||
53 | self._sort_formats(formats) | |
54 | info = {} | |
55 | info['formats'] = formats | |
56 | if chan_data: | |
57 | info.update(self._extract_info(chan_data)) | |
58 | if not info.get('title'): | |
59 | info['title'] = self._live_title(channel_id) | |
60 | if not info.get('id'): # barely possible but just in case | |
61 | info['id'] = compat_str(abs(hash(channel_id)) % (10 ** 8)) | |
62 | ||
63 | return info | |
64 | ||
65 | def _extract_info(self, info): | |
66 | thumbnail = try_get(info, lambda x: x['thumbnail']['url'], compat_str) | |
67 | username = try_get(info, lambda x: x['user']['url'], compat_str) | |
68 | video_id = compat_str(info['id']) if info.get('id') else None | |
69 | rating = info.get('audience') | |
70 | ||
71 | return { | |
72 | 'id': video_id, | |
73 | 'title': info.get('name'), | |
74 | 'description': clean_html(info.get('description')), | |
75 | 'age_limit': self._RATINGS[rating] if rating in self._RATINGS else None, | |
76 | 'is_live': True if info.get('online') else False, | |
77 | 'timestamp': parse_iso8601(info.get('updatedAt')), | |
78 | 'uploader': info.get('token') or username, | |
79 | 'uploader_id': int_or_none(info.get('userId')), | |
80 | 'view_count': int_or_none(info.get('viewersTotal')), | |
81 | 'thumbnail': thumbnail, | |
82 | } |