From be154ccbe2dd1eea5ca3539e5092b54e9e18fa24 Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 29 Nov 2016 13:57:30 +0100 Subject: [PATCH 1/3] [downloader/rtmp] add support for SecureToken verification --- youtube_dl/downloader/rtmp.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/youtube_dl/downloader/rtmp.py b/youtube_dl/downloader/rtmp.py index fbb7f51b0..37e33ad99 100644 --- a/youtube_dl/downloader/rtmp.py +++ b/youtube_dl/downloader/rtmp.py @@ -106,6 +106,7 @@ class RtmpFD(FileDownloader): conn = info_dict.get('rtmp_conn') protocol = info_dict.get('rtmp_protocol') real_time = info_dict.get('rtmp_real_time', False) + securetoken = info_dict.get('rtmp_securetoken') no_resume = info_dict.get('no_resume', False) continue_dl = self.params.get('continuedl', True) @@ -149,6 +150,8 @@ class RtmpFD(FileDownloader): basic_args += ['--protocol', protocol] if real_time: basic_args += ['--realtime'] + if securetoken is not None: + basic_args += ['--token', securetoken] args = basic_args if not no_resume and continue_dl and not live: From e46295036ca0390cd5eaadd71d8cdb47780e71cd Mon Sep 17 00:00:00 2001 From: felix Date: Tue, 29 Nov 2016 14:00:46 +0100 Subject: [PATCH 2/3] [common] add rtmp_securetoken to SMIL parser --- youtube_dl/extractor/common.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/youtube_dl/extractor/common.py b/youtube_dl/extractor/common.py index eaae5e484..6bf4f391c 100644 --- a/youtube_dl/extractor/common.py +++ b/youtube_dl/extractor/common.py @@ -1794,7 +1794,7 @@ class InfoExtractor(object): out.append('{%s}%s' % (namespace, c)) return '/'.join(out) - def _extract_smil_formats(self, smil_url, video_id, fatal=True, f4m_params=None, transform_source=None): + def _extract_smil_formats(self, smil_url, video_id, fatal=True, f4m_params=None, transform_source=None, rtmp_securetoken=None): smil = self._download_smil(smil_url, video_id, fatal=fatal, transform_source=transform_source) if smil is False: @@ -1804,7 +1804,8 @@ class InfoExtractor(object): namespace = self._parse_smil_namespace(smil) return self._parse_smil_formats( - smil, smil_url, video_id, namespace=namespace, f4m_params=f4m_params) + smil, smil_url, video_id, namespace=namespace, f4m_params=f4m_params, + rtmp_securetoken=rtmp_securetoken) def _extract_smil_info(self, smil_url, video_id, fatal=True, f4m_params=None): smil = self._download_smil(smil_url, video_id, fatal=fatal) @@ -1861,7 +1862,7 @@ class InfoExtractor(object): return self._search_regex( r'(?i)^{([^}]+)?}smil$', smil.tag, 'namespace', default=None) - def _parse_smil_formats(self, smil, smil_url, video_id, namespace=None, f4m_params=None, transform_rtmp_url=None): + def _parse_smil_formats(self, smil, smil_url, video_id, namespace=None, f4m_params=None, transform_rtmp_url=None, rtmp_securetoken=None): base = smil_url for meta in smil.findall(self._xpath_ns('./head/meta', namespace)): b = meta.get('base') or meta.get('httpBase') @@ -1903,6 +1904,8 @@ class InfoExtractor(object): 'width': width, 'height': height, }) + if rtmp_securetoken: + formats[-1]['rtmp_securetoken'] = rtmp_securetoken if transform_rtmp_url: streamer, src = transform_rtmp_url(streamer, src) formats[-1].update({ From a3158f41b12cdfc39c9fafe94a190a0740285193 Mon Sep 17 00:00:00 2001 From: felix Date: Sat, 2 Apr 2016 11:43:17 +0200 Subject: [PATCH 3/3] [stolaf] new extractor --- youtube_dl/extractor/extractors.py | 1 + youtube_dl/extractor/stolaf.py | 78 ++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 youtube_dl/extractor/stolaf.py diff --git a/youtube_dl/extractor/extractors.py b/youtube_dl/extractor/extractors.py index 465d9d364..8c77cd373 100644 --- a/youtube_dl/extractor/extractors.py +++ b/youtube_dl/extractor/extractors.py @@ -1056,6 +1056,7 @@ from .srgssr import ( from .srmediathek import SRMediathekIE from .stanfordoc import StanfordOpenClassroomIE from .steam import SteamIE +from .stolaf import StOlafIE from .streamable import StreamableIE from .streamcloud import StreamcloudIE from .streamcz import StreamCZIE diff --git a/youtube_dl/extractor/stolaf.py b/youtube_dl/extractor/stolaf.py new file mode 100644 index 000000000..321c58438 --- /dev/null +++ b/youtube_dl/extractor/stolaf.py @@ -0,0 +1,78 @@ +from __future__ import unicode_literals + +from .common import InfoExtractor +from ..utils import js_to_json + + +class StOlafIE(InfoExtractor): + _VALID_URL = r'^https?://(?:www\.)?stolaf\.edu/multimedia/play/\?e=(?P\d+)' + _TESTS = [{ + 'url': 'https://www.stolaf.edu/multimedia/play/?e=573', + 'info_dict': { + 'id': '573', + 'ext': 'mp4', + 'title': 'Senior Soloists Concert', + 'description': 'St. Olaf Orchestra & Senior Soloists', + 'thumbnail': 'http://www.stolaf.edu/multimedia/components/poster/e573', + }, + 'params': { + 'skip_download': True, # because m3u8 + }, + }] + + def _real_extract(self, url): + playlist_id = self._match_id(url) + + webpage = self._download_webpage(url, playlist_id) + + title = self._og_search_property('title', webpage) + description = self._og_search_property('description', webpage) + + javascript = self._download_webpage( + 'http://www.stolaf.edu/multimedia/components/eventlib.cfc', + playlist_id, 'Downloading playlist #%u' % (3), + query={ + 'method': 'getPlayerPlaylist', + 'eventtype': 'e', + 'eventid': playlist_id, + # param below selects quality of the m3u8 stream; any floating-point + # constant is accepted, but values above 3 are clamped. only + # 1, 2 and 3 seem to give actual streams, though. + # XXX: request all three? or transform the URL locally? + 'html5stream': 3 + }) + thePlaylist = self._parse_json( + self._search_regex(r'(?s)thePlaylist\s*=\s*(\[.*?\]);', javascript, 'thePlaylist'), + playlist_id, transform_source=js_to_json) + token = self._search_regex(r'n7kIjJed73\s*=\s*\'(.*?)\';', javascript, 'token') + + entries = [] + for (i, item) in enumerate(thePlaylist): + video_id = '%s-%u' % (playlist_id, i) + formats = [] + for (j, source) in enumerate(item['sources']): + if source.get('type') == 'rtmp': + formats.extend(self._extract_smil_formats('//stolaf.edu' + source['file'], video_id, rtmp_securetoken=token)) + else: + formats.extend(self._extract_m3u8_formats(source['file'], video_id, 'mp4')) + + entries.append({ + 'id': video_id, + 'title': title, + 'description': description, + 'formats': formats, + 'thumbnail': item.get('image'), + }) + + if len(entries) == 1: + result = entries[0] + result['id'] = playlist_id + return result + + return { + '_type': 'multi_video', + 'id': playlist_id, + 'title': title, + 'description': description, + 'entries': entries, + }