[vimeo] improve extraction
- fix review extraction - fix ondemand extraction - make password protected player case as an expected error(closes #22896) - simplify channel based extractors code
This commit is contained in:
parent
6471d0d3b8
commit
681ac7c92a
1 changed files with 87 additions and 90 deletions
|
@ -15,18 +15,20 @@ from ..compat import (
|
||||||
compat_urlparse,
|
compat_urlparse,
|
||||||
)
|
)
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
|
clean_html,
|
||||||
determine_ext,
|
determine_ext,
|
||||||
|
dict_get,
|
||||||
ExtractorError,
|
ExtractorError,
|
||||||
js_to_json,
|
js_to_json,
|
||||||
int_or_none,
|
int_or_none,
|
||||||
merge_dicts,
|
merge_dicts,
|
||||||
NO_DEFAULT,
|
|
||||||
OnDemandPagedList,
|
OnDemandPagedList,
|
||||||
parse_filesize,
|
parse_filesize,
|
||||||
RegexNotFoundError,
|
RegexNotFoundError,
|
||||||
sanitized_Request,
|
sanitized_Request,
|
||||||
smuggle_url,
|
smuggle_url,
|
||||||
std_headers,
|
std_headers,
|
||||||
|
str_or_none,
|
||||||
try_get,
|
try_get,
|
||||||
unified_timestamp,
|
unified_timestamp,
|
||||||
unsmuggle_url,
|
unsmuggle_url,
|
||||||
|
@ -210,7 +212,7 @@ class VimeoBaseInfoExtractor(InfoExtractor):
|
||||||
video_uploader_url = owner.get('url')
|
video_uploader_url = owner.get('url')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
'id': video_id,
|
'id': str_or_none(video_data.get('id')) or video_id,
|
||||||
'title': self._live_title(video_title) if is_live else video_title,
|
'title': self._live_title(video_title) if is_live else video_title,
|
||||||
'uploader': owner.get('name'),
|
'uploader': owner.get('name'),
|
||||||
'uploader_id': video_uploader_url.split('/')[-1] if video_uploader_url else None,
|
'uploader_id': video_uploader_url.split('/')[-1] if video_uploader_url else None,
|
||||||
|
@ -258,11 +260,11 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
(?:
|
(?:
|
||||||
(?:
|
(?:
|
||||||
www|
|
www|
|
||||||
(?P<player>player)
|
player
|
||||||
)
|
)
|
||||||
\.
|
\.
|
||||||
)?
|
)?
|
||||||
vimeo(?P<pro>pro)?\.com/
|
vimeo(?:pro)?\.com/
|
||||||
(?!(?:channels|album|showcase)/[^/?#]+/?(?:$|[?#])|[^/]+/review/|ondemand/)
|
(?!(?:channels|album|showcase)/[^/?#]+/?(?:$|[?#])|[^/]+/review/|ondemand/)
|
||||||
(?:.*?/)?
|
(?:.*?/)?
|
||||||
(?:
|
(?:
|
||||||
|
@ -284,7 +286,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'id': '56015672',
|
'id': '56015672',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': "youtube-dl test video - \u2605 \" ' \u5e78 / \\ \u00e4 \u21ad \U0001d550",
|
'title': "youtube-dl test video - \u2605 \" ' \u5e78 / \\ \u00e4 \u21ad \U0001d550",
|
||||||
'description': 'md5:509a9ad5c9bf97c60faee9203aca4479',
|
'description': 'md5:2d3305bad981a06ff79f027f19865021',
|
||||||
'timestamp': 1355990239,
|
'timestamp': 1355990239,
|
||||||
'upload_date': '20121220',
|
'upload_date': '20121220',
|
||||||
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/user7108434',
|
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/user7108434',
|
||||||
|
@ -293,6 +295,9 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'duration': 10,
|
'duration': 10,
|
||||||
'license': 'by-sa',
|
'license': 'by-sa',
|
||||||
},
|
},
|
||||||
|
'params': {
|
||||||
|
'format': 'best[protocol=https]',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://vimeopro.com/openstreetmapus/state-of-the-map-us-2013/video/68093876',
|
'url': 'http://vimeopro.com/openstreetmapus/state-of-the-map-us-2013/video/68093876',
|
||||||
|
@ -305,8 +310,13 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'uploader_id': 'openstreetmapus',
|
'uploader_id': 'openstreetmapus',
|
||||||
'uploader': 'OpenStreetMap US',
|
'uploader': 'OpenStreetMap US',
|
||||||
'title': 'Andy Allan - Putting the Carto into OpenStreetMap Cartography',
|
'title': 'Andy Allan - Putting the Carto into OpenStreetMap Cartography',
|
||||||
'description': 'md5:fd69a7b8d8c34a4e1d2ec2e4afd6ec30',
|
'description': 'md5:2c362968038d4499f4d79f88458590c1',
|
||||||
'duration': 1595,
|
'duration': 1595,
|
||||||
|
'upload_date': '20130610',
|
||||||
|
'timestamp': 1370893156,
|
||||||
|
},
|
||||||
|
'params': {
|
||||||
|
'format': 'best[protocol=https]',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
@ -323,6 +333,10 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'duration': 3610,
|
'duration': 3610,
|
||||||
'description': None,
|
'description': None,
|
||||||
},
|
},
|
||||||
|
'params': {
|
||||||
|
'format': 'best[protocol=https]',
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://vimeo.com/68375962',
|
'url': 'http://vimeo.com/68375962',
|
||||||
|
@ -341,6 +355,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'description': 'md5:dca3ea23adb29ee387127bc4ddfce63f',
|
'description': 'md5:dca3ea23adb29ee387127bc4ddfce63f',
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
|
'format': 'best[protocol=https]',
|
||||||
'videopassword': 'youtube-dl',
|
'videopassword': 'youtube-dl',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -441,10 +456,14 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'uploader': '10Ft Films',
|
'uploader': '10Ft Films',
|
||||||
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/tenfootfilms',
|
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/tenfootfilms',
|
||||||
'uploader_id': 'tenfootfilms',
|
'uploader_id': 'tenfootfilms',
|
||||||
|
'description': 'md5:0fa704e05b04f91f40b7f3ca2e801384',
|
||||||
|
'upload_date': '20130830',
|
||||||
|
'timestamp': 1377853339,
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'url': 'http://player.vimeo.com/video/68375962',
|
'url': 'http://player.vimeo.com/video/68375962',
|
||||||
|
@ -459,6 +478,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
'duration': 10,
|
'duration': 10,
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
|
'format': 'best[protocol=https]',
|
||||||
'videopassword': 'youtube-dl',
|
'videopassword': 'youtube-dl',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
@ -523,7 +543,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
def _verify_player_video_password(self, url, video_id, headers):
|
def _verify_player_video_password(self, url, video_id, headers):
|
||||||
password = self._downloader.params.get('videopassword')
|
password = self._downloader.params.get('videopassword')
|
||||||
if password is None:
|
if password is None:
|
||||||
raise ExtractorError('This video is protected by a password, use the --video-password option')
|
raise ExtractorError('This video is protected by a password, use the --video-password option', expected=True)
|
||||||
data = urlencode_postdata({
|
data = urlencode_postdata({
|
||||||
'password': base64.b64encode(password.encode()),
|
'password': base64.b64encode(password.encode()),
|
||||||
})
|
})
|
||||||
|
@ -552,28 +572,26 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
r'vimeo\.com/channels/([^/]+)', url, 'channel id', default=None)
|
r'vimeo\.com/channels/([^/]+)', url, 'channel id', default=None)
|
||||||
|
|
||||||
# Extract ID from URL
|
# Extract ID from URL
|
||||||
mobj = re.match(self._VALID_URL, url)
|
video_id = self._match_id(url)
|
||||||
video_id = mobj.group('id')
|
|
||||||
orig_url = url
|
orig_url = url
|
||||||
if mobj.group('pro'):
|
is_pro = 'vimeopro.com/' in url
|
||||||
|
is_player = '://player.vimeo.com/video/' in url
|
||||||
|
if is_pro:
|
||||||
# some videos require portfolio_id to be present in player url
|
# some videos require portfolio_id to be present in player url
|
||||||
# https://github.com/ytdl-org/youtube-dl/issues/20070
|
# https://github.com/ytdl-org/youtube-dl/issues/20070
|
||||||
url = self._extract_url(url, self._download_webpage(url, video_id))
|
url = self._extract_url(url, self._download_webpage(url, video_id))
|
||||||
elif mobj.group('player'):
|
if not url:
|
||||||
|
url = 'https://vimeo.com/' + video_id
|
||||||
|
elif is_player:
|
||||||
url = 'https://player.vimeo.com/video/' + video_id
|
url = 'https://player.vimeo.com/video/' + video_id
|
||||||
elif any(p in url for p in ('play_redirect_hls', 'moogaloop.swf')):
|
elif any(p in url for p in ('play_redirect_hls', 'moogaloop.swf')):
|
||||||
url = 'https://vimeo.com/' + video_id
|
url = 'https://vimeo.com/' + video_id
|
||||||
|
|
||||||
# Retrieve video webpage to extract further information
|
|
||||||
request = sanitized_Request(url, headers=headers)
|
|
||||||
try:
|
try:
|
||||||
webpage, urlh = self._download_webpage_handle(request, video_id)
|
# Retrieve video webpage to extract further information
|
||||||
|
webpage, urlh = self._download_webpage_handle(
|
||||||
|
url, video_id, headers=headers)
|
||||||
redirect_url = compat_str(urlh.geturl())
|
redirect_url = compat_str(urlh.geturl())
|
||||||
# Some URLs redirect to ondemand can't be extracted with
|
|
||||||
# this extractor right away thus should be passed through
|
|
||||||
# ondemand extractor (e.g. https://vimeo.com/73445910)
|
|
||||||
if VimeoOndemandIE.suitable(redirect_url):
|
|
||||||
return self.url_result(redirect_url, VimeoOndemandIE.ie_key())
|
|
||||||
except ExtractorError as ee:
|
except ExtractorError as ee:
|
||||||
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
|
if isinstance(ee.cause, compat_HTTPError) and ee.cause.code == 403:
|
||||||
errmsg = ee.cause.read()
|
errmsg = ee.cause.read()
|
||||||
|
@ -600,6 +618,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
|
|
||||||
cc_license = None
|
cc_license = None
|
||||||
timestamp = None
|
timestamp = None
|
||||||
|
video_description = None
|
||||||
|
|
||||||
# Extract the config JSON
|
# Extract the config JSON
|
||||||
try:
|
try:
|
||||||
|
@ -611,17 +630,17 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
# Sometimes new react-based page is served instead of old one that require
|
# Sometimes new react-based page is served instead of old one that require
|
||||||
# different config URL extraction approach (see
|
# different config URL extraction approach (see
|
||||||
# https://github.com/ytdl-org/youtube-dl/pull/7209)
|
# https://github.com/ytdl-org/youtube-dl/pull/7209)
|
||||||
vimeo_clip_page_config = self._search_regex(
|
page_config = self._parse_json(self._search_regex(
|
||||||
r'vimeo\.clip_page_config\s*=\s*({.+?});', webpage,
|
r'vimeo\.(?:clip|vod_title)_page_config\s*=\s*({.+?});',
|
||||||
'vimeo clip page config')
|
webpage, 'page config'), video_id)
|
||||||
page_config = self._parse_json(vimeo_clip_page_config, video_id)
|
|
||||||
config_url = page_config['player']['config_url']
|
config_url = page_config['player']['config_url']
|
||||||
cc_license = page_config.get('cc_license')
|
cc_license = page_config.get('cc_license')
|
||||||
timestamp = try_get(
|
timestamp = try_get(
|
||||||
page_config, lambda x: x['clip']['uploaded_on'],
|
page_config, lambda x: x['clip']['uploaded_on'],
|
||||||
compat_str)
|
compat_str)
|
||||||
config_json = self._download_webpage(config_url, video_id)
|
video_description = clean_html(dict_get(
|
||||||
config = json.loads(config_json)
|
page_config, ('description', 'description_html_escaped')))
|
||||||
|
config = self._download_json(config_url, video_id)
|
||||||
except RegexNotFoundError:
|
except RegexNotFoundError:
|
||||||
# For pro videos or player.vimeo.com urls
|
# For pro videos or player.vimeo.com urls
|
||||||
# We try to find out to which variable is assigned the config dic
|
# We try to find out to which variable is assigned the config dic
|
||||||
|
@ -675,14 +694,14 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
{'force_feature_id': True}), 'Vimeo')
|
{'force_feature_id': True}), 'Vimeo')
|
||||||
|
|
||||||
# Extract video description
|
# Extract video description
|
||||||
|
if not video_description:
|
||||||
video_description = self._html_search_regex(
|
video_description = self._html_search_regex(
|
||||||
r'(?s)<div\s+class="[^"]*description[^"]*"[^>]*>(.*?)</div>',
|
r'(?s)<div\s+class="[^"]*description[^"]*"[^>]*>(.*?)</div>',
|
||||||
webpage, 'description', default=None)
|
webpage, 'description', default=None)
|
||||||
if not video_description:
|
if not video_description:
|
||||||
video_description = self._html_search_meta(
|
video_description = self._html_search_meta(
|
||||||
'description', webpage, default=None)
|
'description', webpage, default=None)
|
||||||
if not video_description and mobj.group('pro'):
|
if not video_description and is_pro:
|
||||||
orig_webpage = self._download_webpage(
|
orig_webpage = self._download_webpage(
|
||||||
orig_url, video_id,
|
orig_url, video_id,
|
||||||
note='Downloading webpage for description',
|
note='Downloading webpage for description',
|
||||||
|
@ -690,7 +709,7 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
if orig_webpage:
|
if orig_webpage:
|
||||||
video_description = self._html_search_meta(
|
video_description = self._html_search_meta(
|
||||||
'description', orig_webpage, default=None)
|
'description', orig_webpage, default=None)
|
||||||
if not video_description and not mobj.group('player'):
|
if not video_description and not is_player:
|
||||||
self._downloader.report_warning('Cannot find video description')
|
self._downloader.report_warning('Cannot find video description')
|
||||||
|
|
||||||
# Extract upload date
|
# Extract upload date
|
||||||
|
@ -747,9 +766,9 @@ class VimeoIE(VimeoBaseInfoExtractor):
|
||||||
return info_dict
|
return info_dict
|
||||||
|
|
||||||
|
|
||||||
class VimeoOndemandIE(VimeoBaseInfoExtractor):
|
class VimeoOndemandIE(VimeoIE):
|
||||||
IE_NAME = 'vimeo:ondemand'
|
IE_NAME = 'vimeo:ondemand'
|
||||||
_VALID_URL = r'https?://(?:www\.)?vimeo\.com/ondemand/(?P<id>[^/?#&]+)'
|
_VALID_URL = r'https?://(?:www\.)?vimeo\.com/ondemand/([^/]+/)?(?P<id>[^/?#&]+)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
# ondemand video not available via https://vimeo.com/id
|
# ondemand video not available via https://vimeo.com/id
|
||||||
'url': 'https://vimeo.com/ondemand/20704',
|
'url': 'https://vimeo.com/ondemand/20704',
|
||||||
|
@ -761,24 +780,32 @@ class VimeoOndemandIE(VimeoBaseInfoExtractor):
|
||||||
'uploader': 'גם סרטים',
|
'uploader': 'גם סרטים',
|
||||||
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/gumfilms',
|
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/gumfilms',
|
||||||
'uploader_id': 'gumfilms',
|
'uploader_id': 'gumfilms',
|
||||||
|
'description': 'md5:4c027c965e439de4baab621e48b60791',
|
||||||
|
'upload_date': '20140906',
|
||||||
|
'timestamp': 1410032453,
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
'format': 'best[protocol=https]',
|
'format': 'best[protocol=https]',
|
||||||
},
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
}, {
|
}, {
|
||||||
# requires Referer to be passed along with og:video:url
|
# requires Referer to be passed along with og:video:url
|
||||||
'url': 'https://vimeo.com/ondemand/36938/126682985',
|
'url': 'https://vimeo.com/ondemand/36938/126682985',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': '126682985',
|
'id': '126584684',
|
||||||
'ext': 'mp4',
|
'ext': 'mp4',
|
||||||
'title': 'Rävlock, rätt läte på rätt plats',
|
'title': 'Rävlock, rätt läte på rätt plats',
|
||||||
'uploader': 'Lindroth & Norin',
|
'uploader': 'Lindroth & Norin',
|
||||||
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/user14430847',
|
'uploader_url': r're:https?://(?:www\.)?vimeo\.com/lindrothnorin',
|
||||||
'uploader_id': 'user14430847',
|
'uploader_id': 'lindrothnorin',
|
||||||
|
'description': 'md5:c3c46a90529612c8279fb6af803fc0df',
|
||||||
|
'upload_date': '20150502',
|
||||||
|
'timestamp': 1430586422,
|
||||||
},
|
},
|
||||||
'params': {
|
'params': {
|
||||||
'skip_download': True,
|
'skip_download': True,
|
||||||
},
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
}, {
|
}, {
|
||||||
'url': 'https://vimeo.com/ondemand/nazmaalik',
|
'url': 'https://vimeo.com/ondemand/nazmaalik',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
|
@ -790,16 +817,6 @@ class VimeoOndemandIE(VimeoBaseInfoExtractor):
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
}]
|
}]
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
video_id = self._match_id(url)
|
|
||||||
webpage = self._download_webpage(url, video_id)
|
|
||||||
return self.url_result(
|
|
||||||
# Some videos require Referer to be passed along with og:video:url
|
|
||||||
# similarly to generic vimeo embeds (e.g.
|
|
||||||
# https://vimeo.com/ondemand/36938/126682985).
|
|
||||||
VimeoIE._smuggle_referrer(self._og_search_video_url(webpage), url),
|
|
||||||
VimeoIE.ie_key())
|
|
||||||
|
|
||||||
|
|
||||||
class VimeoChannelIE(VimeoBaseInfoExtractor):
|
class VimeoChannelIE(VimeoBaseInfoExtractor):
|
||||||
IE_NAME = 'vimeo:channel'
|
IE_NAME = 'vimeo:channel'
|
||||||
|
@ -815,6 +832,7 @@ class VimeoChannelIE(VimeoBaseInfoExtractor):
|
||||||
},
|
},
|
||||||
'playlist_mincount': 25,
|
'playlist_mincount': 25,
|
||||||
}]
|
}]
|
||||||
|
_BASE_URL_TEMPL = 'https://vimeo.com/channels/%s'
|
||||||
|
|
||||||
def _page_url(self, base_url, pagenum):
|
def _page_url(self, base_url, pagenum):
|
||||||
return '%s/videos/page:%d/' % (base_url, pagenum)
|
return '%s/videos/page:%d/' % (base_url, pagenum)
|
||||||
|
@ -886,14 +904,13 @@ class VimeoChannelIE(VimeoBaseInfoExtractor):
|
||||||
return self.playlist_result(title_and_entries, list_id, list_title)
|
return self.playlist_result(title_and_entries, list_id, list_title)
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
mobj = re.match(self._VALID_URL, url)
|
channel_id = self._match_id(url)
|
||||||
channel_id = mobj.group('id')
|
return self._extract_videos(channel_id, self._BASE_URL_TEMPL % channel_id)
|
||||||
return self._extract_videos(channel_id, 'https://vimeo.com/channels/%s' % channel_id)
|
|
||||||
|
|
||||||
|
|
||||||
class VimeoUserIE(VimeoChannelIE):
|
class VimeoUserIE(VimeoChannelIE):
|
||||||
IE_NAME = 'vimeo:user'
|
IE_NAME = 'vimeo:user'
|
||||||
_VALID_URL = r'https://vimeo\.com/(?!(?:[0-9]+|watchlater)(?:$|[?#/]))(?P<name>[^/]+)(?:/videos|[#?]|$)'
|
_VALID_URL = r'https://vimeo\.com/(?!(?:[0-9]+|watchlater)(?:$|[?#/]))(?P<id>[^/]+)(?:/videos|[#?]|$)'
|
||||||
_TITLE_RE = r'<a[^>]+?class="user">([^<>]+?)</a>'
|
_TITLE_RE = r'<a[^>]+?class="user">([^<>]+?)</a>'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://vimeo.com/nkistudio/videos',
|
'url': 'https://vimeo.com/nkistudio/videos',
|
||||||
|
@ -903,11 +920,7 @@ class VimeoUserIE(VimeoChannelIE):
|
||||||
},
|
},
|
||||||
'playlist_mincount': 66,
|
'playlist_mincount': 66,
|
||||||
}]
|
}]
|
||||||
|
_BASE_URL_TEMPL = 'https://vimeo.com/%s'
|
||||||
def _real_extract(self, url):
|
|
||||||
mobj = re.match(self._VALID_URL, url)
|
|
||||||
name = mobj.group('name')
|
|
||||||
return self._extract_videos(name, 'https://vimeo.com/%s' % name)
|
|
||||||
|
|
||||||
|
|
||||||
class VimeoAlbumIE(VimeoChannelIE):
|
class VimeoAlbumIE(VimeoChannelIE):
|
||||||
|
@ -969,25 +982,18 @@ class VimeoAlbumIE(VimeoChannelIE):
|
||||||
r'<title>\s*(.+?)(?:\s+on Vimeo)?</title>', webpage, 'title', fatal=False))
|
r'<title>\s*(.+?)(?:\s+on Vimeo)?</title>', webpage, 'title', fatal=False))
|
||||||
|
|
||||||
|
|
||||||
class VimeoGroupsIE(VimeoAlbumIE):
|
class VimeoGroupsIE(VimeoChannelIE):
|
||||||
IE_NAME = 'vimeo:group'
|
IE_NAME = 'vimeo:group'
|
||||||
_VALID_URL = r'https://vimeo\.com/groups/(?P<name>[^/]+)(?:/(?!videos?/\d+)|$)'
|
_VALID_URL = r'https://vimeo\.com/groups/(?P<id>[^/]+)(?:/(?!videos?/\d+)|$)'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'https://vimeo.com/groups/rolexawards',
|
'url': 'https://vimeo.com/groups/kattykay',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
'id': 'rolexawards',
|
'id': 'kattykay',
|
||||||
'title': 'Rolex Awards for Enterprise',
|
'title': 'Katty Kay',
|
||||||
},
|
},
|
||||||
'playlist_mincount': 73,
|
'playlist_mincount': 27,
|
||||||
}]
|
}]
|
||||||
|
_BASE_URL_TEMPL = 'https://vimeo.com/groups/%s'
|
||||||
def _extract_list_title(self, webpage):
|
|
||||||
return self._og_search_title(webpage, fatal=False)
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
|
||||||
mobj = re.match(self._VALID_URL, url)
|
|
||||||
name = mobj.group('name')
|
|
||||||
return self._extract_videos(name, 'https://vimeo.com/groups/%s' % name)
|
|
||||||
|
|
||||||
|
|
||||||
class VimeoReviewIE(VimeoBaseInfoExtractor):
|
class VimeoReviewIE(VimeoBaseInfoExtractor):
|
||||||
|
@ -1003,7 +1009,9 @@ class VimeoReviewIE(VimeoBaseInfoExtractor):
|
||||||
'title': "DICK HARDWICK 'Comedian'",
|
'title': "DICK HARDWICK 'Comedian'",
|
||||||
'uploader': 'Richard Hardwick',
|
'uploader': 'Richard Hardwick',
|
||||||
'uploader_id': 'user21297594',
|
'uploader_id': 'user21297594',
|
||||||
}
|
'description': "Comedian Dick Hardwick's five minute demo filmed in front of a live theater audience.\nEdit by Doug Mattocks",
|
||||||
|
},
|
||||||
|
'expected_warnings': ['Unable to download JSON metadata'],
|
||||||
}, {
|
}, {
|
||||||
'note': 'video player needs Referer',
|
'note': 'video player needs Referer',
|
||||||
'url': 'https://vimeo.com/user22258446/review/91613211/13f927e053',
|
'url': 'https://vimeo.com/user22258446/review/91613211/13f927e053',
|
||||||
|
@ -1016,7 +1024,8 @@ class VimeoReviewIE(VimeoBaseInfoExtractor):
|
||||||
'duration': 2773,
|
'duration': 2773,
|
||||||
'thumbnail': r're:^https?://.*\.jpg$',
|
'thumbnail': r're:^https?://.*\.jpg$',
|
||||||
'uploader_id': 'user22258446',
|
'uploader_id': 'user22258446',
|
||||||
}
|
},
|
||||||
|
'skip': 'video gone',
|
||||||
}, {
|
}, {
|
||||||
'note': 'Password protected',
|
'note': 'Password protected',
|
||||||
'url': 'https://vimeo.com/user37284429/review/138823582/c4d865efde',
|
'url': 'https://vimeo.com/user37284429/review/138823582/c4d865efde',
|
||||||
|
@ -1036,32 +1045,20 @@ class VimeoReviewIE(VimeoBaseInfoExtractor):
|
||||||
def _real_initialize(self):
|
def _real_initialize(self):
|
||||||
self._login()
|
self._login()
|
||||||
|
|
||||||
def _get_config_url(self, webpage_url, video_id, video_password_verified=False):
|
|
||||||
webpage = self._download_webpage(webpage_url, video_id)
|
|
||||||
config_url = self._html_search_regex(
|
|
||||||
r'data-config-url=(["\'])(?P<url>(?:(?!\1).)+)\1', webpage,
|
|
||||||
'config URL', default=None, group='url')
|
|
||||||
if not config_url:
|
|
||||||
data = self._parse_json(self._search_regex(
|
|
||||||
r'window\s*=\s*_extend\(window,\s*({.+?})\);', webpage, 'data',
|
|
||||||
default=NO_DEFAULT if video_password_verified else '{}'), video_id)
|
|
||||||
config = data.get('vimeo_esi', {}).get('config', {})
|
|
||||||
config_url = config.get('configUrl') or try_get(config, lambda x: x['clipData']['configUrl'])
|
|
||||||
if config_url is None:
|
|
||||||
self._verify_video_password(webpage_url, video_id, webpage)
|
|
||||||
config_url = self._get_config_url(
|
|
||||||
webpage_url, video_id, video_password_verified=True)
|
|
||||||
return config_url
|
|
||||||
|
|
||||||
def _real_extract(self, url):
|
def _real_extract(self, url):
|
||||||
page_url, video_id = re.match(self._VALID_URL, url).groups()
|
page_url, video_id = re.match(self._VALID_URL, url).groups()
|
||||||
config_url = self._get_config_url(url, video_id)
|
clip_data = self._download_json(
|
||||||
|
page_url.replace('/review/', '/review/data/'),
|
||||||
|
video_id)['clipData']
|
||||||
|
config_url = clip_data['configUrl']
|
||||||
config = self._download_json(config_url, video_id)
|
config = self._download_json(config_url, video_id)
|
||||||
info_dict = self._parse_config(config, video_id)
|
info_dict = self._parse_config(config, video_id)
|
||||||
source_format = self._extract_original_format(page_url, video_id)
|
source_format = self._extract_original_format(
|
||||||
|
page_url + '/action', video_id)
|
||||||
if source_format:
|
if source_format:
|
||||||
info_dict['formats'].append(source_format)
|
info_dict['formats'].append(source_format)
|
||||||
self._vimeo_sort_formats(info_dict['formats'])
|
self._vimeo_sort_formats(info_dict['formats'])
|
||||||
|
info_dict['description'] = clean_html(clip_data.get('description'))
|
||||||
return info_dict
|
return info_dict
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue