]> jfr.im git - yt-dlp.git/blob - yt_dlp/extractor/youporn.py
b484e08ece573b1bff1dbcd703881f1e5af2b08b
[yt-dlp.git] / yt_dlp / extractor / youporn.py
1 import re
2
3 from .common import InfoExtractor
4 from ..utils import (
5 extract_attributes,
6 int_or_none,
7 str_to_int,
8 unified_strdate,
9 url_or_none,
10 )
11
12
13 class YouPornIE(InfoExtractor):
14 _VALID_URL = r'https?://(?:www\.)?youporn\.com/(?:watch|embed)/(?P<id>\d+)(?:/(?P<display_id>[^/?#&]+))?'
15 _TESTS = [{
16 'url': 'http://www.youporn.com/watch/505835/sex-ed-is-it-safe-to-masturbate-daily/',
17 'md5': '3744d24c50438cf5b6f6d59feb5055c2',
18 'info_dict': {
19 'id': '505835',
20 'display_id': 'sex-ed-is-it-safe-to-masturbate-daily',
21 'ext': 'mp4',
22 'title': 'Sex Ed: Is It Safe To Masturbate Daily?',
23 'description': 'Love & Sex Answers: http://bit.ly/DanAndJenn -- Is It Unhealthy To Masturbate Daily?',
24 'thumbnail': r're:^https?://.*\.jpg$',
25 'duration': 210,
26 'uploader': 'Ask Dan And Jennifer',
27 'upload_date': '20101217',
28 'average_rating': int,
29 'view_count': int,
30 'categories': list,
31 'tags': list,
32 'age_limit': 18,
33 },
34 'skip': 'This video has been disabled',
35 }, {
36 # Unknown uploader
37 'url': 'http://www.youporn.com/watch/561726/big-tits-awesome-brunette-on-amazing-webcam-show/?from=related3&al=2&from_id=561726&pos=4',
38 'info_dict': {
39 'id': '561726',
40 'display_id': 'big-tits-awesome-brunette-on-amazing-webcam-show',
41 'ext': 'mp4',
42 'title': 'Big Tits Awesome Brunette On amazing webcam show',
43 'description': 'http://sweetlivegirls.com Big Tits Awesome Brunette On amazing webcam show.mp4',
44 'thumbnail': r're:^https?://.*\.jpg$',
45 'uploader': 'Unknown',
46 'upload_date': '20110418',
47 'average_rating': int,
48 'view_count': int,
49 'categories': list,
50 'tags': list,
51 'age_limit': 18,
52 },
53 'params': {
54 'skip_download': True,
55 },
56 'skip': '404',
57 }, {
58 'url': 'https://www.youporn.com/embed/505835/sex-ed-is-it-safe-to-masturbate-daily/',
59 'only_matching': True,
60 }, {
61 'url': 'http://www.youporn.com/watch/505835',
62 'only_matching': True,
63 }, {
64 'url': 'https://www.youporn.com/watch/13922959/femdom-principal/',
65 'only_matching': True,
66 }]
67
68 @staticmethod
69 def _extract_urls(webpage):
70 return re.findall(
71 r'<iframe[^>]+\bsrc=["\']((?:https?:)?//(?:www\.)?youporn\.com/embed/\d+)',
72 webpage)
73
74 def _real_extract(self, url):
75 mobj = self._match_valid_url(url)
76 video_id = mobj.group('id')
77 display_id = mobj.group('display_id') or video_id
78
79 definitions = self._download_json(
80 'https://www.youporn.com/api/video/media_definitions/%s/' % video_id,
81 display_id)
82
83 formats = []
84 for definition in definitions:
85 if not isinstance(definition, dict):
86 continue
87 video_url = url_or_none(definition.get('videoUrl'))
88 if not video_url:
89 continue
90 f = {
91 'url': video_url,
92 'filesize': int_or_none(definition.get('videoSize')),
93 }
94 height = int_or_none(definition.get('quality'))
95 # Video URL's path looks like this:
96 # /201012/17/505835/720p_1500k_505835/YouPorn%20-%20Sex%20Ed%20Is%20It%20Safe%20To%20Masturbate%20Daily.mp4
97 # /201012/17/505835/vl_240p_240k_505835/YouPorn%20-%20Sex%20Ed%20Is%20It%20Safe%20To%20Masturbate%20Daily.mp4
98 # /videos/201703/11/109285532/1080P_4000K_109285532.mp4
99 # We will benefit from it by extracting some metadata
100 mobj = re.search(r'(?P<height>\d{3,4})[pP]_(?P<bitrate>\d+)[kK]_\d+', video_url)
101 if mobj:
102 if not height:
103 height = int(mobj.group('height'))
104 bitrate = int(mobj.group('bitrate'))
105 f.update({
106 'format_id': '%dp-%dk' % (height, bitrate),
107 'tbr': bitrate,
108 })
109 f['height'] = height
110 formats.append(f)
111 self._sort_formats(formats)
112
113 webpage = self._download_webpage(
114 'http://www.youporn.com/watch/%s' % video_id, display_id,
115 headers={'Cookie': 'age_verified=1'})
116
117 title = self._html_search_regex(
118 r'(?s)<div[^>]+class=["\']watchVideoTitle[^>]+>(.+?)</div>',
119 webpage, 'title', default=None) or self._og_search_title(
120 webpage, default=None) or self._html_search_meta(
121 'title', webpage, fatal=True)
122
123 description = self._html_search_regex(
124 r'(?s)<div[^>]+\bid=["\']description["\'][^>]*>(.+?)</div>',
125 webpage, 'description',
126 default=None) or self._og_search_description(
127 webpage, default=None)
128 thumbnail = self._search_regex(
129 r'(?:imageurl\s*=|poster\s*:)\s*(["\'])(?P<thumbnail>.+?)\1',
130 webpage, 'thumbnail', fatal=False, group='thumbnail')
131 duration = int_or_none(self._html_search_meta(
132 'video:duration', webpage, 'duration', fatal=False))
133
134 uploader = self._html_search_regex(
135 r'(?s)<div[^>]+class=["\']submitByLink["\'][^>]*>(.+?)</div>',
136 webpage, 'uploader', fatal=False)
137 upload_date = unified_strdate(self._html_search_regex(
138 (r'UPLOADED:\s*<span>([^<]+)',
139 r'Date\s+[Aa]dded:\s*<span>([^<]+)',
140 r'''(?s)<div[^>]+class=["']videoInfo(?:Date|Time)\b[^>]*>(.+?)</div>''',
141 r'(?s)<label\b[^>]*>Uploaded[^<]*</label>\s*<span\b[^>]*>(.+?)</span>'),
142 webpage, 'upload date', fatal=False))
143
144 age_limit = self._rta_search(webpage)
145
146 view_count = None
147 views = self._search_regex(
148 r'(<div[^>]+\bclass=["\']js_videoInfoViews["\']>)', webpage,
149 'views', default=None)
150 if views:
151 view_count = str_to_int(extract_attributes(views).get('data-value'))
152 comment_count = str_to_int(self._search_regex(
153 r'>All [Cc]omments? \(([\d,.]+)\)',
154 webpage, 'comment count', default=None))
155
156 def extract_tag_box(regex, title):
157 tag_box = self._search_regex(regex, webpage, title, default=None)
158 if not tag_box:
159 return []
160 return re.findall(r'<a[^>]+href=[^>]+>([^<]+)', tag_box)
161
162 categories = extract_tag_box(
163 r'(?s)Categories:.*?</[^>]+>(.+?)</div>', 'categories')
164 tags = extract_tag_box(
165 r'(?s)Tags:.*?</div>\s*<div[^>]+class=["\']tagBoxContent["\'][^>]*>(.+?)</div>',
166 'tags')
167
168 return {
169 'id': video_id,
170 'display_id': display_id,
171 'title': title,
172 'description': description,
173 'thumbnail': thumbnail,
174 'duration': duration,
175 'uploader': uploader,
176 'upload_date': upload_date,
177 'view_count': view_count,
178 'comment_count': comment_count,
179 'categories': categories,
180 'tags': tags,
181 'age_limit': age_limit,
182 'formats': formats,
183 }