diff --git a/youtube_dl/extractor/brightcove.py b/youtube_dl/extractor/brightcove.py index 58ec5c979..057b332be 100644 --- a/youtube_dl/extractor/brightcove.py +++ b/youtube_dl/extractor/brightcove.py @@ -12,6 +12,7 @@ from ..compat import ( compat_etree_fromstring, compat_parse_qs, compat_str, + compat_urllib_parse_urlencode, compat_urllib_parse_urlparse, compat_urlparse, compat_xml_parse_error, @@ -611,14 +612,14 @@ class BrightcoveNewIE(AdobePassIE): return entries - def _parse_brightcove_metadata(self, json_data, video_id, headers={}): + def _parse_brightcove_metadata(self, json_data, video_id, headers={}, options={}): title = json_data['name'].strip() formats = [] for source in json_data.get('sources', []): container = source.get('container') ext = mimetype2ext(source.get('type')) - src = source.get('src') + src = self._preprocess_metadata_url(source.get('src'), options) # https://support.brightcove.com/playback-api-video-fields-reference#key_systems_object if ext == 'ism' or container == 'WVM' or source.get('key_systems'): continue @@ -723,6 +724,17 @@ class BrightcoveNewIE(AdobePassIE): 'is_live': is_live, } + def _preprocess_metadata_url(self, url, options={}): + url = compat_urllib_parse_urlparse(url)._asdict() + query = dict(compat_parse_qs(url['query'])) + + if options.get('akamai_token') is not None: + query['hdnts'] = options.get('akamai_token') + + url['query'] = compat_urllib_parse_urlencode(query) + + return compat_urlparse.urlunparse(tuple(url.values())) + def _real_extract(self, url): url, smuggled_data = unsmuggle_url(url, {}) self._initialize_geo_bypass({ @@ -786,12 +798,16 @@ class BrightcoveNewIE(AdobePassIE): 'tveToken': tve_token, }) + options = { + 'akamai_token': smuggled_data.get('akamai_token') + } + if content_type == 'playlist': return self.playlist_result( - [self._parse_brightcove_metadata(vid, vid.get('id'), headers) + [self._parse_brightcove_metadata(vid, vid.get('id'), headers=headers, options=options) for vid in json_data.get('videos', []) if vid.get('id')], json_data.get('id'), json_data.get('name'), json_data.get('description')) return self._parse_brightcove_metadata( - json_data, video_id, headers=headers) + json_data, video_id, headers=headers, options=options) diff --git a/youtube_dl/extractor/cspanlive.py b/youtube_dl/extractor/cspanlive.py new file mode 100644 index 000000000..1a65a4365 --- /dev/null +++ b/youtube_dl/extractor/cspanlive.py @@ -0,0 +1,26 @@ +# coding: utf-8 +from __future__ import unicode_literals + +from .brightcove import BrightcoveNewIE +from .common import InfoExtractor +from ..utils import smuggle_url + + +class CSpanLiveIE(InfoExtractor): + IE_NAME = 'cspanlive' + BRIGHTCOVE_URL_TEMPLATE = 'http://players.brightcove.net/3162030207001/2B2qWQJYYM_default/index.html?videoId=%s' + + _VALID_URL = r'^https?://(?:www\.)?c-span\.org/networks' + + def _real_extract(self, url): + webpage = self._download_webpage(url, 'stream') + + akamai_token = self._html_search_regex(r'data-akamaitoken="([^"]+)"', webpage, 'akamai_token') + video_id = self._html_search_regex(r'data-bcid="([^"]+)"', webpage, 'video_id') + + brightcove_url = smuggle_url(self.BRIGHTCOVE_URL_TEMPLATE % video_id, { + 'akamai_token': akamai_token, + 'source_url': url + }) + + return self.url_result(brightcove_url, ie=BrightcoveNewIE.ie_key(), video_id=video_id) diff --git a/youtube_dl/extractor/extractors.py b/youtube_dl/extractor/extractors.py index 15f54a214..a478f01ec 100644 --- a/youtube_dl/extractor/extractors.py +++ b/youtube_dl/extractor/extractors.py @@ -238,6 +238,7 @@ from .crunchyroll import ( CrunchyrollShowPlaylistIE ) from .cspan import CSpanIE +from .cspanlive import CSpanLiveIE from .ctsnews import CtsNewsIE from .ctvnews import CTVNewsIE from .cultureunplugged import CultureUnpluggedIE