[youtube] Fix extraction.
[youtube-dl] / youtube_dl / extractor / imggaming.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 import json
5 import re
6
7 from .common import InfoExtractor
8 from ..compat import compat_HTTPError
9 from ..utils import (
10     ExtractorError,
11     int_or_none,
12     str_or_none,
13     try_get,
14 )
15
16
17 class ImgGamingBaseIE(InfoExtractor):
18     _API_BASE = 'https://dce-frontoffice.imggaming.com/api/v2/'
19     _API_KEY = '857a1e5d-e35e-4fdf-805b-a87b6f8364bf'
20     _HEADERS = None
21     _MANIFEST_HEADERS = {'Accept-Encoding': 'identity'}
22     _REALM = None
23     _VALID_URL_TEMPL = r'https?://(?P<domain>%s)/(?P<type>live|playlist|video)/(?P<id>\d+)(?:\?.*?\bplaylistId=(?P<playlist_id>\d+))?'
24
25     def _real_initialize(self):
26         self._HEADERS = {
27             'Realm': 'dce.' + self._REALM,
28             'x-api-key': self._API_KEY,
29         }
30
31         email, password = self._get_login_info()
32         if email is None:
33             self.raise_login_required()
34
35         p_headers = self._HEADERS.copy()
36         p_headers['Content-Type'] = 'application/json'
37         self._HEADERS['Authorization'] = 'Bearer ' + self._download_json(
38             self._API_BASE + 'login',
39             None, 'Logging in', data=json.dumps({
40                 'id': email,
41                 'secret': password,
42             }).encode(), headers=p_headers)['authorisationToken']
43
44     def _call_api(self, path, media_id):
45         return self._download_json(
46             self._API_BASE + path + media_id, media_id, headers=self._HEADERS)
47
48     def _extract_dve_api_url(self, media_id, media_type):
49         stream_path = 'stream'
50         if media_type == 'video':
51             stream_path += '/vod/'
52         else:
53             stream_path += '?eventId='
54         try:
55             return self._call_api(
56                 stream_path, media_id)['playerUrlCallback']
57         except ExtractorError as e:
58             if isinstance(e.cause, compat_HTTPError) and e.cause.code == 403:
59                 raise ExtractorError(
60                     self._parse_json(e.cause.read().decode(), media_id)['messages'][0],
61                     expected=True)
62             raise
63
64     def _real_extract(self, url):
65         domain, media_type, media_id, playlist_id = re.match(self._VALID_URL, url).groups()
66
67         if playlist_id:
68             if self._downloader.params.get('noplaylist'):
69                 self.to_screen('Downloading just video %s because of --no-playlist' % media_id)
70             else:
71                 self.to_screen('Downloading playlist %s - add --no-playlist to just download video' % playlist_id)
72                 media_type, media_id = 'playlist', playlist_id
73
74         if media_type == 'playlist':
75             playlist = self._call_api('vod/playlist/', media_id)
76             entries = []
77             for video in try_get(playlist, lambda x: x['videos']['vods']) or []:
78                 video_id = str_or_none(video.get('id'))
79                 if not video_id:
80                     continue
81                 entries.append(self.url_result(
82                     'https://%s/video/%s' % (domain, video_id),
83                     self.ie_key(), video_id))
84             return self.playlist_result(
85                 entries, media_id, playlist.get('title'),
86                 playlist.get('description'))
87
88         dve_api_url = self._extract_dve_api_url(media_id, media_type)
89         video_data = self._download_json(dve_api_url, media_id)
90         is_live = media_type == 'live'
91         if is_live:
92             title = self._live_title(self._call_api('event/', media_id)['title'])
93         else:
94             title = video_data['name']
95
96         formats = []
97         for proto in ('hls', 'dash'):
98             media_url = video_data.get(proto + 'Url') or try_get(video_data, lambda x: x[proto]['url'])
99             if not media_url:
100                 continue
101             if proto == 'hls':
102                 m3u8_formats = self._extract_m3u8_formats(
103                     media_url, media_id, 'mp4', 'm3u8' if is_live else 'm3u8_native',
104                     m3u8_id='hls', fatal=False, headers=self._MANIFEST_HEADERS)
105                 for f in m3u8_formats:
106                     f.setdefault('http_headers', {}).update(self._MANIFEST_HEADERS)
107                     formats.append(f)
108             else:
109                 formats.extend(self._extract_mpd_formats(
110                     media_url, media_id, mpd_id='dash', fatal=False,
111                     headers=self._MANIFEST_HEADERS))
112         self._sort_formats(formats)
113
114         subtitles = {}
115         for subtitle in video_data.get('subtitles', []):
116             subtitle_url = subtitle.get('url')
117             if not subtitle_url:
118                 continue
119             subtitles.setdefault(subtitle.get('lang', 'en_US'), []).append({
120                 'url': subtitle_url,
121             })
122
123         return {
124             'id': media_id,
125             'title': title,
126             'formats': formats,
127             'thumbnail': video_data.get('thumbnailUrl'),
128             'description': video_data.get('description'),
129             'duration': int_or_none(video_data.get('duration')),
130             'tags': video_data.get('tags'),
131             'is_live': is_live,
132             'subtitles': subtitles,
133         }