]>
Commit | Line | Data |
---|---|---|
185744f9 RA |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
1dd58e14 RA |
4 | import re |
5 | ||
185744f9 RA |
6 | from .common import InfoExtractor |
7 | from ..compat import compat_str | |
8 | from ..utils import ( | |
9 | unescapeHTML, | |
1dd58e14 RA |
10 | parse_duration, |
11 | get_element_by_class, | |
185744f9 RA |
12 | ) |
13 | ||
14 | ||
15 | class LEGOIE(InfoExtractor): | |
1dd58e14 RA |
16 | _VALID_URL = r'https?://(?:www\.)?lego\.com/(?P<locale>[^/]+)/(?:[^/]+/)*videos/(?:[^/]+/)*[^/?#]+-(?P<id>[0-9a-f]+)' |
17 | _TESTS = [{ | |
185744f9 RA |
18 | 'url': 'http://www.lego.com/en-us/videos/themes/club/blocumentary-kawaguchi-55492d823b1b4d5e985787fa8c2973b1', |
19 | 'md5': 'f34468f176cfd76488767fc162c405fa', | |
20 | 'info_dict': { | |
21 | 'id': '55492d823b1b4d5e985787fa8c2973b1', | |
22 | 'ext': 'mp4', | |
23 | 'title': 'Blocumentary Great Creations: Akiyuki Kawaguchi', | |
1dd58e14 RA |
24 | 'description': 'Blocumentary Great Creations: Akiyuki Kawaguchi', |
25 | }, | |
26 | }, { | |
27 | # geo-restricted but the contentUrl contain a valid url | |
28 | 'url': 'http://www.lego.com/nl-nl/videos/themes/nexoknights/episode-20-kingdom-of-heroes-13bdc2299ab24d9685701a915b3d71e7##sp=399', | |
29 | 'md5': '4c3fec48a12e40c6e5995abc3d36cc2e', | |
30 | 'info_dict': { | |
31 | 'id': '13bdc2299ab24d9685701a915b3d71e7', | |
32 | 'ext': 'mp4', | |
33 | 'title': 'Aflevering 20 - Helden van het koninkrijk', | |
34 | 'description': 'md5:8ee499aac26d7fa8bcb0cedb7f9c3941', | |
35 | }, | |
36 | }, { | |
37 | # special characters in title | |
38 | 'url': 'http://www.lego.com/en-us/starwars/videos/lego-star-wars-force-surprise-9685ee9d12e84ff38e84b4e3d0db533d', | |
39 | 'info_dict': { | |
40 | 'id': '9685ee9d12e84ff38e84b4e3d0db533d', | |
41 | 'ext': 'mp4', | |
42 | 'title': 'Force Surprise – LEGO® Star Wars™ Microfighters', | |
43 | 'description': 'md5:9c673c96ce6f6271b88563fe9dc56de3', | |
44 | }, | |
45 | 'params': { | |
46 | 'skip_download': True, | |
47 | }, | |
48 | }] | |
185744f9 RA |
49 | _BITRATES = [256, 512, 1024, 1536, 2560] |
50 | ||
51 | def _real_extract(self, url): | |
1dd58e14 RA |
52 | locale, video_id = re.match(self._VALID_URL, url).groups() |
53 | webpage = self._download_webpage(url, video_id) | |
54 | title = get_element_by_class('video-header', webpage).strip() | |
55 | progressive_base = 'https://lc-mediaplayerns-live-s.legocdn.com/' | |
56 | streaming_base = 'http://legoprod-f.akamaihd.net/' | |
57 | content_url = self._html_search_meta('contentUrl', webpage) | |
58 | path = self._search_regex( | |
59 | r'(?:https?:)?//[^/]+/(?:[iz]/s/)?public/(.+)_[0-9,]+\.(?:mp4|webm)', | |
60 | content_url, 'video path', default=None) | |
61 | if not path: | |
62 | player_url = self._proto_relative_url(self._search_regex( | |
63 | r'<iframe[^>]+src="((?:https?)?//(?:www\.)?lego\.com/[^/]+/mediaplayer/video/[^"]+)', | |
64 | webpage, 'player url', default=None)) | |
65 | if not player_url: | |
66 | base_url = self._proto_relative_url(self._search_regex( | |
67 | r'data-baseurl="([^"]+)"', webpage, 'base url', | |
68 | default='http://www.lego.com/%s/mediaplayer/video/' % locale)) | |
69 | player_url = base_url + video_id | |
70 | player_webpage = self._download_webpage(player_url, video_id) | |
71 | video_data = self._parse_json(unescapeHTML(self._search_regex( | |
72 | r"video='([^']+)'", player_webpage, 'video data')), video_id) | |
73 | progressive_base = self._search_regex( | |
74 | r'data-video-progressive-url="([^"]+)"', | |
75 | player_webpage, 'progressive base', default='https://lc-mediaplayerns-live-s.legocdn.com/') | |
76 | streaming_base = self._search_regex( | |
77 | r'data-video-streaming-url="([^"]+)"', | |
78 | player_webpage, 'streaming base', default='http://legoprod-f.akamaihd.net/') | |
79 | item_id = video_data['ItemId'] | |
185744f9 | 80 | |
1dd58e14 RA |
81 | net_storage_path = video_data.get('NetStoragePath') or '/'.join([item_id[:2], item_id[2:4]]) |
82 | base_path = '_'.join([item_id, video_data['VideoId'], video_data['Locale'], compat_str(video_data['VideoVersion'])]) | |
83 | path = '/'.join([net_storage_path, base_path]) | |
185744f9 RA |
84 | streaming_path = ','.join(map(lambda bitrate: compat_str(bitrate), self._BITRATES)) |
85 | ||
86 | formats = self._extract_akamai_formats( | |
87 | '%si/s/public/%s_,%s,.mp4.csmil/master.m3u8' % (streaming_base, path, streaming_path), video_id) | |
88 | m3u8_formats = list(filter( | |
ff99fe52 | 89 | lambda f: f.get('protocol') == 'm3u8_native' and f.get('vcodec') != 'none', |
185744f9 RA |
90 | formats)) |
91 | if len(m3u8_formats) == len(self._BITRATES): | |
92 | self._sort_formats(m3u8_formats) | |
93 | for bitrate, m3u8_format in zip(self._BITRATES, m3u8_formats): | |
94 | progressive_base_url = '%spublic/%s_%d.' % (progressive_base, path, bitrate) | |
95 | mp4_f = m3u8_format.copy() | |
96 | mp4_f.update({ | |
97 | 'url': progressive_base_url + 'mp4', | |
98 | 'format_id': m3u8_format['format_id'].replace('hls', 'mp4'), | |
99 | 'protocol': 'http', | |
100 | }) | |
101 | web_f = { | |
102 | 'url': progressive_base_url + 'webm', | |
103 | 'format_id': m3u8_format['format_id'].replace('hls', 'webm'), | |
104 | 'width': m3u8_format['width'], | |
105 | 'height': m3u8_format['height'], | |
106 | 'tbr': m3u8_format.get('tbr'), | |
107 | 'ext': 'webm', | |
108 | } | |
109 | formats.extend([web_f, mp4_f]) | |
110 | else: | |
111 | for bitrate in self._BITRATES: | |
112 | for ext in ('web', 'mp4'): | |
113 | formats.append({ | |
114 | 'format_id': '%s-%s' % (ext, bitrate), | |
115 | 'url': '%spublic/%s_%d.%s' % (progressive_base, path, bitrate, ext), | |
116 | 'tbr': bitrate, | |
117 | 'ext': ext, | |
118 | }) | |
119 | self._sort_formats(formats) | |
120 | ||
121 | return { | |
122 | 'id': video_id, | |
123 | 'title': title, | |
1dd58e14 RA |
124 | 'description': self._html_search_meta('description', webpage), |
125 | 'thumbnail': self._html_search_meta('thumbnail', webpage), | |
126 | 'duration': parse_duration(self._html_search_meta('duration', webpage)), | |
185744f9 RA |
127 | 'formats': formats, |
128 | } |