1 from .common
import InfoExtractor
13 class RedTubeIE(InfoExtractor
):
14 _VALID_URL
= r
'https?://(?:(?:\w+\.)?redtube\.com/|embed\.redtube\.com/\?.*?\bid=)(?P<id>[0-9]+)'
15 _EMBED_REGEX
= [r
'<iframe[^>]+?src=["\'](?P
<url
>(?
:https?
:)?
//embed\
.redtube\
.com
/\?.*?
\bid
=\d
+)']
17 'url
': 'https
://www
.redtube
.com
/38864951',
18 'md5
': '4fba70cbca3aefd25767ab4b523c9878
',
22 'title
': 'Public Sex on the Balcony
in Freezing Paris
! Amateur Couple LeoLulu
',
23 'description
': 'Watch video Public Sex on the Balcony
in Freezing Paris
! Amateur Couple LeoLulu on Redtube
, home of free Blowjob porn videos
and Blonde sex movies online
. Video length
: (10:46) - Uploaded by leolulu
- Verified User
- Starring Pornstar
: Leolulu
',
24 'upload_date
': '20210111',
25 'timestamp
': 1610343109,
29 'thumbnail
': r're
:https
://\wi
-ph\
.rdtcdn\
.com
/videos
/.+/.+\
.jpg
',
32 'url
': 'http
://embed
.redtube
.com
/?bgcolor
=000000&id=1443286',
33 'only_matching
': True,
35 'url
': 'http
://it
.redtube
.com
/66418',
36 'only_matching
': True,
39 def _real_extract(self, url):
40 video_id = self._match_id(url)
41 webpage = self._download_webpage(
42 'http
://www
.redtube
.com
/%s' % video_id, video_id)
45 (('video
-deleted
-info
', '>This video has been removed
'), 'has been removed
'),
46 (('private_video_text
', '>This video
is private
', '>Send a friend request to its owner to be able to view it
'), 'is private
'),
49 for patterns, message in ERRORS:
50 if any(p in webpage for p in patterns):
52 'Video
%s %s' % (video_id, message), expected=True)
54 info = self._search_json_ld(webpage, video_id, default={})
56 if not info.get('title
'):
57 info['title
'] = self._html_search_regex(
58 (r'<h(\d
)[^
>]+class="(?:video_title_text|videoTitle|video_title)[^"]*">(?P<title>(?:(?!\1).)+)</h\1>',
59 r'(?:videoTitle|title)\s*:\s*(["\'])(?P
<title
>(?
:(?
!\
1).)+)\
1',),
60 webpage, 'title
', group='title
',
61 default=None) or self._og_search_title(webpage)
64 sources = self._parse_json(
66 r'sources\s
*:\s
*({.+?}
)', webpage, 'source
', default='{}'),
67 video_id, fatal=False)
68 if sources and isinstance(sources, dict):
69 for format_id, format_url in sources.items():
73 'format_id
': format_id,
74 'height
': int_or_none(format_id),
76 medias = self._parse_json(
78 r'mediaDefinition
["\']?\s*:\s*(\[.+?}\s*\])', webpage,
79 'media definitions', default='{}'),
80 video_id, fatal=False)
81 for media in medias if isinstance(medias, list) else []:
82 format_url = url_or_none(media.get('videoUrl'))
85 format_id = media.get('format')
86 quality = media.get('quality')
87 if format_id == 'hls' or (format_id == 'mp4' and not quality):
88 more_media = self._download_json(format_url, video_id, fatal=False)
91 for media in more_media if isinstance(more_media, list) else []:
92 format_url = url_or_none(media.get('videoUrl'))
95 format_id = media.get('format')
96 if format_id == 'hls' or determine_ext(format_url) == 'm3u8':
97 formats.extend(self._extract_m3u8_formats(
98 format_url, video_id, 'mp4',
99 entry_protocol='m3u8_native', m3u8_id=format_id or 'hls',
102 format_id = media.get('quality')
106 'format_id': format_id,
107 'height': int_or_none(format_id),
110 video_url = self._html_search_regex(
111 r'<source src="(.+?
)" type="video
/mp4
">', webpage, 'video URL')
112 formats.append({'url': video_url, 'ext': 'mp4'})
113 self._sort_formats(formats)
115 thumbnail = self._og_search_thumbnail(webpage)
116 upload_date = unified_strdate(self._search_regex(
117 r'<span[^>]+>(?:ADDED|Published on) ([^<]+)<',
118 webpage, 'upload date', default=None))
119 duration = int_or_none(self._og_search_property(
120 'video:duration', webpage, default=None) or self._search_regex(
121 r'videoDuration\s*:\s*(\d+)', webpage, 'duration', default=None))
122 view_count = str_to_int(self._search_regex(
123 (r'<div[^>]*>Views</div>\s*<div[^>]*>\s*([\d,.]+)',
124 r'<span[^>]*>VIEWS</span>\s*</td>\s*<td>\s*([\d,.]+)',
125 r'<span[^>]+\bclass=["\']video_view_count
[^
>]*>\s
*([\d
,.]+)'),
126 webpage, 'view count
', default=None))
128 # No self-labeling, but they describe themselves as
129 # "Home of Videos Porno"
132 return merge_dicts(info, {
135 'thumbnail
': thumbnail,
136 'upload_date
': upload_date,
137 'duration
': duration,
138 'view_count
': view_count,
139 'age_limit
': age_limit,