|
|
@ -5,11 +5,13 @@ import re
|
|
|
|
|
|
|
|
|
|
|
|
from .common import InfoExtractor
|
|
|
|
from .common import InfoExtractor
|
|
|
|
from ..utils import (
|
|
|
|
from ..utils import (
|
|
|
|
|
|
|
|
dict_get,
|
|
|
|
ExtractorError,
|
|
|
|
ExtractorError,
|
|
|
|
float_or_none,
|
|
|
|
float_or_none,
|
|
|
|
int_or_none,
|
|
|
|
int_or_none,
|
|
|
|
parse_duration,
|
|
|
|
parse_duration,
|
|
|
|
parse_iso8601,
|
|
|
|
parse_iso8601,
|
|
|
|
|
|
|
|
try_get,
|
|
|
|
unescapeHTML,
|
|
|
|
unescapeHTML,
|
|
|
|
)
|
|
|
|
)
|
|
|
|
from ..compat import (
|
|
|
|
from ..compat import (
|
|
|
@ -643,6 +645,24 @@ class BBCIE(BBCCoUkIE):
|
|
|
|
# rtmp download
|
|
|
|
# rtmp download
|
|
|
|
'skip_download': True,
|
|
|
|
'skip_download': True,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}, {
|
|
|
|
|
|
|
|
# single video embedded with Morph
|
|
|
|
|
|
|
|
'url': 'http://www.bbc.co.uk/sport/live/olympics/36895975',
|
|
|
|
|
|
|
|
'info_dict': {
|
|
|
|
|
|
|
|
'id': 'p041vhd0',
|
|
|
|
|
|
|
|
'ext': 'mp4',
|
|
|
|
|
|
|
|
'title': "Nigeria v Japan - Men's First Round",
|
|
|
|
|
|
|
|
'description': 'Live coverage of the first round from Group B at the Amazonia Arena.',
|
|
|
|
|
|
|
|
'duration': 7980,
|
|
|
|
|
|
|
|
'uploader': 'BBC Sport',
|
|
|
|
|
|
|
|
'uploader_id': 'bbc_sport',
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
'params': {
|
|
|
|
|
|
|
|
# m3u8 download
|
|
|
|
|
|
|
|
'skip_download': True,
|
|
|
|
|
|
|
|
'proxy': '5.101.173.158:8080',
|
|
|
|
|
|
|
|
},
|
|
|
|
|
|
|
|
'skip': 'Georestricted to UK',
|
|
|
|
}, {
|
|
|
|
}, {
|
|
|
|
# single video with playlist.sxml URL in playlist param
|
|
|
|
# single video with playlist.sxml URL in playlist param
|
|
|
|
'url': 'http://www.bbc.com/sport/0/football/33653409',
|
|
|
|
'url': 'http://www.bbc.com/sport/0/football/33653409',
|
|
|
@ -864,6 +884,50 @@ class BBCIE(BBCCoUkIE):
|
|
|
|
'subtitles': subtitles,
|
|
|
|
'subtitles': subtitles,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Morph based embed (e.g. http://www.bbc.co.uk/sport/live/olympics/36895975)
|
|
|
|
|
|
|
|
# There are several setPayload calls may be present but the video
|
|
|
|
|
|
|
|
# seems to be always related to the first one
|
|
|
|
|
|
|
|
morph_payload = self._parse_json(
|
|
|
|
|
|
|
|
self._search_regex(
|
|
|
|
|
|
|
|
r'Morph\.setPayload\([^,]+,\s*({.+?})\);',
|
|
|
|
|
|
|
|
webpage, 'morph payload', default='{}'),
|
|
|
|
|
|
|
|
playlist_id, fatal=False)
|
|
|
|
|
|
|
|
if morph_payload:
|
|
|
|
|
|
|
|
components = try_get(morph_payload, lambda x: x['body']['components'], list) or []
|
|
|
|
|
|
|
|
for component in components:
|
|
|
|
|
|
|
|
if not isinstance(component, dict):
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
lead_media = try_get(component, lambda x: x['props']['leadMedia'], dict)
|
|
|
|
|
|
|
|
if not lead_media:
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
identifiers = lead_media.get('identifiers')
|
|
|
|
|
|
|
|
if not identifiers or not isinstance(identifiers, dict):
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
programme_id = identifiers.get('vpid') or identifiers.get('playablePid')
|
|
|
|
|
|
|
|
if not programme_id:
|
|
|
|
|
|
|
|
continue
|
|
|
|
|
|
|
|
title = lead_media.get('title') or self._og_search_title(webpage)
|
|
|
|
|
|
|
|
formats, subtitles = self._download_media_selector(programme_id)
|
|
|
|
|
|
|
|
self._sort_formats(formats)
|
|
|
|
|
|
|
|
description = lead_media.get('summary')
|
|
|
|
|
|
|
|
uploader = lead_media.get('masterBrand')
|
|
|
|
|
|
|
|
uploader_id = lead_media.get('mid')
|
|
|
|
|
|
|
|
duration = None
|
|
|
|
|
|
|
|
duration_d = lead_media.get('duration')
|
|
|
|
|
|
|
|
if isinstance(duration_d, dict):
|
|
|
|
|
|
|
|
duration = parse_duration(dict_get(
|
|
|
|
|
|
|
|
duration_d, ('rawDuration', 'formattedDuration', 'spokenDuration')))
|
|
|
|
|
|
|
|
return {
|
|
|
|
|
|
|
|
'id': programme_id,
|
|
|
|
|
|
|
|
'title': title,
|
|
|
|
|
|
|
|
'description': description,
|
|
|
|
|
|
|
|
'duration': duration,
|
|
|
|
|
|
|
|
'uploader': uploader,
|
|
|
|
|
|
|
|
'uploader_id': uploader_id,
|
|
|
|
|
|
|
|
'formats': formats,
|
|
|
|
|
|
|
|
'subtitles': subtitles,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
def extract_all(pattern):
|
|
|
|
def extract_all(pattern):
|
|
|
|
return list(filter(None, map(
|
|
|
|
return list(filter(None, map(
|
|
|
|
lambda s: self._parse_json(s, playlist_id, fatal=False),
|
|
|
|
lambda s: self._parse_json(s, playlist_id, fatal=False),
|
|
|
|