[youtube] fix hd720 format position
[youtube-dl] / youtube_dl / extractor / laola1tv.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 import json
5
6 from .common import InfoExtractor
7 from ..utils import (
8     ExtractorError,
9     unified_strdate,
10     urlencode_postdata,
11     xpath_element,
12     xpath_text,
13     update_url_query,
14     js_to_json,
15 )
16
17
18 class Laola1TvEmbedIE(InfoExtractor):
19     IE_NAME = 'laola1tv:embed'
20     _VALID_URL = r'https?://(?:www\.)?laola1\.tv/titanplayer\.php\?.*?\bvideoid=(?P<id>\d+)'
21     _TESTS = [{
22         # flashvars.premium = "false";
23         'url': 'https://www.laola1.tv/titanplayer.php?videoid=708065&type=V&lang=en&portal=int&customer=1024',
24         'info_dict': {
25             'id': '708065',
26             'ext': 'mp4',
27             'title': 'MA Long CHN - FAN Zhendong CHN',
28             'uploader': 'ITTF - International Table Tennis Federation',
29             'upload_date': '20161211',
30         },
31     }]
32
33     def _extract_token_url(self, stream_access_url, video_id, data):
34         return self._download_json(
35             stream_access_url, video_id, headers={
36                 'Content-Type': 'application/json',
37             }, data=json.dumps(data).encode())['data']['stream-access'][0]
38
39     def _extract_formats(self, token_url, video_id):
40         token_doc = self._download_xml(
41             token_url, video_id, 'Downloading token',
42             headers=self.geo_verification_headers())
43
44         token_attrib = xpath_element(token_doc, './/token').attrib
45
46         if token_attrib['status'] != '0':
47             raise ExtractorError(
48                 'Token error: %s' % token_attrib['comment'], expected=True)
49
50         formats = self._extract_akamai_formats(
51             '%s?hdnea=%s' % (token_attrib['url'], token_attrib['auth']),
52             video_id)
53         self._sort_formats(formats)
54         return formats
55
56     def _real_extract(self, url):
57         video_id = self._match_id(url)
58         webpage = self._download_webpage(url, video_id)
59         flash_vars = self._search_regex(
60             r'(?s)flashvars\s*=\s*({.+?});', webpage, 'flash vars')
61
62         def get_flashvar(x, *args, **kwargs):
63             flash_var = self._search_regex(
64                 r'%s\s*:\s*"([^"]+)"' % x,
65                 flash_vars, x, default=None)
66             if not flash_var:
67                 flash_var = self._search_regex([
68                     r'flashvars\.%s\s*=\s*"([^"]+)"' % x,
69                     r'%s\s*=\s*"([^"]+)"' % x],
70                     webpage, x, *args, **kwargs)
71             return flash_var
72
73         hd_doc = self._download_xml(
74             'http://www.laola1.tv/server/hd_video.php', video_id, query={
75                 'play': get_flashvar('streamid'),
76                 'partner': get_flashvar('partnerid'),
77                 'portal': get_flashvar('portalid'),
78                 'lang': get_flashvar('sprache'),
79                 'v5ident': '',
80             })
81
82         _v = lambda x, **k: xpath_text(hd_doc, './/video/' + x, **k)
83         title = _v('title', fatal=True)
84
85         token_url = None
86         premium = get_flashvar('premium', default=None)
87         if premium:
88             token_url = update_url_query(
89                 _v('url', fatal=True), {
90                     'timestamp': get_flashvar('timestamp'),
91                     'auth': get_flashvar('auth'),
92                 })
93         else:
94             data_abo = urlencode_postdata(
95                 dict((i, v) for i, v in enumerate(_v('req_liga_abos').split(','))))
96             stream_access_url = update_url_query(
97                 'https://club.laola1.tv/sp/laola1/api/v3/user/session/premium/player/stream-access', {
98                     'videoId': _v('id'),
99                     'target': self._search_regex(r'vs_target = (\d+);', webpage, 'vs target'),
100                     'label': _v('label'),
101                     'area': _v('area'),
102                 })
103             token_url = self._extract_token_url(stream_access_url, video_id, data_abo)
104
105         formats = self._extract_formats(token_url, video_id)
106
107         categories_str = _v('meta_sports')
108         categories = categories_str.split(',') if categories_str else []
109         is_live = _v('islive') == 'true'
110
111         return {
112             'id': video_id,
113             'title': self._live_title(title) if is_live else title,
114             'upload_date': unified_strdate(_v('time_date')),
115             'uploader': _v('meta_organisation'),
116             'categories': categories,
117             'is_live': is_live,
118             'formats': formats,
119         }
120
121
122 class Laola1TvIE(Laola1TvEmbedIE):
123     IE_NAME = 'laola1tv'
124     _VALID_URL = r'https?://(?:www\.)?laola1\.tv/[a-z]+-[a-z]+/[^/]+/(?P<id>[^/?#&]+)'
125     _TESTS = [{
126         'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie/227883.html',
127         'info_dict': {
128             'id': '227883',
129             'display_id': 'straubing-tigers-koelner-haie',
130             'ext': 'flv',
131             'title': 'Straubing Tigers - Kölner Haie',
132             'upload_date': '20140912',
133             'is_live': False,
134             'categories': ['Eishockey'],
135         },
136         'params': {
137             'skip_download': True,
138         },
139     }, {
140         'url': 'http://www.laola1.tv/de-de/video/straubing-tigers-koelner-haie',
141         'info_dict': {
142             'id': '464602',
143             'display_id': 'straubing-tigers-koelner-haie',
144             'ext': 'flv',
145             'title': 'Straubing Tigers - Kölner Haie',
146             'upload_date': '20160129',
147             'is_live': False,
148             'categories': ['Eishockey'],
149         },
150         'params': {
151             'skip_download': True,
152         },
153     }, {
154         'url': 'http://www.laola1.tv/de-de/livestream/2016-03-22-belogorie-belgorod-trentino-diatec-lde',
155         'info_dict': {
156             'id': '487850',
157             'display_id': '2016-03-22-belogorie-belgorod-trentino-diatec-lde',
158             'ext': 'flv',
159             'title': 'Belogorie BELGOROD - TRENTINO Diatec',
160             'upload_date': '20160322',
161             'uploader': 'CEV - Europäischer Volleyball Verband',
162             'is_live': True,
163             'categories': ['Volleyball'],
164         },
165         'params': {
166             'skip_download': True,
167         },
168         'skip': 'This live stream has already finished.',
169     }]
170
171     def _real_extract(self, url):
172         display_id = self._match_id(url)
173
174         webpage = self._download_webpage(url, display_id)
175
176         if 'Dieser Livestream ist bereits beendet.' in webpage:
177             raise ExtractorError('This live stream has already finished.', expected=True)
178
179         conf = self._parse_json(self._search_regex(
180             r'(?s)conf\s*=\s*({.+?});', webpage, 'conf'),
181             display_id, js_to_json)
182
183         video_id = conf['videoid']
184
185         config = self._download_json(conf['configUrl'], video_id, query={
186             'videoid': video_id,
187             'partnerid': conf['partnerid'],
188             'language': conf.get('language', ''),
189             'portal': conf.get('portalid', ''),
190         })
191         error = config.get('error')
192         if error:
193             raise ExtractorError('%s said: %s' % (self.IE_NAME, error), expected=True)
194
195         video_data = config['video']
196         title = video_data['title']
197         is_live = video_data.get('isLivestream') and video_data.get('isLive')
198         meta = video_data.get('metaInformation')
199         sports = meta.get('sports')
200         categories = sports.split(',') if sports else []
201
202         token_url = self._extract_token_url(
203             video_data['streamAccess'], video_id,
204             video_data['abo']['required'])
205
206         formats = self._extract_formats(token_url, video_id)
207
208         return {
209             'id': video_id,
210             'display_id': display_id,
211             'title': self._live_title(title) if is_live else title,
212             'description': video_data.get('description'),
213             'thumbnail': video_data.get('image'),
214             'categories': categories,
215             'formats': formats,
216             'is_live': is_live,
217         }
218
219
220 class ITTFIE(InfoExtractor):
221     _VALID_URL = r'https?://tv\.ittf\.com/video/[^/]+/(?P<id>\d+)'
222     _TEST = {
223         'url': 'https://tv.ittf.com/video/peng-wang-wei-matsudaira-kenta/951802',
224         'only_matching': True,
225     }
226
227     def _real_extract(self, url):
228         return self.url_result(
229             update_url_query('https://www.laola1.tv/titanplayer.php', {
230                 'videoid': self._match_id(url),
231                 'type': 'V',
232                 'lang': 'en',
233                 'portal': 'int',
234                 'customer': 1024,
235             }), Laola1TvEmbedIE.ie_key())