]>
Commit | Line | Data |
---|---|---|
8fddc232 | 1 | import random |
2 | ||
3 | from .common import InfoExtractor | |
4 | from ..utils import ExtractorError, traverse_obj | |
5 | ||
6 | ||
7 | class CamsodaIE(InfoExtractor): | |
8 | _VALID_URL = r'https?://www\.camsoda\.com/(?P<id>[\w-]+)' | |
9 | _TESTS = [{ | |
10 | 'url': 'https://www.camsoda.com/lizzhopf', | |
11 | 'info_dict': { | |
12 | 'id': 'lizzhopf', | |
13 | 'ext': 'mp4', | |
14 | 'title': 'lizzhopf (lizzhopf) Nude on Cam. Free Live Sex Chat Room - CamSoda', | |
15 | 'description': str, | |
16 | 'is_live': True, | |
17 | 'age_limit': 18, | |
18 | }, | |
19 | 'skip': 'Room is offline', | |
20 | }] | |
21 | ||
22 | def _real_extract(self, url): | |
23 | video_id = self._match_id(url) | |
24 | webpage = self._download_webpage(url, video_id, headers=self.geo_verification_headers()) | |
25 | ||
26 | data = self._download_json( | |
27 | f'https://camsoda.com/api/v1/video/vtoken/{video_id}', video_id, | |
28 | query={'username': f'guest_{random.randrange(10000, 99999)}'}, | |
29 | headers=self.geo_verification_headers()) | |
30 | if not data: | |
31 | raise ExtractorError('Unable to find configuration for stream.') | |
32 | elif data.get('private_servers'): | |
33 | raise ExtractorError('Model is in private show.', expected=True) | |
34 | elif not data.get('stream_name'): | |
35 | raise ExtractorError('Model is offline.', expected=True) | |
36 | ||
37 | stream_name = traverse_obj(data, 'stream_name', expected_type=str) | |
38 | token = traverse_obj(data, 'token', expected_type=str) | |
39 | ||
40 | formats = [] | |
41 | for server in traverse_obj(data, ('edge_servers', ...)): | |
42 | formats = self._extract_m3u8_formats( | |
43 | f'https://{server}/{stream_name}_v1/index.m3u8?token={token}', | |
44 | video_id, ext='mp4', m3u8_id='hls', fatal=False, live=True) | |
45 | if formats: | |
46 | break | |
47 | if not formats: | |
48 | self.raise_no_formats('No active streams found', expected=True) | |
49 | ||
8fddc232 | 50 | return { |
51 | 'id': video_id, | |
52 | 'title': self._html_extract_title(webpage), | |
53 | 'description': self._html_search_meta('description', webpage, default=None), | |
54 | 'is_live': True, | |
55 | 'formats': formats, | |
56 | 'age_limit': 18, | |
57 | } |