]> jfr.im git - yt-dlp.git/blame - yt_dlp/extractor/cammodels.py
Completely change project name to yt-dlp (#85)
[yt-dlp.git] / yt_dlp / extractor / cammodels.py
CommitLineData
8b1da46e 1# coding: utf-8
2a49d019 2from __future__ import unicode_literals
8b1da46e 3
2a49d019 4from .common import InfoExtractor
8b1da46e
S
5from ..utils import (
6 ExtractorError,
7 int_or_none,
3052a30d 8 url_or_none,
8b1da46e 9)
2a49d019 10
11
12class CamModelsIE(InfoExtractor):
8b1da46e
S
13 _VALID_URL = r'https?://(?:www\.)?cammodels\.com/cam/(?P<id>[^/?#&]+)'
14 _TESTS = [{
15 'url': 'https://www.cammodels.com/cam/AutumnKnight/',
16 'only_matching': True,
9b5c8751 17 'age_limit': 18
8b1da46e 18 }]
2a49d019 19
20 def _real_extract(self, url):
8b1da46e
S
21 user_id = self._match_id(url)
22
8882840e
S
23 webpage = self._download_webpage(
24 url, user_id, headers=self.geo_verification_headers())
8b1da46e
S
25
26 manifest_root = self._html_search_regex(
27 r'manifestUrlRoot=([^&\']+)', webpage, 'manifest', default=None)
28
29 if not manifest_root:
30 ERRORS = (
31 ("I'm offline, but let's stay connected", 'This user is currently offline'),
32 ('in a private show', 'This user is in a private show'),
2ce35d9f 33 ('is currently performing LIVE', 'This model is currently performing live'),
2a49d019 34 )
8b1da46e
S
35 for pattern, message in ERRORS:
36 if pattern in webpage:
37 error = message
38 expected = True
39 break
40 else:
41 error = 'Unable to find manifest URL root'
42 expected = False
43 raise ExtractorError(error, expected=expected)
44
2a49d019 45 manifest = self._download_json(
8b1da46e
S
46 '%s%s.json' % (manifest_root, user_id), user_id)
47
48 formats = []
49 for format_id, format_dict in manifest['formats'].items():
50 if not isinstance(format_dict, dict):
51 continue
52 encodings = format_dict.get('encodings')
53 if not isinstance(encodings, list):
54 continue
55 vcodec = format_dict.get('videoCodec')
56 acodec = format_dict.get('audioCodec')
57 for media in encodings:
58 if not isinstance(media, dict):
59 continue
3052a30d
S
60 media_url = url_or_none(media.get('location'))
61 if not media_url:
8b1da46e
S
62 continue
63
64 format_id_list = [format_id]
65 height = int_or_none(media.get('videoHeight'))
66 if height is not None:
67 format_id_list.append('%dp' % height)
68 f = {
69 'url': media_url,
70 'format_id': '-'.join(format_id_list),
71 'width': int_or_none(media.get('videoWidth')),
72 'height': height,
73 'vbr': int_or_none(media.get('videoKbps')),
74 'abr': int_or_none(media.get('audioKbps')),
75 'fps': int_or_none(media.get('fps')),
76 'vcodec': vcodec,
77 'acodec': acodec,
78 }
79 if 'rtmp' in format_id:
80 f['ext'] = 'flv'
81 elif 'hls' in format_id:
82 f.update({
2a49d019 83 'ext': 'mp4',
8b1da46e 84 # hls skips fragments, preferring rtmp
f983b875 85 'quality': -10,
2a49d019 86 })
8b1da46e
S
87 else:
88 continue
89 formats.append(f)
2a49d019 90 self._sort_formats(formats)
8b1da46e 91
2a49d019 92 return {
8b1da46e
S
93 'id': user_id,
94 'title': self._live_title(user_id),
95 'is_live': True,
96 'formats': formats,
9b5c8751 97 'age_limit': 18
2a49d019 98 }