]>
Commit | Line | Data |
---|---|---|
bbe1f363 S |
1 | # coding: utf-8 |
2 | from __future__ import unicode_literals | |
3 | ||
4 | import re | |
5 | ||
6 | from .common import InfoExtractor | |
7 | from ..utils import ( | |
1f766b6e | 8 | ExtractorError, |
bbe1f363 S |
9 | float_or_none, |
10 | int_or_none, | |
bbe1f363 | 11 | parse_iso8601, |
4dfbf869 | 12 | parse_qs, |
29f7c58a | 13 | try_get, |
bbe1f363 S |
14 | ) |
15 | ||
16 | ||
17 | class ArkenaIE(InfoExtractor): | |
1f766b6e S |
18 | _VALID_URL = r'''(?x) |
19 | https?:// | |
20 | (?: | |
29f7c58a | 21 | video\.(?:arkena|qbrick)\.com/play2/embed/player\?| |
1f766b6e S |
22 | play\.arkena\.com/(?:config|embed)/avp/v\d/player/media/(?P<id>[^/]+)/[^/]+/(?P<account_id>\d+) |
23 | ) | |
24 | ''' | |
bbe1f363 | 25 | _TESTS = [{ |
29f7c58a | 26 | 'url': 'https://video.qbrick.com/play2/embed/player?accountId=1034090&mediaId=d8ab4607-00090107-aab86310', |
27 | 'md5': '97f117754e5f3c020f5f26da4a44ebaf', | |
bbe1f363 | 28 | 'info_dict': { |
29f7c58a | 29 | 'id': 'd8ab4607-00090107-aab86310', |
bbe1f363 | 30 | 'ext': 'mp4', |
29f7c58a | 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 | }, | |
bbe1f363 | 38 | }, |
29f7c58a | 39 | }, { |
40 | 'url': 'https://play.arkena.com/embed/avp/v2/player/media/b41dda37-d8e7-4d3f-b1b5-9a9db578bdfe/1/129411', | |
41 | 'only_matching': True, | |
bbe1f363 S |
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, | |
1f766b6e S |
51 | }, { |
52 | 'url': 'http://video.arkena.com/play2/embed/player?accountId=472718&mediaId=35763b3b-00090078-bf604299&pageStyling=styled', | |
53 | 'only_matching': True, | |
bbe1f363 S |
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): | |
5ad28e7f | 66 | mobj = self._match_valid_url(url) |
bbe1f363 S |
67 | video_id = mobj.group('id') |
68 | account_id = mobj.group('account_id') | |
69 | ||
1f766b6e S |
70 | # Handle http://video.arkena.com/play2/embed/player URL |
71 | if not video_id: | |
4dfbf869 | 72 | qs = parse_qs(url) |
1f766b6e S |
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 | ||
29f7c58a | 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'] | |
bbe1f363 | 86 | |
29f7c58a | 87 | duration = None |
bbe1f363 | 88 | formats = [] |
29f7c58a | 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)) | |
bbe1f363 S |
151 | self._sort_formats(formats) |
152 | ||
bbe1f363 S |
153 | return { |
154 | 'id': video_id, | |
155 | 'title': title, | |
29f7c58a | 156 | 'description': metadata.get('description'), |
157 | 'timestamp': parse_iso8601(media.get('created')), | |
bbe1f363 | 158 | 'thumbnails': thumbnails, |
29f7c58a | 159 | 'subtitles': subtitles, |
160 | 'duration': duration, | |
161 | 'tags': media.get('tags'), | |
bbe1f363 S |
162 | 'formats': formats, |
163 | } |