mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-08-14 00:18:31 +00:00
Merge d336e7474b
into f2919bd28e
This commit is contained in:
commit
1cd566983d
@ -152,7 +152,6 @@
|
||||
ARDBetaMediathekIE,
|
||||
ARDMediathekCollectionIE,
|
||||
)
|
||||
from .arkena import ArkenaIE
|
||||
from .arnes import ArnesIE
|
||||
from .art19 import (
|
||||
Art19IE,
|
||||
@ -1187,15 +1186,7 @@
|
||||
from .moviezine import MoviezineIE
|
||||
from .movingimage import MovingImageIE
|
||||
from .msn import MSNIE
|
||||
from .mtv import (
|
||||
MTVDEIE,
|
||||
MTVIE,
|
||||
MTVItaliaIE,
|
||||
MTVItaliaProgrammaIE,
|
||||
MTVJapanIE,
|
||||
MTVServicesEmbeddedIE,
|
||||
MTVVideoIE,
|
||||
)
|
||||
from .mtv import MTVIE
|
||||
from .muenchentv import MuenchenTVIE
|
||||
from .murrtube import (
|
||||
MurrtubeIE,
|
||||
@ -1548,7 +1539,6 @@
|
||||
PixivSketchIE,
|
||||
PixivSketchUserIE,
|
||||
)
|
||||
from .pladform import PladformIE
|
||||
from .planetmarathi import PlanetMarathiIE
|
||||
from .platzi import (
|
||||
PlatziCourseIE,
|
||||
@ -1947,10 +1937,6 @@
|
||||
SpankBangPlaylistIE,
|
||||
)
|
||||
from .spiegel import SpiegelIE
|
||||
from .spike import (
|
||||
BellatorIE,
|
||||
ParamountNetworkIE,
|
||||
)
|
||||
from .sport5 import Sport5IE
|
||||
from .sportbox import SportBoxIE
|
||||
from .sportdeutschland import SportDeutschlandIE
|
||||
@ -2215,7 +2201,6 @@
|
||||
from .tver import TVerIE
|
||||
from .tvigle import TvigleIE
|
||||
from .tviplayer import TVIPlayerIE
|
||||
from .tvland import TVLandIE
|
||||
from .tvn24 import TVN24IE
|
||||
from .tvnoe import TVNoeIE
|
||||
from .tvopengr import (
|
||||
@ -2313,10 +2298,6 @@
|
||||
from .vbox7 import Vbox7IE
|
||||
from .veo import VeoIE
|
||||
from .vesti import VestiIE
|
||||
from .vevo import (
|
||||
VevoIE,
|
||||
VevoPlaylistIE,
|
||||
)
|
||||
from .vgtv import (
|
||||
VGTVIE,
|
||||
BTArticleIE,
|
||||
|
@ -1,150 +0,0 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
ExtractorError,
|
||||
float_or_none,
|
||||
int_or_none,
|
||||
parse_iso8601,
|
||||
parse_qs,
|
||||
try_get,
|
||||
)
|
||||
|
||||
|
||||
class ArkenaIE(InfoExtractor):
|
||||
_VALID_URL = r'''(?x)
|
||||
https?://
|
||||
(?:
|
||||
video\.(?:arkena|qbrick)\.com/play2/embed/player\?|
|
||||
play\.arkena\.com/(?:config|embed)/avp/v\d/player/media/(?P<id>[^/]+)/[^/]+/(?P<account_id>\d+)
|
||||
)
|
||||
'''
|
||||
# See https://support.arkena.com/display/PLAY/Ways+to+embed+your+video
|
||||
_EMBED_REGEX = [r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//play\.arkena\.com/embed/avp/.+?)\1']
|
||||
_TESTS = [{
|
||||
'url': 'https://video.qbrick.com/play2/embed/player?accountId=1034090&mediaId=d8ab4607-00090107-aab86310',
|
||||
'md5': '97f117754e5f3c020f5f26da4a44ebaf',
|
||||
'info_dict': {
|
||||
'id': 'd8ab4607-00090107-aab86310',
|
||||
'ext': 'mp4',
|
||||
'title': 'EM_HT20_117_roslund_v2.mp4',
|
||||
'timestamp': 1608285912,
|
||||
'upload_date': '20201218',
|
||||
'duration': 1429.162667,
|
||||
'subtitles': {
|
||||
'sv': 'count:3',
|
||||
},
|
||||
},
|
||||
}, {
|
||||
'url': 'https://play.arkena.com/embed/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://play.arkena.com/config/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411/?callbackMethod=jQuery1111023664739129262213_1469227693893',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'http://play.arkena.com/config/avp/v1/player/media/327336/darkmatter/131064/?callbackMethod=jQuery1111002221189684892677_1469227595972',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'http://play.arkena.com/embed/avp/v1/player/media/327336/darkmatter/131064/',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'http://video.arkena.com/play2/embed/player?accountId=472718&mediaId=35763b3b-00090078-bf604299&pageStyling=styled',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = self._match_valid_url(url)
|
||||
video_id = mobj.group('id')
|
||||
account_id = mobj.group('account_id')
|
||||
|
||||
# Handle http://video.arkena.com/play2/embed/player URL
|
||||
if not video_id:
|
||||
qs = parse_qs(url)
|
||||
video_id = qs.get('mediaId', [None])[0]
|
||||
account_id = qs.get('accountId', [None])[0]
|
||||
if not video_id or not account_id:
|
||||
raise ExtractorError('Invalid URL', expected=True)
|
||||
|
||||
media = self._download_json(
|
||||
f'https://video.qbrick.com/api/v1/public/accounts/{account_id}/medias/{video_id}',
|
||||
video_id, query={
|
||||
# https://video.qbrick.com/docs/api/examples/library-api.html
|
||||
'fields': 'asset/resources/*/renditions/*(height,id,language,links/*(href,mimeType),type,size,videos/*(audios/*(codec,sampleRate),bitrate,codec,duration,height,width),width),created,metadata/*(title,description),tags',
|
||||
})
|
||||
metadata = media.get('metadata') or {}
|
||||
title = metadata['title']
|
||||
|
||||
duration = None
|
||||
formats = []
|
||||
thumbnails = []
|
||||
subtitles = {}
|
||||
for resource in media['asset']['resources']:
|
||||
for rendition in (resource.get('renditions') or []):
|
||||
rendition_type = rendition.get('type')
|
||||
for i, link in enumerate(rendition.get('links') or []):
|
||||
href = link.get('href')
|
||||
if not href:
|
||||
continue
|
||||
if rendition_type == 'image':
|
||||
thumbnails.append({
|
||||
'filesize': int_or_none(rendition.get('size')),
|
||||
'height': int_or_none(rendition.get('height')),
|
||||
'id': rendition.get('id'),
|
||||
'url': href,
|
||||
'width': int_or_none(rendition.get('width')),
|
||||
})
|
||||
elif rendition_type == 'subtitle':
|
||||
subtitles.setdefault(rendition.get('language') or 'en', []).append({
|
||||
'url': href,
|
||||
})
|
||||
elif rendition_type == 'video':
|
||||
f = {
|
||||
'filesize': int_or_none(rendition.get('size')),
|
||||
'format_id': rendition.get('id'),
|
||||
'url': href,
|
||||
}
|
||||
video = try_get(rendition, lambda x: x['videos'][i], dict)
|
||||
if video:
|
||||
if not duration:
|
||||
duration = float_or_none(video.get('duration'))
|
||||
f.update({
|
||||
'height': int_or_none(video.get('height')),
|
||||
'tbr': int_or_none(video.get('bitrate'), 1000),
|
||||
'vcodec': video.get('codec'),
|
||||
'width': int_or_none(video.get('width')),
|
||||
})
|
||||
audio = try_get(video, lambda x: x['audios'][0], dict)
|
||||
if audio:
|
||||
f.update({
|
||||
'acodec': audio.get('codec'),
|
||||
'asr': int_or_none(audio.get('sampleRate')),
|
||||
})
|
||||
formats.append(f)
|
||||
elif rendition_type == 'index':
|
||||
mime_type = link.get('mimeType')
|
||||
if mime_type == 'application/smil+xml':
|
||||
formats.extend(self._extract_smil_formats(
|
||||
href, video_id, fatal=False))
|
||||
elif mime_type == 'application/x-mpegURL':
|
||||
formats.extend(self._extract_m3u8_formats(
|
||||
href, video_id, 'mp4', 'm3u8_native',
|
||||
m3u8_id='hls', fatal=False))
|
||||
elif mime_type == 'application/hds+xml':
|
||||
formats.extend(self._extract_f4m_formats(
|
||||
href, video_id, f4m_id='hds', fatal=False))
|
||||
elif mime_type == 'application/dash+xml':
|
||||
formats.extend(self._extract_mpd_formats(
|
||||
href, video_id, mpd_id='dash', fatal=False))
|
||||
elif mime_type == 'application/vnd.ms-sstr+xml':
|
||||
formats.extend(self._extract_ism_formats(
|
||||
href, video_id, ism_id='mss', fatal=False))
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'title': title,
|
||||
'description': metadata.get('description'),
|
||||
'timestamp': parse_iso8601(media.get('created')),
|
||||
'thumbnails': thumbnails,
|
||||
'subtitles': subtitles,
|
||||
'duration': duration,
|
||||
'tags': media.get('tags'),
|
||||
'formats': formats,
|
||||
}
|
@ -3107,7 +3107,6 @@ def location_key(location):
|
||||
else:
|
||||
# $Number*$ or $Time$ in media template with S list available
|
||||
# Example $Number*$: http://www.svtplay.se/klipp/9023742/stopptid-om-bjorn-borg
|
||||
# Example $Time$: https://play.arkena.com/embed/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411
|
||||
representation_ms_info['fragments'] = []
|
||||
segment_time = 0
|
||||
segment_d = None
|
||||
|
@ -171,17 +171,6 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
||||
'view_count': int,
|
||||
},
|
||||
'skip': 'video gone',
|
||||
}, {
|
||||
# Vevo video
|
||||
'url': 'http://www.dailymotion.com/video/x149uew_katy-perry-roar-official_musi',
|
||||
'info_dict': {
|
||||
'title': 'Roar (Official)',
|
||||
'id': 'USUV71301934',
|
||||
'ext': 'mp4',
|
||||
'uploader': 'Katy Perry',
|
||||
'upload_date': '20130905',
|
||||
},
|
||||
'skip': 'Invalid URL',
|
||||
}, {
|
||||
# age-restricted video
|
||||
'url': 'http://www.dailymotion.com/video/xyh2zz_leanna-decker-cyber-girl-of-the-year-desires-nude-playboy-plus_redband',
|
||||
|
@ -90,10 +90,6 @@ def _real_extract(self, url):
|
||||
webpage, 'embed data'), video_id)
|
||||
video_data = page_data['video']
|
||||
|
||||
for external in video_data.get('externals', []):
|
||||
if external.get('source') == 'vevo':
|
||||
return self.url_result('vevo:' + external['data_id'], 'Vevo')
|
||||
|
||||
video_id = video_data['id']
|
||||
title = video_data['title']
|
||||
|
||||
|
@ -1,8 +1,8 @@
|
||||
from .arkena import ArkenaIE
|
||||
from .common import InfoExtractor
|
||||
|
||||
|
||||
class LcpPlayIE(ArkenaIE): # XXX: Do not subclass from concrete IE
|
||||
class LcpPlayIE(InfoExtractor):
|
||||
_WORKING = False
|
||||
_VALID_URL = r'https?://play\.lcp\.fr/embed/(?P<id>[^/]+)/(?P<account_id>[^/]+)/[^/]+/[^/]+'
|
||||
_TESTS = [{
|
||||
'url': 'http://play.lcp.fr/embed/327336/131064/darkmatter/0',
|
||||
@ -24,21 +24,6 @@ class LcpIE(InfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?lcp\.fr/(?:[^/]+/)*(?P<id>[^/]+)'
|
||||
|
||||
_TESTS = [{
|
||||
# arkena embed
|
||||
'url': 'http://www.lcp.fr/la-politique-en-video/schwartzenberg-prg-preconise-francois-hollande-de-participer-une-primaire',
|
||||
'md5': 'b8bd9298542929c06c1c15788b1f277a',
|
||||
'info_dict': {
|
||||
'id': 'd56d03e9',
|
||||
'ext': 'mp4',
|
||||
'title': 'Schwartzenberg (PRG) préconise à François Hollande de participer à une primaire à gauche',
|
||||
'description': 'md5:96ad55009548da9dea19f4120c6c16a8',
|
||||
'timestamp': 1456488895,
|
||||
'upload_date': '20160226',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}, {
|
||||
# dailymotion live stream
|
||||
'url': 'http://www.lcp.fr/le-direct',
|
||||
'info_dict': {
|
||||
|
@ -322,37 +322,6 @@ def _real_extract(self, url):
|
||||
return self._get_videos_info(mgid, url=url)
|
||||
|
||||
|
||||
class MTVServicesEmbeddedIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'mtvservices:embedded'
|
||||
_VALID_URL = r'https?://media\.mtvnservices\.com/embed/(?P<mgid>.+?)(\?|/|$)'
|
||||
_EMBED_REGEX = [r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?:)?//media\.mtvnservices\.com/embed/.+?)\1']
|
||||
|
||||
_TEST = {
|
||||
# From http://www.thewrap.com/peter-dinklage-sums-up-game-of-thrones-in-45-seconds-video/
|
||||
'url': 'http://media.mtvnservices.com/embed/mgid:uma:video:mtv.com:1043906/cp~vid%3D1043906%26uri%3Dmgid%3Auma%3Avideo%3Amtv.com%3A1043906',
|
||||
'md5': 'cb349b21a7897164cede95bd7bf3fbb9',
|
||||
'info_dict': {
|
||||
'id': '1043906',
|
||||
'ext': 'mp4',
|
||||
'title': 'Peter Dinklage Sums Up \'Game Of Thrones\' In 45 Seconds',
|
||||
'description': '"Sexy sexy sexy, stabby stabby stabby, beautiful language," says Peter Dinklage as he tries summarizing "Game of Thrones" in under a minute.',
|
||||
'timestamp': 1400126400,
|
||||
'upload_date': '20140515',
|
||||
},
|
||||
}
|
||||
|
||||
def _get_feed_url(self, uri, url=None):
|
||||
video_id = self._id_from_uri(uri)
|
||||
config = self._download_json(
|
||||
f'http://media.mtvnservices.com/pmt/e1/access/index.html?uri={uri}&configtype=edge', video_id)
|
||||
return self._remove_template_parameter(config['feedWithQueryParams'])
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = self._match_valid_url(url)
|
||||
mgid = mobj.group('mgid')
|
||||
return self._get_videos_info(mgid)
|
||||
|
||||
|
||||
class MTVIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'mtv'
|
||||
_VALID_URL = r'https?://(?:www\.)?mtv\.com/(?:video-clips|(?:full-)?episodes)/(?P<id>[^/?#.]+)'
|
||||
@ -376,277 +345,3 @@ class MTVIE(MTVServicesInfoExtractor):
|
||||
'url': 'http://www.mtv.com/episodes/g8xu7q/teen-mom-2-breaking-the-wall-season-7-ep-713',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
|
||||
class MTVJapanIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'mtvjapan'
|
||||
_VALID_URL = r'https?://(?:www\.)?mtvjapan\.com/videos/(?P<id>[0-9a-z]+)'
|
||||
|
||||
_TEST = {
|
||||
'url': 'http://www.mtvjapan.com/videos/prayht/fresh-info-cadillac-escalade',
|
||||
'info_dict': {
|
||||
'id': 'bc01da03-6fe5-4284-8880-f291f4e368f5',
|
||||
'ext': 'mp4',
|
||||
'title': '【Fresh Info】Cadillac ESCALADE Sport Edition',
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}
|
||||
_GEO_COUNTRIES = ['JP']
|
||||
_FEED_URL = 'http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed'
|
||||
|
||||
def _get_feed_query(self, uri):
|
||||
return {
|
||||
'arcEp': 'mtvjapan.com',
|
||||
'mgid': uri,
|
||||
}
|
||||
|
||||
|
||||
class MTVVideoIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'mtv:video'
|
||||
_VALID_URL = r'''(?x)^https?://
|
||||
(?:(?:www\.)?mtv\.com/videos/.+?/(?P<videoid>[0-9]+)/[^/]+$|
|
||||
m\.mtv\.com/videos/video\.rbml\?.*?id=(?P<mgid>[^&]+))'''
|
||||
|
||||
_FEED_URL = 'http://www.mtv.com/player/embed/AS3/rss/'
|
||||
|
||||
_TESTS = [
|
||||
{
|
||||
'url': 'http://www.mtv.com/videos/misc/853555/ours-vh1-storytellers.jhtml',
|
||||
'md5': '850f3f143316b1e71fa56a4edfd6e0f8',
|
||||
'info_dict': {
|
||||
'id': '853555',
|
||||
'ext': 'mp4',
|
||||
'title': 'Taylor Swift - "Ours (VH1 Storytellers)"',
|
||||
'description': 'Album: Taylor Swift performs "Ours" for VH1 Storytellers at Harvey Mudd College.',
|
||||
'timestamp': 1352610000,
|
||||
'upload_date': '20121111',
|
||||
},
|
||||
},
|
||||
]
|
||||
|
||||
def _get_thumbnail_url(self, uri, itemdoc):
|
||||
return 'http://mtv.mtvnimages.com/uri/' + uri
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = self._match_valid_url(url)
|
||||
video_id = mobj.group('videoid')
|
||||
uri = mobj.groupdict().get('mgid')
|
||||
if uri is None:
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
|
||||
# Some videos come from Vevo.com
|
||||
m_vevo = re.search(
|
||||
r'(?s)isVevoVideo = true;.*?vevoVideoId = "(.*?)";', webpage)
|
||||
if m_vevo:
|
||||
vevo_id = m_vevo.group(1)
|
||||
self.to_screen(f'Vevo video detected: {vevo_id}')
|
||||
return self.url_result(f'vevo:{vevo_id}', ie='Vevo')
|
||||
|
||||
uri = self._html_search_regex(r'/uri/(.*?)\?', webpage, 'uri')
|
||||
return self._get_videos_info(uri)
|
||||
|
||||
|
||||
class MTVDEIE(MTVServicesInfoExtractor):
|
||||
_WORKING = False
|
||||
IE_NAME = 'mtv.de'
|
||||
_VALID_URL = r'https?://(?:www\.)?mtv\.de/(?:musik/videoclips|folgen|news)/(?P<id>[0-9a-z]+)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.mtv.de/musik/videoclips/2gpnv7/Traum',
|
||||
'info_dict': {
|
||||
'id': 'd5d472bc-f5b7-11e5-bffd-a4badb20dab5',
|
||||
'ext': 'mp4',
|
||||
'title': 'Traum',
|
||||
'description': 'Traum',
|
||||
},
|
||||
'params': {
|
||||
# rtmp download
|
||||
'skip_download': True,
|
||||
},
|
||||
'skip': 'Blocked at Travis CI',
|
||||
}, {
|
||||
# mediagen URL without query (e.g. http://videos.mtvnn.com/mediagen/e865da714c166d18d6f80893195fcb97)
|
||||
'url': 'http://www.mtv.de/folgen/6b1ylu/teen-mom-2-enthuellungen-S5-F1',
|
||||
'info_dict': {
|
||||
'id': '1e5a878b-31c5-11e7-a442-0e40cf2fc285',
|
||||
'ext': 'mp4',
|
||||
'title': 'Teen Mom 2',
|
||||
'description': 'md5:dc65e357ef7e1085ed53e9e9d83146a7',
|
||||
},
|
||||
'params': {
|
||||
# rtmp download
|
||||
'skip_download': True,
|
||||
},
|
||||
'skip': 'Blocked at Travis CI',
|
||||
}, {
|
||||
'url': 'http://www.mtv.de/news/glolix/77491-mtv-movies-spotlight--pixels--teil-3',
|
||||
'info_dict': {
|
||||
'id': 'local_playlist-4e760566473c4c8c5344',
|
||||
'ext': 'mp4',
|
||||
'title': 'Article_mtv-movies-spotlight-pixels-teil-3_short-clips_part1',
|
||||
'description': 'MTV Movies Supercut',
|
||||
},
|
||||
'params': {
|
||||
# rtmp download
|
||||
'skip_download': True,
|
||||
},
|
||||
'skip': 'Das Video kann zur Zeit nicht abgespielt werden.',
|
||||
}]
|
||||
_GEO_COUNTRIES = ['DE']
|
||||
_FEED_URL = 'http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed'
|
||||
|
||||
def _get_feed_query(self, uri):
|
||||
return {
|
||||
'arcEp': 'mtv.de',
|
||||
'mgid': uri,
|
||||
}
|
||||
|
||||
|
||||
class MTVItaliaIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'mtv.it'
|
||||
_VALID_URL = r'https?://(?:www\.)?mtv\.it/(?:episodi|video|musica)/(?P<id>[0-9a-z]+)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.mtv.it/episodi/24bqab/mario-una-serie-di-maccio-capatonda-cavoli-amario-episodio-completo-S1-E1',
|
||||
'info_dict': {
|
||||
'id': '0f0fc78e-45fc-4cce-8f24-971c25477530',
|
||||
'ext': 'mp4',
|
||||
'title': 'Cavoli amario (episodio completo)',
|
||||
'description': 'md5:4962bccea8fed5b7c03b295ae1340660',
|
||||
'series': 'Mario - Una Serie Di Maccio Capatonda',
|
||||
'season_number': 1,
|
||||
'episode_number': 1,
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}]
|
||||
_GEO_COUNTRIES = ['IT']
|
||||
_FEED_URL = 'http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed'
|
||||
|
||||
def _get_feed_query(self, uri):
|
||||
return {
|
||||
'arcEp': 'mtv.it',
|
||||
'mgid': uri,
|
||||
}
|
||||
|
||||
|
||||
class MTVItaliaProgrammaIE(MTVItaliaIE): # XXX: Do not subclass from concrete IE
|
||||
IE_NAME = 'mtv.it:programma'
|
||||
_VALID_URL = r'https?://(?:www\.)?mtv\.it/(?:programmi|playlist)/(?P<id>[0-9a-z]+)'
|
||||
_TESTS = [{
|
||||
# program page: general
|
||||
'url': 'http://www.mtv.it/programmi/s2rppv/mario-una-serie-di-maccio-capatonda',
|
||||
'info_dict': {
|
||||
'id': 'a6f155bc-8220-4640-aa43-9b95f64ffa3d',
|
||||
'title': 'Mario - Una Serie Di Maccio Capatonda',
|
||||
'description': 'md5:72fbffe1f77ccf4e90757dd4e3216153',
|
||||
},
|
||||
'playlist_count': 2,
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}, {
|
||||
# program page: specific season
|
||||
'url': 'http://www.mtv.it/programmi/d9ncjf/mario-una-serie-di-maccio-capatonda-S2',
|
||||
'info_dict': {
|
||||
'id': '4deeb5d8-f272-490c-bde2-ff8d261c6dd1',
|
||||
'title': 'Mario - Una Serie Di Maccio Capatonda - Stagione 2',
|
||||
},
|
||||
'playlist_count': 34,
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}, {
|
||||
# playlist page + redirect
|
||||
'url': 'http://www.mtv.it/playlist/sexy-videos/ilctal',
|
||||
'info_dict': {
|
||||
'id': 'dee8f9ee-756d-493b-bf37-16d1d2783359',
|
||||
'title': 'Sexy Videos',
|
||||
},
|
||||
'playlist_mincount': 145,
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}]
|
||||
_GEO_COUNTRIES = ['IT']
|
||||
_FEED_URL = 'http://www.mtv.it/feeds/triforce/manifest/v8'
|
||||
|
||||
def _get_entries(self, title, url):
|
||||
while True:
|
||||
pg = self._search_regex(r'/(\d+)$', url, 'entries', '1')
|
||||
entries = self._download_json(url, title, f'page {pg}')
|
||||
url = try_get(
|
||||
entries, lambda x: x['result']['nextPageURL'], str)
|
||||
entries = try_get(
|
||||
entries, (
|
||||
lambda x: x['result']['data']['items'],
|
||||
lambda x: x['result']['data']['seasons']),
|
||||
list)
|
||||
for entry in entries or []:
|
||||
if entry.get('canonicalURL'):
|
||||
yield self.url_result(entry['canonicalURL'])
|
||||
if not url:
|
||||
break
|
||||
|
||||
def _real_extract(self, url):
|
||||
query = {'url': url}
|
||||
info_url = update_url_query(self._FEED_URL, query)
|
||||
video_id = self._match_id(url)
|
||||
info = self._download_json(info_url, video_id).get('manifest')
|
||||
|
||||
redirect = try_get(
|
||||
info, lambda x: x['newLocation']['url'], str)
|
||||
if redirect:
|
||||
return self.url_result(redirect)
|
||||
|
||||
title = info.get('title')
|
||||
video_id = try_get(
|
||||
info, lambda x: x['reporting']['itemId'], str)
|
||||
parent_id = try_get(
|
||||
info, lambda x: x['reporting']['parentId'], str)
|
||||
|
||||
playlist_url = current_url = None
|
||||
for z in (info.get('zones') or {}).values():
|
||||
if z.get('moduleName') in ('INTL_M304', 'INTL_M209'):
|
||||
info_url = z.get('feed')
|
||||
if z.get('moduleName') in ('INTL_M308', 'INTL_M317'):
|
||||
playlist_url = playlist_url or z.get('feed')
|
||||
if z.get('moduleName') in ('INTL_M300',):
|
||||
current_url = current_url or z.get('feed')
|
||||
|
||||
if not info_url:
|
||||
raise ExtractorError('No info found')
|
||||
|
||||
if video_id == parent_id:
|
||||
video_id = self._search_regex(
|
||||
r'([^\/]+)/[^\/]+$', info_url, 'video_id')
|
||||
|
||||
info = self._download_json(info_url, video_id, 'Show infos')
|
||||
info = try_get(info, lambda x: x['result']['data'], dict)
|
||||
title = title or try_get(
|
||||
info, (
|
||||
lambda x: x['title'],
|
||||
lambda x: x['headline']),
|
||||
str)
|
||||
description = try_get(info, lambda x: x['content'], str)
|
||||
|
||||
if current_url:
|
||||
season = try_get(
|
||||
self._download_json(playlist_url, video_id, 'Seasons info'),
|
||||
lambda x: x['result']['data'], dict)
|
||||
current = try_get(
|
||||
season, lambda x: x['currentSeason'], str)
|
||||
seasons = try_get(
|
||||
season, lambda x: x['seasons'], list) or []
|
||||
|
||||
if current in [s.get('eTitle') for s in seasons]:
|
||||
playlist_url = current_url
|
||||
|
||||
title = re.sub(
|
||||
r'[-|]\s*(?:mtv\s*italia|programma|playlist)',
|
||||
'', title, flags=re.IGNORECASE).strip()
|
||||
|
||||
return self.playlist_result(
|
||||
self._get_entries(title, playlist_url),
|
||||
video_id, title, description)
|
||||
|
@ -111,12 +111,8 @@ def search_data(name):
|
||||
search_data('stream-url'), search_data('hls-stream-url'),
|
||||
search_data('http-stream-url'))
|
||||
if not formats:
|
||||
vevo_id = search_data('vevo-id')
|
||||
youtube_id = search_data('youtube-id')
|
||||
if vevo_id:
|
||||
self.to_screen(f'Vevo video detected: {vevo_id}')
|
||||
return self.url_result(f'vevo:{vevo_id}', ie='Vevo')
|
||||
elif youtube_id:
|
||||
if youtube_id:
|
||||
self.to_screen(f'Youtube video detected: {youtube_id}')
|
||||
return self.url_result(youtube_id, ie='Youtube')
|
||||
else:
|
||||
|
@ -352,14 +352,6 @@ def _extract_desktop(self, url):
|
||||
'subtitles': subtitles,
|
||||
}
|
||||
|
||||
# pladform
|
||||
if provider == 'OPEN_GRAPH':
|
||||
info.update({
|
||||
'_type': 'url_transparent',
|
||||
'url': movie['contentId'],
|
||||
})
|
||||
return info
|
||||
|
||||
if provider == 'USER_YOUTUBE':
|
||||
info.update({
|
||||
'_type': 'url_transparent',
|
||||
|
@ -1,135 +0,0 @@
|
||||
from .common import InfoExtractor
|
||||
from ..utils import (
|
||||
ExtractorError,
|
||||
determine_ext,
|
||||
int_or_none,
|
||||
parse_qs,
|
||||
qualities,
|
||||
xpath_text,
|
||||
)
|
||||
|
||||
|
||||
class PladformIE(InfoExtractor):
|
||||
_VALID_URL = r'''(?x)
|
||||
https?://
|
||||
(?:
|
||||
(?:
|
||||
out\.pladform\.ru/player|
|
||||
static\.pladform\.ru/player\.swf
|
||||
)
|
||||
\?.*\bvideoid=|
|
||||
video\.pladform\.ru/catalog/video/videoid/
|
||||
)
|
||||
(?P<id>\d+)
|
||||
'''
|
||||
_EMBED_REGEX = [r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//out\.pladform\.ru/player\?.+?)\1']
|
||||
_TESTS = [{
|
||||
'url': 'http://out.pladform.ru/player?pl=18079&type=html5&videoid=100231282',
|
||||
'info_dict': {
|
||||
'id': '6216d548e755edae6e8280667d774791',
|
||||
'ext': 'mp4',
|
||||
'timestamp': 1406117012,
|
||||
'title': 'Гарик Мартиросян и Гарик Харламов - Кастинг на концерт ко Дню милиции',
|
||||
'age_limit': 0,
|
||||
'upload_date': '20140723',
|
||||
'thumbnail': str,
|
||||
'view_count': int,
|
||||
'description': str,
|
||||
'uploader_id': '12082',
|
||||
'uploader': 'Comedy Club',
|
||||
'duration': 367,
|
||||
},
|
||||
'expected_warnings': ['HTTP Error 404: Not Found'],
|
||||
}, {
|
||||
'url': 'https://out.pladform.ru/player?pl=64471&videoid=3777899&vk_puid15=0&vk_puid34=0',
|
||||
'md5': '53362fac3a27352da20fa2803cc5cd6f',
|
||||
'info_dict': {
|
||||
'id': '3777899',
|
||||
'ext': 'mp4',
|
||||
'title': 'СТУДИЯ СОЮЗ • Шоу Студия Союз, 24 выпуск (01.02.2018) Нурлан Сабуров и Слава Комиссаренко',
|
||||
'description': 'md5:05140e8bf1b7e2d46e7ba140be57fd95',
|
||||
'thumbnail': r're:^https?://.*\.jpg$',
|
||||
'duration': 3190,
|
||||
},
|
||||
}, {
|
||||
'url': 'http://static.pladform.ru/player.swf?pl=21469&videoid=100183293&vkcid=0',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'http://video.pladform.ru/catalog/video/videoid/100183293/vkcid/0',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
|
||||
qs = parse_qs(url)
|
||||
pl = qs.get('pl', ['1'])[0]
|
||||
|
||||
video = self._download_xml(
|
||||
'http://out.pladform.ru/getVideo', video_id, query={
|
||||
'pl': pl,
|
||||
'videoid': video_id,
|
||||
}, fatal=False)
|
||||
|
||||
def fail(text):
|
||||
raise ExtractorError(
|
||||
f'{self.IE_NAME} returned error: {text}',
|
||||
expected=True)
|
||||
|
||||
if not video:
|
||||
target_url = self._request_webpage(url, video_id, note='Resolving final URL').url
|
||||
if target_url == url:
|
||||
raise ExtractorError('Can\'t parse page')
|
||||
return self.url_result(target_url)
|
||||
|
||||
if video.tag == 'error':
|
||||
fail(video.text)
|
||||
|
||||
quality = qualities(('ld', 'sd', 'hd'))
|
||||
|
||||
formats = []
|
||||
for src in video.findall('./src'):
|
||||
if src is None:
|
||||
continue
|
||||
format_url = src.text
|
||||
if not format_url:
|
||||
continue
|
||||
if src.get('type') == 'hls' or determine_ext(format_url) == 'm3u8':
|
||||
formats.extend(self._extract_m3u8_formats(
|
||||
format_url, video_id, 'mp4', entry_protocol='m3u8_native',
|
||||
m3u8_id='hls', fatal=False))
|
||||
else:
|
||||
formats.append({
|
||||
'url': src.text,
|
||||
'format_id': src.get('quality'),
|
||||
'quality': quality(src.get('quality')),
|
||||
})
|
||||
|
||||
if not formats:
|
||||
error = xpath_text(video, './cap', 'error', default=None)
|
||||
if error:
|
||||
fail(error)
|
||||
|
||||
webpage = self._download_webpage(
|
||||
f'http://video.pladform.ru/catalog/video/videoid/{video_id}',
|
||||
video_id)
|
||||
|
||||
title = self._og_search_title(webpage, fatal=False) or xpath_text(
|
||||
video, './/title', 'title', fatal=True)
|
||||
description = self._search_regex(
|
||||
r'</h3>\s*<p>([^<]+)</p>', webpage, 'description', fatal=False)
|
||||
thumbnail = self._og_search_thumbnail(webpage) or xpath_text(
|
||||
video, './/cover', 'cover')
|
||||
|
||||
duration = int_or_none(xpath_text(video, './/time', 'duration'))
|
||||
age_limit = int_or_none(xpath_text(video, './/age18', 'age limit'))
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'title': title,
|
||||
'description': description,
|
||||
'thumbnail': thumbnail,
|
||||
'duration': duration,
|
||||
'age_limit': age_limit,
|
||||
'formats': formats,
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
from .mtv import MTVServicesInfoExtractor
|
||||
|
||||
|
||||
class BellatorIE(MTVServicesInfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?bellator\.com/[^/]+/[\da-z]{6}(?:[/?#&]|$)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.bellator.com/fight/atwr7k/bellator-158-michael-page-vs-evangelista-cyborg',
|
||||
'info_dict': {
|
||||
'title': 'Michael Page vs. Evangelista Cyborg',
|
||||
'description': 'md5:0d917fc00ffd72dd92814963fc6cbb05',
|
||||
},
|
||||
'playlist_count': 3,
|
||||
}, {
|
||||
'url': 'http://www.bellator.com/video-clips/bw6k7n/bellator-158-foundations-michael-venom-page',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
_FEED_URL = 'http://www.bellator.com/feeds/mrss/'
|
||||
_GEO_COUNTRIES = ['US']
|
||||
|
||||
|
||||
class ParamountNetworkIE(MTVServicesInfoExtractor):
|
||||
_VALID_URL = r'https?://(?:www\.)?paramountnetwork\.com/[^/]+/[\da-z]{6}(?:[/?#&]|$)'
|
||||
_TESTS = [{
|
||||
'url': 'http://www.paramountnetwork.com/episodes/j830qm/lip-sync-battle-joel-mchale-vs-jim-rash-season-2-ep-13',
|
||||
'info_dict': {
|
||||
'id': '37ace3a8-1df6-48be-85b8-38df8229e241',
|
||||
'ext': 'mp4',
|
||||
'title': 'Lip Sync Battle|April 28, 2016|2|209|Joel McHale Vs. Jim Rash|Act 1',
|
||||
'description': 'md5:a739ca8f978a7802f67f8016d27ce114',
|
||||
},
|
||||
'params': {
|
||||
# m3u8 download
|
||||
'skip_download': True,
|
||||
},
|
||||
}]
|
||||
|
||||
_FEED_URL = 'http://feeds.mtvnservices.com/od/feed/intl-mrss-player-feed'
|
||||
_GEO_COUNTRIES = ['US']
|
||||
|
||||
def _get_feed_query(self, uri):
|
||||
return {
|
||||
'arcEp': 'paramountnetwork.com',
|
||||
'imageEp': 'paramountnetwork.com',
|
||||
'mgid': uri,
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
from .mtv import MTVServicesInfoExtractor
|
||||
|
||||
# TODO: Remove - Reason not used anymore - Service moved to youtube
|
||||
|
||||
|
||||
class TVLandIE(MTVServicesInfoExtractor):
|
||||
IE_NAME = 'tvland.com'
|
||||
_VALID_URL = r'https?://(?:www\.)?tvland\.com/(?:video-clips|(?:full-)?episodes)/(?P<id>[^/?#.]+)'
|
||||
_FEED_URL = 'http://www.tvland.com/feeds/mrss/'
|
||||
_TESTS = [{
|
||||
# Geo-restricted. Without a proxy metadata are still there. With a
|
||||
# proxy it redirects to http://m.tvland.com/app/
|
||||
'url': 'https://www.tvland.com/episodes/s04pzf/everybody-loves-raymond-the-dog-season-1-ep-19',
|
||||
'info_dict': {
|
||||
'description': 'md5:84928e7a8ad6649371fbf5da5e1ad75a',
|
||||
'title': 'The Dog',
|
||||
},
|
||||
'playlist_mincount': 5,
|
||||
'skip': '404 Not found',
|
||||
}, {
|
||||
'url': 'https://www.tvland.com/video-clips/4n87f2/younger-a-first-look-at-younger-season-6',
|
||||
'md5': 'e2c6389401cf485df26c79c247b08713',
|
||||
'info_dict': {
|
||||
'id': '891f7d3c-5b5b-4753-b879-b7ba1a601757',
|
||||
'ext': 'mp4',
|
||||
'title': 'Younger|April 30, 2019|6|NO-EPISODE#|A First Look at Younger Season 6',
|
||||
'description': 'md5:595ea74578d3a888ae878dfd1c7d4ab2',
|
||||
'upload_date': '20190430',
|
||||
'timestamp': 1556658000,
|
||||
},
|
||||
'params': {
|
||||
'skip_download': True,
|
||||
},
|
||||
}, {
|
||||
'url': 'http://www.tvland.com/full-episodes/iu0hz6/younger-a-kiss-is-just-a-kiss-season-3-ep-301',
|
||||
'only_matching': True,
|
||||
}]
|
@ -1,352 +0,0 @@
|
||||
import json
|
||||
import re
|
||||
|
||||
from .common import InfoExtractor
|
||||
from ..networking.exceptions import HTTPError
|
||||
from ..utils import (
|
||||
ExtractorError,
|
||||
int_or_none,
|
||||
parse_iso8601,
|
||||
parse_qs,
|
||||
)
|
||||
|
||||
|
||||
class VevoBaseIE(InfoExtractor):
|
||||
def _extract_json(self, webpage, video_id):
|
||||
return self._parse_json(
|
||||
self._search_regex(
|
||||
r'window\.__INITIAL_STORE__\s*=\s*({.+?});\s*</script>',
|
||||
webpage, 'initial store'),
|
||||
video_id)
|
||||
|
||||
|
||||
class VevoIE(VevoBaseIE):
|
||||
"""
|
||||
Accepts urls from vevo.com or in the format 'vevo:{id}'
|
||||
(currently used by MTVIE and MySpaceIE)
|
||||
"""
|
||||
_VALID_URL = r'''(?x)
|
||||
(?:https?://(?:www\.)?vevo\.com/watch/(?!playlist|genre)(?:[^/]+/(?:[^/]+/)?)?|
|
||||
https?://cache\.vevo\.com/m/html/embed\.html\?video=|
|
||||
https?://videoplayer\.vevo\.com/embed/embedded\?videoId=|
|
||||
https?://embed\.vevo\.com/.*?[?&]isrc=|
|
||||
https?://tv\.vevo\.com/watch/artist/(?:[^/]+)/|
|
||||
vevo:)
|
||||
(?P<id>[^&?#]+)'''
|
||||
_EMBED_REGEX = [r'<iframe[^>]+?src=(["\'])(?P<url>(?:https?:)?//(?:cache\.)?vevo\.com/.+?)\1']
|
||||
|
||||
_TESTS = [{
|
||||
'url': 'http://www.vevo.com/watch/hurts/somebody-to-die-for/GB1101300280',
|
||||
'md5': '95ee28ee45e70130e3ab02b0f579ae23',
|
||||
'info_dict': {
|
||||
'id': 'GB1101300280',
|
||||
'ext': 'mp4',
|
||||
'title': 'Hurts - Somebody to Die For',
|
||||
'timestamp': 1372057200,
|
||||
'upload_date': '20130624',
|
||||
'uploader': 'Hurts',
|
||||
'track': 'Somebody to Die For',
|
||||
'artist': 'Hurts',
|
||||
'genre': 'Pop',
|
||||
},
|
||||
'expected_warnings': ['Unable to download SMIL file', 'Unable to download info'],
|
||||
}, {
|
||||
'note': 'v3 SMIL format',
|
||||
'url': 'http://www.vevo.com/watch/cassadee-pope/i-wish-i-could-break-your-heart/USUV71302923',
|
||||
'md5': 'f6ab09b034f8c22969020b042e5ac7fc',
|
||||
'info_dict': {
|
||||
'id': 'USUV71302923',
|
||||
'ext': 'mp4',
|
||||
'title': 'Cassadee Pope - I Wish I Could Break Your Heart',
|
||||
'timestamp': 1392796919,
|
||||
'upload_date': '20140219',
|
||||
'uploader': 'Cassadee Pope',
|
||||
'track': 'I Wish I Could Break Your Heart',
|
||||
'artist': 'Cassadee Pope',
|
||||
'genre': 'Country',
|
||||
},
|
||||
'expected_warnings': ['Unable to download SMIL file', 'Unable to download info'],
|
||||
}, {
|
||||
'note': 'Age-limited video',
|
||||
'url': 'https://www.vevo.com/watch/justin-timberlake/tunnel-vision-explicit/USRV81300282',
|
||||
'info_dict': {
|
||||
'id': 'USRV81300282',
|
||||
'ext': 'mp4',
|
||||
'title': 'Justin Timberlake - Tunnel Vision (Explicit)',
|
||||
'age_limit': 18,
|
||||
'timestamp': 1372888800,
|
||||
'upload_date': '20130703',
|
||||
'uploader': 'Justin Timberlake',
|
||||
'track': 'Tunnel Vision (Explicit)',
|
||||
'artist': 'Justin Timberlake',
|
||||
'genre': 'Pop',
|
||||
},
|
||||
'expected_warnings': ['Unable to download SMIL file', 'Unable to download info'],
|
||||
}, {
|
||||
'note': 'No video_info',
|
||||
'url': 'http://www.vevo.com/watch/k-camp-1/Till-I-Die/USUV71503000',
|
||||
'md5': '8b83cc492d72fc9cf74a02acee7dc1b0',
|
||||
'info_dict': {
|
||||
'id': 'USUV71503000',
|
||||
'ext': 'mp4',
|
||||
'title': 'K Camp ft. T.I. - Till I Die',
|
||||
'age_limit': 18,
|
||||
'timestamp': 1449468000,
|
||||
'upload_date': '20151207',
|
||||
'uploader': 'K Camp',
|
||||
'track': 'Till I Die',
|
||||
'artist': 'K Camp',
|
||||
'genre': 'Hip-Hop',
|
||||
},
|
||||
'expected_warnings': ['Unable to download SMIL file', 'Unable to download info'],
|
||||
}, {
|
||||
'note': 'Featured test',
|
||||
'url': 'https://www.vevo.com/watch/lemaitre/Wait/USUV71402190',
|
||||
'md5': 'd28675e5e8805035d949dc5cf161071d',
|
||||
'info_dict': {
|
||||
'id': 'USUV71402190',
|
||||
'ext': 'mp4',
|
||||
'title': 'Lemaitre ft. LoLo - Wait',
|
||||
'age_limit': 0,
|
||||
'timestamp': 1413432000,
|
||||
'upload_date': '20141016',
|
||||
'uploader': 'Lemaitre',
|
||||
'track': 'Wait',
|
||||
'artist': 'Lemaitre',
|
||||
'genre': 'Electronic',
|
||||
},
|
||||
'expected_warnings': ['Unable to download SMIL file', 'Unable to download info'],
|
||||
}, {
|
||||
'note': 'Only available via webpage',
|
||||
'url': 'http://www.vevo.com/watch/GBUV71600656',
|
||||
'md5': '67e79210613865b66a47c33baa5e37fe',
|
||||
'info_dict': {
|
||||
'id': 'GBUV71600656',
|
||||
'ext': 'mp4',
|
||||
'title': 'ABC - Viva Love',
|
||||
'age_limit': 0,
|
||||
'timestamp': 1461830400,
|
||||
'upload_date': '20160428',
|
||||
'uploader': 'ABC',
|
||||
'track': 'Viva Love',
|
||||
'artist': 'ABC',
|
||||
'genre': 'Pop',
|
||||
},
|
||||
'expected_warnings': ['Failed to download video versions info'],
|
||||
}, {
|
||||
# no genres available
|
||||
'url': 'http://www.vevo.com/watch/INS171400764',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
# Another case available only via the webpage; using streams/streamsV3 formats
|
||||
# Geo-restricted to Netherlands/Germany
|
||||
'url': 'http://www.vevo.com/watch/boostee/pop-corn-clip-officiel/FR1A91600909',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://embed.vevo.com/?isrc=USH5V1923499&partnerId=4d61b777-8023-4191-9ede-497ed6c24647&partnerAdCode=',
|
||||
'only_matching': True,
|
||||
}, {
|
||||
'url': 'https://tv.vevo.com/watch/artist/janet-jackson/US0450100550',
|
||||
'only_matching': True,
|
||||
}]
|
||||
_VERSIONS = {
|
||||
0: 'youtube', # only in AuthenticateVideo videoVersions
|
||||
1: 'level3',
|
||||
2: 'akamai',
|
||||
3: 'level3',
|
||||
4: 'amazon',
|
||||
}
|
||||
|
||||
def _initialize_api(self, video_id):
|
||||
webpage = self._download_webpage(
|
||||
'https://accounts.vevo.com/token', None,
|
||||
note='Retrieving oauth token',
|
||||
errnote='Unable to retrieve oauth token',
|
||||
data=json.dumps({
|
||||
'client_id': 'SPupX1tvqFEopQ1YS6SS',
|
||||
'grant_type': 'urn:vevo:params:oauth:grant-type:anonymous',
|
||||
}).encode(),
|
||||
headers={
|
||||
'Content-Type': 'application/json',
|
||||
})
|
||||
|
||||
if re.search(r'(?i)THIS PAGE IS CURRENTLY UNAVAILABLE IN YOUR REGION', webpage):
|
||||
self.raise_geo_restricted(
|
||||
f'{self.IE_NAME} said: This page is currently unavailable in your region')
|
||||
|
||||
auth_info = self._parse_json(webpage, video_id)
|
||||
self._api_url_template = self.http_scheme() + '//apiv2.vevo.com/%s?token=' + auth_info['legacy_token']
|
||||
|
||||
def _call_api(self, path, *args, **kwargs):
|
||||
try:
|
||||
data = self._download_json(self._api_url_template % path, *args, **kwargs)
|
||||
except ExtractorError as e:
|
||||
if isinstance(e.cause, HTTPError):
|
||||
errors = self._parse_json(e.cause.response.read().decode(), None)['errors']
|
||||
error_message = ', '.join([error['message'] for error in errors])
|
||||
raise ExtractorError(f'{self.IE_NAME} said: {error_message}', expected=True)
|
||||
raise
|
||||
return data
|
||||
|
||||
def _real_extract(self, url):
|
||||
video_id = self._match_id(url)
|
||||
|
||||
self._initialize_api(video_id)
|
||||
|
||||
video_info = self._call_api(
|
||||
f'video/{video_id}', video_id, 'Downloading api video info',
|
||||
'Failed to download video info')
|
||||
|
||||
video_versions = self._call_api(
|
||||
f'video/{video_id}/streams', video_id,
|
||||
'Downloading video versions info',
|
||||
'Failed to download video versions info',
|
||||
fatal=False)
|
||||
|
||||
# Some videos are only available via webpage (e.g.
|
||||
# https://github.com/ytdl-org/youtube-dl/issues/9366)
|
||||
if not video_versions:
|
||||
webpage = self._download_webpage(url, video_id)
|
||||
json_data = self._extract_json(webpage, video_id)
|
||||
if 'streams' in json_data.get('default', {}):
|
||||
video_versions = json_data['default']['streams'][video_id][0]
|
||||
else:
|
||||
video_versions = [
|
||||
value
|
||||
for key, value in json_data['apollo']['data'].items()
|
||||
if key.startswith(f'{video_id}.streams')]
|
||||
|
||||
uploader = None
|
||||
artist = None
|
||||
featured_artist = None
|
||||
artists = video_info.get('artists')
|
||||
for curr_artist in artists:
|
||||
if curr_artist.get('role') == 'Featured':
|
||||
featured_artist = curr_artist['name']
|
||||
else:
|
||||
artist = uploader = curr_artist['name']
|
||||
|
||||
formats = []
|
||||
for video_version in video_versions:
|
||||
version = self._VERSIONS.get(video_version.get('version'), 'generic')
|
||||
version_url = video_version.get('url')
|
||||
if not version_url:
|
||||
continue
|
||||
|
||||
if '.ism' in version_url:
|
||||
continue
|
||||
elif '.mpd' in version_url:
|
||||
formats.extend(self._extract_mpd_formats(
|
||||
version_url, video_id, mpd_id=f'dash-{version}',
|
||||
note=f'Downloading {version} MPD information',
|
||||
errnote=f'Failed to download {version} MPD information',
|
||||
fatal=False))
|
||||
elif '.m3u8' in version_url:
|
||||
formats.extend(self._extract_m3u8_formats(
|
||||
version_url, video_id, 'mp4', 'm3u8_native',
|
||||
m3u8_id=f'hls-{version}',
|
||||
note=f'Downloading {version} m3u8 information',
|
||||
errnote=f'Failed to download {version} m3u8 information',
|
||||
fatal=False))
|
||||
else:
|
||||
m = re.search(r'''(?xi)
|
||||
_(?P<quality>[a-z0-9]+)
|
||||
_(?P<width>[0-9]+)x(?P<height>[0-9]+)
|
||||
_(?P<vcodec>[a-z0-9]+)
|
||||
_(?P<vbr>[0-9]+)
|
||||
_(?P<acodec>[a-z0-9]+)
|
||||
_(?P<abr>[0-9]+)
|
||||
\.(?P<ext>[a-z0-9]+)''', version_url)
|
||||
if not m:
|
||||
continue
|
||||
|
||||
formats.append({
|
||||
'url': version_url,
|
||||
'format_id': f'http-{version}-{video_version.get("quality") or m.group("quality")}',
|
||||
'vcodec': m.group('vcodec'),
|
||||
'acodec': m.group('acodec'),
|
||||
'vbr': int(m.group('vbr')),
|
||||
'abr': int(m.group('abr')),
|
||||
'ext': m.group('ext'),
|
||||
'width': int(m.group('width')),
|
||||
'height': int(m.group('height')),
|
||||
})
|
||||
|
||||
track = video_info['title']
|
||||
if featured_artist:
|
||||
artist = f'{artist} ft. {featured_artist}'
|
||||
title = f'{artist} - {track}' if artist else track
|
||||
|
||||
genres = video_info.get('genres')
|
||||
genre = (
|
||||
genres[0] if genres and isinstance(genres, list)
|
||||
and isinstance(genres[0], str) else None)
|
||||
|
||||
is_explicit = video_info.get('isExplicit')
|
||||
if is_explicit is True:
|
||||
age_limit = 18
|
||||
elif is_explicit is False:
|
||||
age_limit = 0
|
||||
else:
|
||||
age_limit = None
|
||||
|
||||
return {
|
||||
'id': video_id,
|
||||
'title': title,
|
||||
'formats': formats,
|
||||
'thumbnail': video_info.get('imageUrl') or video_info.get('thumbnailUrl'),
|
||||
'timestamp': parse_iso8601(video_info.get('releaseDate')),
|
||||
'uploader': uploader,
|
||||
'duration': int_or_none(video_info.get('duration')),
|
||||
'view_count': int_or_none(video_info.get('views', {}).get('total')),
|
||||
'age_limit': age_limit,
|
||||
'track': track,
|
||||
'artist': uploader,
|
||||
'genre': genre,
|
||||
}
|
||||
|
||||
|
||||
class VevoPlaylistIE(VevoBaseIE):
|
||||
_VALID_URL = r'https?://(?:www\.)?vevo\.com/watch/(?P<kind>playlist|genre)/(?P<id>[^/?#&]+)'
|
||||
|
||||
_TESTS = [{
|
||||
'url': 'http://www.vevo.com/watch/genre/rock',
|
||||
'info_dict': {
|
||||
'id': 'rock',
|
||||
'title': 'Rock',
|
||||
},
|
||||
'playlist_count': 20,
|
||||
}, {
|
||||
'url': 'http://www.vevo.com/watch/genre/rock?index=0',
|
||||
'only_matching': True,
|
||||
}]
|
||||
|
||||
def _real_extract(self, url):
|
||||
mobj = self._match_valid_url(url)
|
||||
playlist_id = mobj.group('id')
|
||||
playlist_kind = mobj.group('kind')
|
||||
|
||||
webpage = self._download_webpage(url, playlist_id)
|
||||
|
||||
qs = parse_qs(url)
|
||||
index = qs.get('index', [None])[0]
|
||||
|
||||
if index:
|
||||
video_id = self._search_regex(
|
||||
r'<meta[^>]+content=(["\'])vevo://video/(?P<id>.+?)\1[^>]*>',
|
||||
webpage, 'video id', default=None, group='id')
|
||||
if video_id:
|
||||
return self.url_result(f'vevo:{video_id}', VevoIE.ie_key())
|
||||
|
||||
playlists = self._extract_json(webpage, playlist_id)['default'][f'{playlist_kind}s']
|
||||
|
||||
playlist = (next(iter(playlists.values()))
|
||||
if playlist_kind == 'playlist' else playlists[playlist_id])
|
||||
|
||||
entries = [
|
||||
self.url_result(f'vevo:{src}', VevoIE.ie_key())
|
||||
for src in playlist['isrcs']]
|
||||
|
||||
return self.playlist_result(
|
||||
entries, playlist.get('playlistId') or playlist_id,
|
||||
playlist.get('name'), playlist.get('description'))
|
@ -5,7 +5,6 @@
|
||||
from .common import InfoExtractor
|
||||
from .dailymotion import DailymotionIE
|
||||
from .odnoklassniki import OdnoklassnikiIE
|
||||
from .pladform import PladformIE
|
||||
from .sibnet import SibnetEmbedIE
|
||||
from .vimeo import VimeoIE
|
||||
from .youtube import YoutubeIE
|
||||
@ -334,11 +333,6 @@ class VKIE(VKBaseIE):
|
||||
'url': 'https://vk.com/video205387401_164765225',
|
||||
'only_matching': True,
|
||||
},
|
||||
{
|
||||
# pladform embed
|
||||
'url': 'https://vk.com/video-76116461_171554880',
|
||||
'only_matching': True,
|
||||
},
|
||||
{
|
||||
'url': 'http://new.vk.com/video205387401_165548505',
|
||||
'only_matching': True,
|
||||
@ -456,10 +450,6 @@ def _real_extract(self, url):
|
||||
if vimeo_url is not None:
|
||||
return self.url_result(vimeo_url, VimeoIE.ie_key())
|
||||
|
||||
pladform_url = PladformIE._extract_url(info_page)
|
||||
if pladform_url:
|
||||
return self.url_result(pladform_url, PladformIE.ie_key())
|
||||
|
||||
m_rutube = re.search(
|
||||
r'\ssrc="((?:https?:)?//rutube\.ru\\?/(?:video|play)\\?/embed(?:.*?))\\?"', info_page)
|
||||
if m_rutube is not None:
|
||||
|
Loading…
Reference in New Issue
Block a user