1# coding: utf-8
2from __future__ import unicode_literals
3
4import re
5
6from .common import InfoExtractor
7from ..compat import compat_urlparse
8from ..utils import (
9    ExtractorError,
10    float_or_none,
11    int_or_none,
12    parse_iso8601,
13    try_get,
14)
15
16
17class 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 = re.match(self._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 = compat_urlparse.parse_qs(compat_urlparse.urlparse(url).query)
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        }
164