]>
Commit | Line | Data |
---|---|---|
1 | # coding: utf-8 | |
2 | from __future__ import unicode_literals | |
3 | ||
4 | import re | |
5 | ||
6 | from .common import InfoExtractor | |
7 | from ..utils import ( | |
8 | ExtractorError, | |
9 | float_or_none, | |
10 | int_or_none, | |
11 | parse_iso8601, | |
12 | parse_qs, | |
13 | try_get, | |
14 | ) | |
15 | ||
16 | ||
17 | class ArkenaIE(InfoExtractor): | |
18 | _VALID_URL = r'''(?x) | |
19 | https?:// | |
20 | (?: | |
21 | video\.(?:arkena|qbrick)\.com/play2/embed/player\?| | |
22 | play\.arkena\.com/(?:config|embed)/avp/v\d/player/media/(?P<id>[^/]+)/[^/]+/(?P<account_id>\d+) | |
23 | ) | |
24 | ''' | |
25 | _TESTS = [{ | |
26 | 'url': 'https://video.qbrick.com/play2/embed/player?accountId=1034090&mediaId=d8ab4607-00090107-aab86310', | |
27 | 'md5': '97f117754e5f3c020f5f26da4a44ebaf', | |
28 | 'info_dict': { | |
29 | 'id': 'd8ab4607-00090107-aab86310', | |
30 | 'ext': 'mp4', | |
31 | 'title': 'EM_HT20_117_roslund_v2.mp4', | |
32 | 'timestamp': 1608285912, | |
33 | 'upload_date': '20201218', | |
34 | 'duration': 1429.162667, | |
35 | 'subtitles': { | |
36 | 'sv': 'count:3', | |
37 | }, | |
38 | }, | |
39 | }, { | |
40 | 'url': 'https://play.arkena.com/embed/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411', | |
41 | 'only_matching': True, | |
42 | }, { | |
43 | 'url': 'https://play.arkena.com/config/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411/?callbackMethod=jQuery1111023664739129262213_1469227693893', | |
44 | 'only_matching': True, | |
45 | }, { | |
46 | 'url': 'http://play.arkena.com/config/avp/v1/player/media/327336/darkmatter/131064/?callbackMethod=jQuery1111002221189684892677_1469227595972', | |
47 | 'only_matching': True, | |
48 | }, { | |
49 | 'url': 'http://play.arkena.com/embed/avp/v1/player/media/327336/darkmatter/131064/', | |
50 | 'only_matching': True, | |
51 | }, { | |
52 | 'url': 'http://video.arkena.com/play2/embed/player?accountId=472718&mediaId=35763b3b-00090078-bf604299&pageStyling=styled', | |
53 | 'only_matching': True, | |
54 | }] | |
55 | ||
56 | @staticmethod | |
57 | def _extract_url(webpage): | |
58 | # See https://support.arkena.com/display/PLAY/Ways+to+embed+your+video | |
59 | mobj = re.search( | |
60 | r'<iframe[^>]+src=(["\'])(?P<url>(?:https?:)?//play\.arkena\.com/embed/avp/.+?)\1', | |
61 | webpage) | |
62 | if mobj: | |
63 | return mobj.group('url') | |
64 | ||
65 | def _real_extract(self, url): | |
66 | mobj = self._match_valid_url(url) | |
67 | video_id = mobj.group('id') | |
68 | account_id = mobj.group('account_id') | |
69 | ||
70 | # Handle http://video.arkena.com/play2/embed/player URL | |
71 | if not video_id: | |
72 | qs = parse_qs(url) | |
73 | video_id = qs.get('mediaId', [None])[0] | |
74 | account_id = qs.get('accountId', [None])[0] | |
75 | if not video_id or not account_id: | |
76 | raise ExtractorError('Invalid URL', expected=True) | |
77 | ||
78 | media = self._download_json( | |
79 | 'https://video.qbrick.com/api/v1/public/accounts/%s/medias/%s' % (account_id, video_id), | |
80 | video_id, query={ | |
81 | # https://video.qbrick.com/docs/api/examples/library-api.html | |
82 | 'fields': 'asset/resources/*/renditions/*(height,id,language,links/*(href,mimeType),type,size,videos/*(audios/*(codec,sampleRate),bitrate,codec,duration,height,width),width),created,metadata/*(title,description),tags', | |
83 | }) | |
84 | metadata = media.get('metadata') or {} | |
85 | title = metadata['title'] | |
86 | ||
87 | duration = None | |
88 | formats = [] | |
89 | thumbnails = [] | |
90 | subtitles = {} | |
91 | for resource in media['asset']['resources']: | |
92 | for rendition in (resource.get('renditions') or []): | |
93 | rendition_type = rendition.get('type') | |
94 | for i, link in enumerate(rendition.get('links') or []): | |
95 | href = link.get('href') | |
96 | if not href: | |
97 | continue | |
98 | if rendition_type == 'image': | |
99 | thumbnails.append({ | |
100 | 'filesize': int_or_none(rendition.get('size')), | |
101 | 'height': int_or_none(rendition.get('height')), | |
102 | 'id': rendition.get('id'), | |
103 | 'url': href, | |
104 | 'width': int_or_none(rendition.get('width')), | |
105 | }) | |
106 | elif rendition_type == 'subtitle': | |
107 | subtitles.setdefault(rendition.get('language') or 'en', []).append({ | |
108 | 'url': href, | |
109 | }) | |
110 | elif rendition_type == 'video': | |
111 | f = { | |
112 | 'filesize': int_or_none(rendition.get('size')), | |
113 | 'format_id': rendition.get('id'), | |
114 | 'url': href, | |
115 | } | |
116 | video = try_get(rendition, lambda x: x['videos'][i], dict) | |
117 | if video: | |
118 | if not duration: | |
119 | duration = float_or_none(video.get('duration')) | |
120 | f.update({ | |
121 | 'height': int_or_none(video.get('height')), | |
122 | 'tbr': int_or_none(video.get('bitrate'), 1000), | |
123 | 'vcodec': video.get('codec'), | |
124 | 'width': int_or_none(video.get('width')), | |
125 | }) | |
126 | audio = try_get(video, lambda x: x['audios'][0], dict) | |
127 | if audio: | |
128 | f.update({ | |
129 | 'acodec': audio.get('codec'), | |
130 | 'asr': int_or_none(audio.get('sampleRate')), | |
131 | }) | |
132 | formats.append(f) | |
133 | elif rendition_type == 'index': | |
134 | mime_type = link.get('mimeType') | |
135 | if mime_type == 'application/smil+xml': | |
136 | formats.extend(self._extract_smil_formats( | |
137 | href, video_id, fatal=False)) | |
138 | elif mime_type == 'application/x-mpegURL': | |
139 | formats.extend(self._extract_m3u8_formats( | |
140 | href, video_id, 'mp4', 'm3u8_native', | |
141 | m3u8_id='hls', fatal=False)) | |
142 | elif mime_type == 'application/hds+xml': | |
143 | formats.extend(self._extract_f4m_formats( | |
144 | href, video_id, f4m_id='hds', fatal=False)) | |
145 | elif mime_type == 'application/dash+xml': | |
146 | formats.extend(self._extract_f4m_formats( | |
147 | href, video_id, f4m_id='hds', fatal=False)) | |
148 | elif mime_type == 'application/vnd.ms-sstr+xml': | |
149 | formats.extend(self._extract_ism_formats( | |
150 | href, video_id, ism_id='mss', fatal=False)) | |
151 | self._sort_formats(formats) | |
152 | ||
153 | return { | |
154 | 'id': video_id, | |
155 | 'title': title, | |
156 | 'description': metadata.get('description'), | |
157 | 'timestamp': parse_iso8601(media.get('created')), | |
158 | 'thumbnails': thumbnails, | |
159 | 'subtitles': subtitles, | |
160 | 'duration': duration, | |
161 | 'tags': media.get('tags'), | |
162 | 'formats': formats, | |
163 | } |