source: titan/mediathek/localhoster/lib/youtube_dl/extractor/afreecatv.py @ 40094

Last change on this file since 40094 was 40094, checked in by obi, 7 years ago

tithek add yoztube-dl support

File size: 9.0 KB
Line 
1# coding: utf-8
2from __future__ import unicode_literals
3
4import re
5
6from .common import InfoExtractor
7from ..compat import (
8    compat_urllib_parse_urlparse,
9    compat_urlparse,
10)
11from ..utils import (
12    ExtractorError,
13    int_or_none,
14    update_url_query,
15    xpath_element,
16    xpath_text,
17)
18
19
20class AfreecaTVIE(InfoExtractor):
21    IE_NAME = 'afreecatv'
22    IE_DESC = 'afreecatv.com'
23    _VALID_URL = r'''(?x)
24                    https?://
25                        (?:
26                            (?:(?:live|afbbs|www)\.)?afreeca(?:tv)?\.com(?::\d+)?
27                            (?:
28                                /app/(?:index|read_ucc_bbs)\.cgi|
29                                /player/[Pp]layer\.(?:swf|html)
30                            )\?.*?\bnTitleNo=|
31                            vod\.afreecatv\.com/PLAYER/STATION/
32                        )
33                        (?P<id>\d+)
34                    '''
35    _TESTS = [{
36        'url': 'http://live.afreecatv.com:8079/app/index.cgi?szType=read_ucc_bbs&szBjId=dailyapril&nStationNo=16711924&nBbsNo=18605867&nTitleNo=36164052&szSkin=',
37        'md5': 'f72c89fe7ecc14c1b5ce506c4996046e',
38        'info_dict': {
39            'id': '36164052',
40            'ext': 'mp4',
41            'title': '데일리 에이프릴 요정들의 시상식!',
42            'thumbnail': 're:^https?://(?:video|st)img.afreecatv.com/.*$',
43            'uploader': 'dailyapril',
44            'uploader_id': 'dailyapril',
45            'upload_date': '20160503',
46        }
47    }, {
48        'url': 'http://afbbs.afreecatv.com:8080/app/read_ucc_bbs.cgi?nStationNo=16711924&nTitleNo=36153164&szBjId=dailyapril&nBbsNo=18605867',
49        'info_dict': {
50            'id': '36153164',
51            'title': "BJ유트루와 함께하는 '팅커벨 메이크업!'",
52            'thumbnail': 're:^https?://(?:video|st)img.afreecatv.com/.*$',
53            'uploader': 'dailyapril',
54            'uploader_id': 'dailyapril',
55        },
56        'playlist_count': 2,
57        'playlist': [{
58            'md5': 'd8b7c174568da61d774ef0203159bf97',
59            'info_dict': {
60                'id': '36153164_1',
61                'ext': 'mp4',
62                'title': "BJ유트루와 함께하는 '팅커벨 메이크업!'",
63                'upload_date': '20160502',
64            },
65        }, {
66            'md5': '58f2ce7f6044e34439ab2d50612ab02b',
67            'info_dict': {
68                'id': '36153164_2',
69                'ext': 'mp4',
70                'title': "BJ유트루와 함께하는 '팅커벨 메이크업!'",
71                'upload_date': '20160502',
72            },
73        }],
74    }, {
75        'url': 'http://www.afreecatv.com/player/Player.swf?szType=szBjId=djleegoon&nStationNo=11273158&nBbsNo=13161095&nTitleNo=36327652',
76        'only_matching': True,
77    }, {
78        'url': 'http://vod.afreecatv.com/PLAYER/STATION/15055030',
79        'only_matching': True,
80    }]
81
82    @staticmethod
83    def parse_video_key(key):
84        video_key = {}
85        m = re.match(r'^(?P<upload_date>\d{8})_\w+_(?P<part>\d+)$', key)
86        if m:
87            video_key['upload_date'] = m.group('upload_date')
88            video_key['part'] = m.group('part')
89        return video_key
90
91    def _real_extract(self, url):
92        video_id = self._match_id(url)
93        parsed_url = compat_urllib_parse_urlparse(url)
94        info_url = compat_urlparse.urlunparse(parsed_url._replace(
95            netloc='afbbs.afreecatv.com:8080',
96            path='/api/video/get_video_info.php'))
97
98        video_xml = self._download_xml(
99            update_url_query(info_url, {'nTitleNo': video_id}), video_id)
100
101        if xpath_element(video_xml, './track/video/file') is None:
102            raise ExtractorError('Specified AfreecaTV video does not exist',
103                                 expected=True)
104
105        title = xpath_text(video_xml, './track/title', 'title')
106        uploader = xpath_text(video_xml, './track/nickname', 'uploader')
107        uploader_id = xpath_text(video_xml, './track/bj_id', 'uploader id')
108        duration = int_or_none(xpath_text(video_xml, './track/duration',
109                                          'duration'))
110        thumbnail = xpath_text(video_xml, './track/titleImage', 'thumbnail')
111
112        entries = []
113        for i, video_file in enumerate(video_xml.findall('./track/video/file')):
114            video_key = self.parse_video_key(video_file.get('key', ''))
115            if not video_key:
116                continue
117            entries.append({
118                'id': '%s_%s' % (video_id, video_key.get('part', i + 1)),
119                'title': title,
120                'upload_date': video_key.get('upload_date'),
121                'duration': int_or_none(video_file.get('duration')),
122                'url': video_file.text,
123            })
124
125        info = {
126            'id': video_id,
127            'title': title,
128            'uploader': uploader,
129            'uploader_id': uploader_id,
130            'duration': duration,
131            'thumbnail': thumbnail,
132        }
133
134        if len(entries) > 1:
135            info['_type'] = 'multi_video'
136            info['entries'] = entries
137        elif len(entries) == 1:
138            info['url'] = entries[0]['url']
139            info['upload_date'] = entries[0].get('upload_date')
140        else:
141            raise ExtractorError(
142                'No files found for the specified AfreecaTV video, either'
143                ' the URL is incorrect or the video has been made private.',
144                expected=True)
145
146        return info
147
148
149class AfreecaTVGlobalIE(AfreecaTVIE):
150    IE_NAME = 'afreecatv:global'
151    _VALID_URL = r'https?://(?:www\.)?afreeca\.tv/(?P<channel_id>\d+)(?:/v/(?P<video_id>\d+))?'
152    _TESTS = [{
153        'url': 'http://afreeca.tv/36853014/v/58301',
154        'info_dict': {
155            'id': '58301',
156            'title': 'tryhard top100',
157            'uploader_id': '36853014',
158            'uploader': 'makgi Hearthstone Live!',
159        },
160        'playlist_count': 3,
161    }]
162
163    def _real_extract(self, url):
164        channel_id, video_id = re.match(self._VALID_URL, url).groups()
165        video_type = 'video' if video_id else 'live'
166        query = {
167            'pt': 'view',
168            'bid': channel_id,
169        }
170        if video_id:
171            query['vno'] = video_id
172        video_data = self._download_json(
173            'http://api.afreeca.tv/%s/view_%s.php' % (video_type, video_type),
174            video_id or channel_id, query=query)['channel']
175
176        if video_data.get('result') != 1:
177            raise ExtractorError('%s said: %s' % (self.IE_NAME, video_data['remsg']))
178
179        title = video_data['title']
180
181        info = {
182            'thumbnail': video_data.get('thumb'),
183            'view_count': int_or_none(video_data.get('vcnt')),
184            'age_limit': int_or_none(video_data.get('grade')),
185            'uploader_id': channel_id,
186            'uploader': video_data.get('cname'),
187        }
188
189        if video_id:
190            entries = []
191            for i, f in enumerate(video_data.get('flist', [])):
192                video_key = self.parse_video_key(f.get('key', ''))
193                f_url = f.get('file')
194                if not video_key or not f_url:
195                    continue
196                entries.append({
197                    'id': '%s_%s' % (video_id, video_key.get('part', i + 1)),
198                    'title': title,
199                    'upload_date': video_key.get('upload_date'),
200                    'duration': int_or_none(f.get('length')),
201                    'url': f_url,
202                    'protocol': 'm3u8_native',
203                    'ext': 'mp4',
204                })
205
206            info.update({
207                'id': video_id,
208                'title': title,
209                'duration': int_or_none(video_data.get('length')),
210            })
211            if len(entries) > 1:
212                info['_type'] = 'multi_video'
213                info['entries'] = entries
214            elif len(entries) == 1:
215                i = entries[0].copy()
216                i.update(info)
217                info = i
218        else:
219            formats = []
220            for s in video_data.get('strm', []):
221                s_url = s.get('purl')
222                if not s_url:
223                    continue
224                stype = s.get('stype')
225                if stype == 'HLS':
226                    formats.extend(self._extract_m3u8_formats(
227                        s_url, channel_id, 'mp4', m3u8_id=stype, fatal=False))
228                elif stype == 'RTMP':
229                    format_id = [stype]
230                    label = s.get('label')
231                    if label:
232                        format_id.append(label)
233                    formats.append({
234                        'format_id': '-'.join(format_id),
235                        'url': s_url,
236                        'tbr': int_or_none(s.get('bps')),
237                        'height': int_or_none(s.get('brt')),
238                        'ext': 'flv',
239                        'rtmp_live': True,
240                    })
241            self._sort_formats(formats)
242
243            info.update({
244                'id': channel_id,
245                'title': self._live_title(title),
246                'is_live': True,
247                'formats': formats,
248            })
249
250        return info
Note: See TracBrowser for help on using the repository browser.