3 from .common
import InfoExtractor
4 from ..utils
import ExtractorError
, traverse_obj
7 class CamsodaIE(InfoExtractor
):
8 _VALID_URL
= r
'https?://www\.camsoda\.com/(?P<id>[\w-]+)'
10 'url': 'https://www.camsoda.com/lizzhopf',
14 'title': 'lizzhopf (lizzhopf) Nude on Cam. Free Live Sex Chat Room - CamSoda',
19 'skip': 'Room is offline',
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())
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())
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)
37 stream_name
= traverse_obj(data
, 'stream_name', expected_type
=str)
38 token
= traverse_obj(data
, 'token', expected_type
=str)
41 for server
in traverse_obj(data
, ('edge_servers', ...)):
42 formats
= self
._extract
_m
3u8_formats
(
43 f
'https://{server}/{stream_name}_v1/index.m3u8?token={token}',
44 video_id
, ext
='mp4', m3u8_id
='hls', fatal
=False, live
=True)
48 self
.raise_no_formats('No active streams found', expected
=True)
52 'title': self
._html
_extract
_title
(webpage
),
53 'description': self
._html
_search
_meta
('description', webpage
, default
=None),