diff options
Diffstat (limited to 'youtube_dl/extractor/dplay.py')
| -rw-r--r-- | youtube_dl/extractor/dplay.py | 123 | 
1 files changed, 95 insertions, 28 deletions
| diff --git a/youtube_dl/extractor/dplay.py b/youtube_dl/extractor/dplay.py index 47501dbe6..540505719 100644 --- a/youtube_dl/extractor/dplay.py +++ b/youtube_dl/extractor/dplay.py @@ -1,6 +1,7 @@  # coding: utf-8  from __future__ import unicode_literals +import json  import re  from .common import InfoExtractor @@ -151,56 +152,79 @@ class DPlayIE(InfoExtractor):          'only_matching': True,      }] +    def _process_errors(self, e, geo_countries): +        info = self._parse_json(e.cause.read().decode('utf-8'), None) +        error = info['errors'][0] +        error_code = error.get('code') +        if error_code == 'access.denied.geoblocked': +            self.raise_geo_restricted(countries=geo_countries) +        elif error_code in ('access.denied.missingpackage', 'invalid.token'): +            raise ExtractorError( +                'This video is only available for registered users. You may want to use --cookies.', expected=True) +        raise ExtractorError(info['errors'][0]['detail'], expected=True) + +    def _update_disco_api_headers(self, headers, disco_base, display_id, realm): +        headers['Authorization'] = 'Bearer ' + self._download_json( +            disco_base + 'token', display_id, 'Downloading token', +            query={ +                'realm': realm, +            })['data']['attributes']['token'] + +    def _download_video_playback_info(self, disco_base, video_id, headers): +        streaming = self._download_json( +            disco_base + 'playback/videoPlaybackInfo/' + video_id, +            video_id, headers=headers)['data']['attributes']['streaming'] +        streaming_list = [] +        for format_id, format_dict in streaming.items(): +            streaming_list.append({ +                'type': format_id, +                'url': format_dict.get('url'), +            }) +        return streaming_list +      def _get_disco_api_info(self, url, display_id, disco_host, realm, country):          geo_countries = [country.upper()]          self._initialize_geo_bypass({              'countries': geo_countries,          })          disco_base = 'https://%s/' % disco_host -        token = self._download_json( -            disco_base + 'token', display_id, 'Downloading token', -            query={ -                'realm': realm, -            })['data']['attributes']['token']          headers = {              'Referer': url, -            'Authorization': 'Bearer ' + token,          } -        video = self._download_json( -            disco_base + 'content/videos/' + display_id, display_id, -            headers=headers, query={ -                'fields[channel]': 'name', -                'fields[image]': 'height,src,width', -                'fields[show]': 'name', -                'fields[tag]': 'name', -                'fields[video]': 'description,episodeNumber,name,publishStart,seasonNumber,videoDuration', -                'include': 'images,primaryChannel,show,tags' -            }) +        self._update_disco_api_headers(headers, disco_base, display_id, realm) +        try: +            video = self._download_json( +                disco_base + 'content/videos/' + display_id, display_id, +                headers=headers, query={ +                    'fields[channel]': 'name', +                    'fields[image]': 'height,src,width', +                    'fields[show]': 'name', +                    'fields[tag]': 'name', +                    'fields[video]': 'description,episodeNumber,name,publishStart,seasonNumber,videoDuration', +                    'include': 'images,primaryChannel,show,tags' +                }) +        except ExtractorError as e: +            if isinstance(e.cause, compat_HTTPError) and e.cause.code == 400: +                self._process_errors(e, geo_countries) +            raise          video_id = video['data']['id']          info = video['data']['attributes']          title = info['name'].strip()          formats = []          try: -            streaming = self._download_json( -                disco_base + 'playback/videoPlaybackInfo/' + video_id, -                display_id, headers=headers)['data']['attributes']['streaming'] +            streaming = self._download_video_playback_info( +                disco_base, video_id, headers)          except ExtractorError as e:              if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403: -                info = self._parse_json(e.cause.read().decode('utf-8'), display_id) -                error = info['errors'][0] -                error_code = error.get('code') -                if error_code == 'access.denied.geoblocked': -                    self.raise_geo_restricted(countries=geo_countries) -                elif error_code == 'access.denied.missingpackage': -                    self.raise_login_required() -                raise ExtractorError(info['errors'][0]['detail'], expected=True) +                self._process_errors(e, geo_countries)              raise -        for format_id, format_dict in streaming.items(): +        for format_dict in streaming:              if not isinstance(format_dict, dict):                  continue              format_url = format_dict.get('url')              if not format_url:                  continue +            format_id = format_dict.get('type')              ext = determine_ext(format_url)              if format_id == 'dash' or ext == 'mpd':                  formats.extend(self._extract_mpd_formats( @@ -268,3 +292,46 @@ class DPlayIE(InfoExtractor):          host = 'disco-api.' + domain if domain[0] == 'd' else 'eu2-prod.disco-api.com'          return self._get_disco_api_info(              url, display_id, host, 'dplay' + country, country) + + +class DiscoveryPlusIE(DPlayIE): +    _VALID_URL = r'https?://(?:www\.)?discoveryplus\.com/video/(?P<id>[^/]+/[^/]+)' +    _TESTS = [{ +        'url': 'https://www.discoveryplus.com/video/property-brothers-forever-home/food-and-family', +        'info_dict': { +            'id': '1140794', +            'display_id': 'property-brothers-forever-home/food-and-family', +            'ext': 'mp4', +            'title': 'Food and Family', +            'description': 'The brothers help a Richmond family expand their single-level home.', +            'duration': 2583.113, +            'timestamp': 1609304400, +            'upload_date': '20201230', +            'creator': 'HGTV', +            'series': 'Property Brothers: Forever Home', +            'season_number': 1, +            'episode_number': 1, +        }, +        'skip': 'Available for Premium users', +    }] + +    def _update_disco_api_headers(self, headers, disco_base, display_id, realm): +        headers['x-disco-client'] = 'WEB:UNKNOWN:dplus_us:15.0.0' + +    def _download_video_playback_info(self, disco_base, video_id, headers): +        return self._download_json( +            disco_base + 'playback/v3/videoPlaybackInfo', +            video_id, headers=headers, data=json.dumps({ +                'deviceInfo': { +                    'adBlocker': False, +                }, +                'videoId': video_id, +                'wisteriaProperties': { +                    'platform': 'desktop', +                }, +            }).encode('utf-8'))['data']['attributes']['streaming'] + +    def _real_extract(self, url): +        display_id = self._match_id(url) +        return self._get_disco_api_info( +            url, display_id, 'us1-prod-direct.discoveryplus.com', 'go', 'us') | 
