mirror of
https://github.com/yt-dlp/yt-dlp.git
synced 2025-08-16 09:28:28 +00:00
Merge d336e7474b
into f2919bd28e
This commit is contained in:
commit
1cd566983d
@ -152,7 +152,6 @@
|
|||||||
ARDBetaMediathekIE,
|
ARDBetaMediathekIE,
|
||||||
ARDMediathekCollectionIE,
|
ARDMediathekCollectionIE,
|
||||||
)
|
)
|
||||||
from .arkena import ArkenaIE
|
|
||||||
from .arnes import ArnesIE
|
from .arnes import ArnesIE
|
||||||
from .art19 import (
|
from .art19 import (
|
||||||
Art19IE,
|
Art19IE,
|
||||||
@ -1187,15 +1186,7 @@
|
|||||||
from .moviezine import MoviezineIE
|
from .moviezine import MoviezineIE
|
||||||
from .movingimage import MovingImageIE
|
from .movingimage import MovingImageIE
|
||||||
from .msn import MSNIE
|
from .msn import MSNIE
|
||||||
from .mtv import (
|
from .mtv import MTVIE
|
||||||
MTVDEIE,
|
|
||||||
MTVIE,
|
|
||||||
MTVItaliaIE,
|
|
||||||
MTVItaliaProgrammaIE,
|
|
||||||
MTVJapanIE,
|
|
||||||
MTVServicesEmbeddedIE,
|
|
||||||
MTVVideoIE,
|
|
||||||
)
|
|
||||||
from .muenchentv import MuenchenTVIE
|
from .muenchentv import MuenchenTVIE
|
||||||
from .murrtube import (
|
from .murrtube import (
|
||||||
MurrtubeIE,
|
MurrtubeIE,
|
||||||
@ -1548,7 +1539,6 @@
|
|||||||
PixivSketchIE,
|
PixivSketchIE,
|
||||||
PixivSketchUserIE,
|
PixivSketchUserIE,
|
||||||
)
|
)
|
||||||
from .pladform import PladformIE
|
|
||||||
from .planetmarathi import PlanetMarathiIE
|
from .planetmarathi import PlanetMarathiIE
|
||||||
from .platzi import (
|
from .platzi import (
|
||||||
PlatziCourseIE,
|
PlatziCourseIE,
|
||||||
@ -1947,10 +1937,6 @@
|
|||||||
SpankBangPlaylistIE,
|
SpankBangPlaylistIE,
|
||||||
)
|
)
|
||||||
from .spiegel import SpiegelIE
|
from .spiegel import SpiegelIE
|
||||||
from .spike import (
|
|
||||||
BellatorIE,
|
|
||||||
ParamountNetworkIE,
|
|
||||||
)
|
|
||||||
from .sport5 import Sport5IE
|
from .sport5 import Sport5IE
|
||||||
from .sportbox import SportBoxIE
|
from .sportbox import SportBoxIE
|
||||||
from .sportdeutschland import SportDeutschlandIE
|
from .sportdeutschland import SportDeutschlandIE
|
||||||
@ -2215,7 +2201,6 @@
|
|||||||
from .tver import TVerIE
|
from .tver import TVerIE
|
||||||
from .tvigle import TvigleIE
|
from .tvigle import TvigleIE
|
||||||
from .tviplayer import TVIPlayerIE
|
from .tviplayer import TVIPlayerIE
|
||||||
from .tvland import TVLandIE
|
|
||||||
from .tvn24 import TVN24IE
|
from .tvn24 import TVN24IE
|
||||||
from .tvnoe import TVNoeIE
|
from .tvnoe import TVNoeIE
|
||||||
from .tvopengr import (
|
from .tvopengr import (
|
||||||
@ -2313,10 +2298,6 @@
|
|||||||
from .vbox7 import Vbox7IE
|
from .vbox7 import Vbox7IE
|
||||||
from .veo import VeoIE
|
from .veo import VeoIE
|
||||||
from .vesti import VestiIE
|
from .vesti import VestiIE
|
||||||
from .vevo import (
|
|
||||||
VevoIE,
|
|
||||||
VevoPlaylistIE,
|
|
||||||
)
|
|
||||||
from .vgtv import (
|
from .vgtv import (
|
||||||
VGTVIE,
|
VGTVIE,
|
||||||
BTArticleIE,
|
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:
|
else:
|
||||||
# $Number*$ or $Time$ in media template with S list available
|
# $Number*$ or $Time$ in media template with S list available
|
||||||
# Example $Number*$: http://www.svtplay.se/klipp/9023742/stopptid-om-bjorn-borg
|
# 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'] = []
|
representation_ms_info['fragments'] = []
|
||||||
segment_time = 0
|
segment_time = 0
|
||||||
segment_d = None
|
segment_d = None
|
||||||
|
@ -171,17 +171,6 @@ class DailymotionIE(DailymotionBaseInfoExtractor):
|
|||||||
'view_count': int,
|
'view_count': int,
|
||||||
},
|
},
|
||||||
'skip': 'video gone',
|
'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
|
# age-restricted video
|
||||||
'url': 'http://www.dailymotion.com/video/xyh2zz_leanna-decker-cyber-girl-of-the-year-desires-nude-playboy-plus_redband',
|
'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)
|
webpage, 'embed data'), video_id)
|
||||||
video_data = page_data['video']
|
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']
|
video_id = video_data['id']
|
||||||
title = video_data['title']
|
title = video_data['title']
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
from .arkena import ArkenaIE
|
|
||||||
from .common import InfoExtractor
|
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>[^/]+)/[^/]+/[^/]+'
|
_VALID_URL = r'https?://play\.lcp\.fr/embed/(?P<id>[^/]+)/(?P<account_id>[^/]+)/[^/]+/[^/]+'
|
||||||
_TESTS = [{
|
_TESTS = [{
|
||||||
'url': 'http://play.lcp.fr/embed/327336/131064/darkmatter/0',
|
'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>[^/]+)'
|
_VALID_URL = r'https?://(?:www\.)?lcp\.fr/(?:[^/]+/)*(?P<id>[^/]+)'
|
||||||
|
|
||||||
_TESTS = [{
|
_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
|
# dailymotion live stream
|
||||||
'url': 'http://www.lcp.fr/le-direct',
|
'url': 'http://www.lcp.fr/le-direct',
|
||||||
'info_dict': {
|
'info_dict': {
|
||||||
|
@ -322,37 +322,6 @@ def _real_extract(self, url):
|
|||||||
return self._get_videos_info(mgid, url=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):
|
class MTVIE(MTVServicesInfoExtractor):
|
||||||
IE_NAME = 'mtv'
|
IE_NAME = 'mtv'
|
||||||
_VALID_URL = r'https?://(?:www\.)?mtv\.com/(?:video-clips|(?:full-)?episodes)/(?P<id>[^/?#.]+)'
|
_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',
|
'url': 'http://www.mtv.com/episodes/g8xu7q/teen-mom-2-breaking-the-wall-season-7-ep-713',
|
||||||
'only_matching': True,
|
'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('stream-url'), search_data('hls-stream-url'),
|
||||||
search_data('http-stream-url'))
|
search_data('http-stream-url'))
|
||||||
if not formats:
|
if not formats:
|
||||||
vevo_id = search_data('vevo-id')
|
|
||||||
youtube_id = search_data('youtube-id')
|
youtube_id = search_data('youtube-id')
|
||||||
if vevo_id:
|
if youtube_id:
|
||||||
self.to_screen(f'Vevo video detected: {vevo_id}')
|
|
||||||
return self.url_result(f'vevo:{vevo_id}', ie='Vevo')
|
|
||||||
elif youtube_id:
|
|
||||||
self.to_screen(f'Youtube video detected: {youtube_id}')
|
self.to_screen(f'Youtube video detected: {youtube_id}')
|
||||||
return self.url_result(youtube_id, ie='Youtube')
|
return self.url_result(youtube_id, ie='Youtube')
|
||||||
else:
|
else:
|
||||||
|
@ -352,14 +352,6 @@ def _extract_desktop(self, url):
|
|||||||
'subtitles': subtitles,
|
'subtitles': subtitles,
|
||||||
}
|
}
|
||||||
|
|
||||||
# pladform
|
|
||||||
if provider == 'OPEN_GRAPH':
|
|
||||||
info.update({
|
|
||||||
'_type': 'url_transparent',
|
|
||||||
'url': movie['contentId'],
|
|
||||||
})
|
|
||||||
return info
|
|
||||||
|
|
||||||
if provider == 'USER_YOUTUBE':
|
if provider == 'USER_YOUTUBE':
|
||||||
info.update({
|
info.update({
|
||||||
'_type': 'url_transparent',
|
'_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 .common import InfoExtractor
|
||||||
from .dailymotion import DailymotionIE
|
from .dailymotion import DailymotionIE
|
||||||
from .odnoklassniki import OdnoklassnikiIE
|
from .odnoklassniki import OdnoklassnikiIE
|
||||||
from .pladform import PladformIE
|
|
||||||
from .sibnet import SibnetEmbedIE
|
from .sibnet import SibnetEmbedIE
|
||||||
from .vimeo import VimeoIE
|
from .vimeo import VimeoIE
|
||||||
from .youtube import YoutubeIE
|
from .youtube import YoutubeIE
|
||||||
@ -334,11 +333,6 @@ class VKIE(VKBaseIE):
|
|||||||
'url': 'https://vk.com/video205387401_164765225',
|
'url': 'https://vk.com/video205387401_164765225',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
},
|
},
|
||||||
{
|
|
||||||
# pladform embed
|
|
||||||
'url': 'https://vk.com/video-76116461_171554880',
|
|
||||||
'only_matching': True,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
'url': 'http://new.vk.com/video205387401_165548505',
|
'url': 'http://new.vk.com/video205387401_165548505',
|
||||||
'only_matching': True,
|
'only_matching': True,
|
||||||
@ -456,10 +450,6 @@ def _real_extract(self, url):
|
|||||||
if vimeo_url is not None:
|
if vimeo_url is not None:
|
||||||
return self.url_result(vimeo_url, VimeoIE.ie_key())
|
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(
|
m_rutube = re.search(
|
||||||
r'\ssrc="((?:https?:)?//rutube\.ru\\?/(?:video|play)\\?/embed(?:.*?))\\?"', info_page)
|
r'\ssrc="((?:https?:)?//rutube\.ru\\?/(?:video|play)\\?/embed(?:.*?))\\?"', info_page)
|
||||||
if m_rutube is not None:
|
if m_rutube is not None:
|
||||||
|
Loading…
Reference in New Issue
Block a user