diff options
| -rw-r--r-- | youtube_dl/extractor/bellmedia.py | 5 | ||||
| -rw-r--r-- | youtube_dl/extractor/disney.py | 60 | ||||
| -rw-r--r-- | youtube_dl/extractor/generic.py | 22 | ||||
| -rw-r--r-- | youtube_dl/extractor/limelight.py | 23 | 
4 files changed, 78 insertions, 32 deletions
diff --git a/youtube_dl/extractor/bellmedia.py b/youtube_dl/extractor/bellmedia.py index 32326ed9e..1f5b6ed92 100644 --- a/youtube_dl/extractor/bellmedia.py +++ b/youtube_dl/extractor/bellmedia.py @@ -24,7 +24,7 @@ class BellMediaIE(InfoExtractor):                  space              )\.ca|              much\.com -        )/.*?(?:\bvid=|-vid|~|%7E|/(?:episode)?)(?P<id>[0-9]{6})''' +        )/.*?(?:\bvid=|-vid|~|%7E|/(?:episode)?)(?P<id>[0-9]{6,})'''      _TESTS = [{          'url': 'http://www.ctv.ca/video/player?vid=706966',          'md5': 'ff2ebbeae0aa2dcc32a830c3fd69b7b0', @@ -55,6 +55,9 @@ class BellMediaIE(InfoExtractor):      }, {          'url': 'http://www.much.com/shows/the-almost-impossible-gameshow/928979/episode-6',          'only_matching': True, +    }, { +        'url': 'http://www.ctv.ca/DCs-Legends-of-Tomorrow/Video/S2E11-Turncoat-vid1051430', +        'only_matching': True,      }]      _DOMAINS = {          'thecomedynetwork': 'comedy', diff --git a/youtube_dl/extractor/disney.py b/youtube_dl/extractor/disney.py index 396873c6d..939d1338c 100644 --- a/youtube_dl/extractor/disney.py +++ b/youtube_dl/extractor/disney.py @@ -9,13 +9,15 @@ from ..utils import (      unified_strdate,      compat_str,      determine_ext, +    ExtractorError,  )  class DisneyIE(InfoExtractor):      _VALID_URL = r'''(?x) -        https?://(?P<domain>(?:[^/]+\.)?(?:disney\.[a-z]{2,3}(?:\.[a-z]{2})?|disney(?:(?:me|latino)\.com|turkiye\.com\.tr)|starwars\.com))/(?:embed/|(?:[^/]+/)+[\w-]+-)(?P<id>[a-z0-9]{24})''' +        https?://(?P<domain>(?:[^/]+\.)?(?:disney\.[a-z]{2,3}(?:\.[a-z]{2})?|disney(?:(?:me|latino)\.com|turkiye\.com\.tr)|(?:starwars|marvelkids)\.com))/(?:(?:embed/|(?:[^/]+/)+[\w-]+-)(?P<id>[a-z0-9]{24})|(?:[^/]+/)?(?P<display_id>[^/?#]+))'''      _TESTS = [{ +        # Disney.EmbedVideo          'url': 'http://video.disney.com/watch/moana-trailer-545ed1857afee5a0ec239977',          'info_dict': {              'id': '545ed1857afee5a0ec239977', @@ -29,6 +31,20 @@ class DisneyIE(InfoExtractor):              'skip_download': True,          }      }, { +        # Grill.burger +        'url': 'http://www.starwars.com/video/rogue-one-a-star-wars-story-intro-featurette', +        'info_dict': { +            'id': '5454e9f4e9804a552e3524c8', +            'ext': 'mp4', +            'title': '"Intro" Featurette: Rogue One: A Star Wars Story', +            'upload_date': '20170104', +            'description': 'Go behind-the-scenes of Rogue One: A Star Wars Story in this featurette with Director Gareth Edwards and the cast of the film.', +        }, +        'params': { +            # m3u8 download +            'skip_download': True, +        } +    }, {          'url': 'http://videos.disneylatino.com/ver/spider-man-de-regreso-a-casa-primer-adelanto-543a33a1850bdcfcca13bae2',          'only_matching': True,      }, { @@ -43,31 +59,55 @@ class DisneyIE(InfoExtractor):      }, {          'url': 'http://www.starwars.com/embed/54690d1e6c42e5f09a0fb097',          'only_matching': True, +    }, { +        'url': 'http://spiderman.marvelkids.com/embed/522900d2ced3c565e4cc0677', +        'only_matching': True, +    }, { +        'url': 'http://spiderman.marvelkids.com/videos/contest-of-champions-part-four-clip-1', +        'only_matching': True, +    }, { +        'url': 'http://disneyjunior.en.disneyme.com/dj/watch-my-friends-tigger-and-pooh-promo', +        'only_matching': True, +    }, { +        'url': 'http://disneyjunior.disney.com/galactech-the-galactech-grab-galactech-an-admiral-rescue', +        'only_matching': True,      }]      def _real_extract(self, url): -        domain, video_id = re.match(self._VALID_URL, url).groups() -        webpage = self._download_webpage( -            'http://%s/embed/%s' % (domain, video_id), video_id) -        video_data = self._parse_json(self._search_regex( -            r'Disney\.EmbedVideo=({.+});', webpage, 'embed data'), video_id)['video'] +        domain, video_id, display_id = re.match(self._VALID_URL, url).groups() +        if not video_id: +            webpage = self._download_webpage(url, display_id) +            grill = re.sub(r'"\s*\+\s*"', '', self._search_regex( +                r'Grill\.burger\s*=\s*({.+})\s*:', +                webpage, 'grill data')) +            page_data = next(s for s in self._parse_json(grill, display_id)['stack'] if s.get('type') == 'video') +            video_data = page_data['data'][0] +        else: +            webpage = self._download_webpage( +                'http://%s/embed/%s' % (domain, video_id), video_id) +            page_data = self._parse_json(self._search_regex( +                r'Disney\.EmbedVideo\s*=\s*({.+});', +                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']          formats = []          for flavor in video_data.get('flavors', []):              flavor_format = flavor.get('format')              flavor_url = flavor.get('url') -            if not flavor_url or not re.match(r'https?://', flavor_url): +            if not flavor_url or not re.match(r'https?://', flavor_url) or flavor_format == 'mp4_access':                  continue              tbr = int_or_none(flavor.get('bitrate'))              if tbr == 99999:                  formats.extend(self._extract_m3u8_formats( -                    flavor_url, video_id, 'mp4', m3u8_id=flavor_format, fatal=False)) +                    flavor_url, video_id, 'mp4', +                    m3u8_id=flavor_format, fatal=False))                  continue              format_id = []              if flavor_format: @@ -88,6 +128,10 @@ class DisneyIE(InfoExtractor):                  'ext': ext,                  'vcodec': 'none' if (width == 0 and height == 0) else None,              }) +        if not formats and video_data.get('expired'): +            raise ExtractorError( +                '%s said: %s' % (self.IE_NAME, page_data['translations']['video_expired']), +                expected=True)          self._sort_formats(formats)          subtitles = {} diff --git a/youtube_dl/extractor/generic.py b/youtube_dl/extractor/generic.py index 1c233f038..a2b0298ec 100644 --- a/youtube_dl/extractor/generic.py +++ b/youtube_dl/extractor/generic.py @@ -991,19 +991,6 @@ class GenericIE(InfoExtractor):                  'title': 'Os Guinness // Is It Fools Talk? // Unbelievable? Conference 2014',              },          }, -        # Kaltura embed protected with referrer -        { -            'url': 'http://www.disney.nl/disney-channel/filmpjes/achter-de-schermen#/videoId/violetta-achter-de-schermen-ruggero', -            'info_dict': { -                'id': '1_g4fbemnq', -                'ext': 'mp4', -                'title': 'Violetta - Achter De Schermen - Ruggero', -                'description': 'Achter de schermen met Ruggero', -                'timestamp': 1435133761, -                'upload_date': '20150624', -                'uploader_id': 'echojecka', -            }, -        },          # Kaltura embed with single quotes          {              'url': 'http://fod.infobase.com/p_ViewPlaylist.aspx?AssignmentID=NUN8ZY', @@ -2350,8 +2337,9 @@ class GenericIE(InfoExtractor):                  'Channel': 'channel',                  'ChannelList': 'channel_list',              } -            return self.url_result('limelight:%s:%s' % ( -                lm[mobj.group(1)], mobj.group(2)), 'Limelight%s' % mobj.group(1), mobj.group(2)) +            return self.url_result(smuggle_url('limelight:%s:%s' % ( +                lm[mobj.group(1)], mobj.group(2)), {'source_url': url}), +                'Limelight%s' % mobj.group(1), mobj.group(2))          mobj = re.search(              r'''(?sx) @@ -2361,7 +2349,9 @@ class GenericIE(InfoExtractor):                          value=(["\'])(?:(?!\3).)*mediaId=(?P<id>[a-z0-9]{32})              ''', webpage)          if mobj: -            return self.url_result('limelight:media:%s' % mobj.group('id')) +            return self.url_result(smuggle_url( +                'limelight:media:%s' % mobj.group('id'), +                {'source_url': url}), 'LimelightMedia', mobj.group('id'))          # Look for AdobeTVVideo embeds          mobj = re.search( diff --git a/youtube_dl/extractor/limelight.py b/youtube_dl/extractor/limelight.py index e635f3c4d..a3712665b 100644 --- a/youtube_dl/extractor/limelight.py +++ b/youtube_dl/extractor/limelight.py @@ -8,6 +8,7 @@ from ..utils import (      determine_ext,      float_or_none,      int_or_none, +    unsmuggle_url,  ) @@ -15,20 +16,23 @@ class LimelightBaseIE(InfoExtractor):      _PLAYLIST_SERVICE_URL = 'http://production-ps.lvp.llnw.net/r/PlaylistService/%s/%s/%s'      _API_URL = 'http://api.video.limelight.com/rest/organizations/%s/%s/%s/%s.json' -    def _call_playlist_service(self, item_id, method, fatal=True): +    def _call_playlist_service(self, item_id, method, fatal=True, referer=None): +        headers = {} +        if referer: +            headers['Referer'] = referer          return self._download_json(              self._PLAYLIST_SERVICE_URL % (self._PLAYLIST_SERVICE_PATH, item_id, method), -            item_id, 'Downloading PlaylistService %s JSON' % method, fatal=fatal) +            item_id, 'Downloading PlaylistService %s JSON' % method, fatal=fatal, headers=headers)      def _call_api(self, organization_id, item_id, method):          return self._download_json(              self._API_URL % (organization_id, self._API_PATH, item_id, method),              item_id, 'Downloading API %s JSON' % method) -    def _extract(self, item_id, pc_method, mobile_method, meta_method): -        pc = self._call_playlist_service(item_id, pc_method) +    def _extract(self, item_id, pc_method, mobile_method, meta_method, referer=None): +        pc = self._call_playlist_service(item_id, pc_method, referer=referer)          metadata = self._call_api(pc['orgId'], item_id, meta_method) -        mobile = self._call_playlist_service(item_id, mobile_method, fatal=False) +        mobile = self._call_playlist_service(item_id, mobile_method, fatal=False, referer=referer)          return pc, mobile, metadata      def _extract_info(self, streams, mobile_urls, properties): @@ -207,10 +211,13 @@ class LimelightMediaIE(LimelightBaseIE):      _API_PATH = 'media'      def _real_extract(self, url): +        url, smuggled_data = unsmuggle_url(url, {})          video_id = self._match_id(url)          pc, mobile, metadata = self._extract( -            video_id, 'getPlaylistByMediaId', 'getMobilePlaylistByMediaId', 'properties') +            video_id, 'getPlaylistByMediaId', +            'getMobilePlaylistByMediaId', 'properties', +            smuggled_data.get('source_url'))          return self._extract_info(              pc['playlistItems'][0].get('streams', []), @@ -247,11 +254,13 @@ class LimelightChannelIE(LimelightBaseIE):      _API_PATH = 'channels'      def _real_extract(self, url): +        url, smuggled_data = unsmuggle_url(url, {})          channel_id = self._match_id(url)          pc, mobile, medias = self._extract(              channel_id, 'getPlaylistByChannelId', -            'getMobilePlaylistWithNItemsByChannelId?begin=0&count=-1', 'media') +            'getMobilePlaylistWithNItemsByChannelId?begin=0&count=-1', +            'media', smuggled_data.get('source_url'))          entries = [              self._extract_info(  | 
