[dcn] add support for live streams and catchup videos
[youtube-dl] / youtube_dl / extractor / dcn.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 import re
5 import base64
6
7 from .common import InfoExtractor
8 from ..compat import (
9     compat_urllib_parse,
10     compat_urllib_request,
11 )
12 from ..utils import (
13     int_or_none,
14     parse_iso8601,
15     smuggle_url,
16     unsmuggle_url,
17 )
18
19
20 class DCNGeneralIE(InfoExtractor):
21     _VALID_URL = r'https?://(?:www\.)?dcndigital\.ae/(?:#/)?show/(?P<show_id>\d+)/[^/]+(?:/(?P<video_id>\d+)/(?P<season_id>\d+))?'
22
23     def _real_extract(self, url):
24         show_id, video_id, season_id = re.match(self._VALID_URL, url).groups()
25         url = ''
26         ie_key = ''
27         if video_id and int(video_id) > 0:
28             url = 'http://www.dcndigital.ae/#/media/%s' % video_id
29             ie_key = 'DCNVideo'
30         else:
31             ie_key = 'DCNSeason'
32             if season_id and int(season_id) > 0:
33                 url = smuggle_url('http://www.dcndigital.ae/#/program/season/%s' % season_id, {'show_id': show_id})
34             else:
35                 url = 'http://www.dcndigital.ae/#/program/%s' % show_id
36         return {
37             'url': url,
38             '_type': 'url',
39             'ie_key': ie_key
40         }
41
42
43 class DCNVideoIE(InfoExtractor):
44     IE_NAME = 'dcn:video'
45     _VALID_URL = r'https?://(?:www\.)?dcndigital\.ae/(?:#/)?(?:video/[^/]+|media|catchup/[^/]+/[^/]+)/(?P<id>\d+)'
46     _TEST = {
47         'url': 'http://www.dcndigital.ae/#/video/%D8%B1%D8%AD%D9%84%D8%A9-%D8%A7%D9%84%D8%B9%D9%85%D8%B1-%D8%A7%D9%84%D8%AD%D9%84%D9%82%D8%A9-1/17375',
48         'info_dict':
49         {
50             'id': '17375',
51             'ext': 'mp4',
52             'title': 'رحلة العمر : الحلقة 1',
53             'description': 'md5:0156e935d870acb8ef0a66d24070c6d6',
54             'thumbnail': 're:^https?://.*\.jpg$',
55             'duration': 2041,
56             'timestamp': 1227504126,
57             'upload_date': '20081124',
58         },
59         'params': {
60             # m3u8 download
61             'skip_download': True,
62         },
63     }
64
65     def _real_extract(self, url):
66         video_id = self._match_id(url)
67
68         request = compat_urllib_request.Request(
69             'http://admin.mangomolo.com/analytics/index.php/plus/video?id=%s' % video_id,
70             headers={'Origin': 'http://www.dcndigital.ae'})
71
72         video = self._download_json(request, video_id)
73         title = video.get('title_en') or video['title_ar']
74
75         webpage = self._download_webpage(
76             'http://admin.mangomolo.com/analytics/index.php/customers/embed/video?'
77             + compat_urllib_parse.urlencode({
78                 'id': video['id'],
79                 'user_id': video['user_id'],
80                 'signature': video['signature'],
81                 'countries': 'Q0M=',
82                 'filter': 'DENY',
83             }), video_id)
84
85         m3u8_url = self._html_search_regex(r'file:\s*"([^"]+)', webpage, 'm3u8 url')
86         formats = self._extract_m3u8_formats(
87             m3u8_url, video_id, 'mp4', entry_protocol='m3u8_native', m3u8_id='hls')
88
89         rtsp_url = self._search_regex(
90             r'<a[^>]+href="(rtsp://[^"]+)"', webpage, 'rtsp url', fatal=False)
91         if rtsp_url:
92             formats.append({
93                 'url': rtsp_url,
94                 'format_id': 'rtsp',
95             })
96
97         self._sort_formats(formats)
98
99         img = video.get('img')
100         thumbnail = 'http://admin.mangomolo.com/analytics/%s' % img if img else None
101         duration = int_or_none(video.get('duration'))
102         description = video.get('description_en') or video.get('description_ar')
103         timestamp = parse_iso8601(video.get('create_time') or video.get('update_time'), ' ')
104
105         return {
106             'id': video_id,
107             'title': title,
108             'description': description,
109             'thumbnail': thumbnail,
110             'duration': duration,
111             'timestamp': timestamp,
112             'formats': formats,
113         }
114
115
116 class DCNLiveIE(InfoExtractor):
117     IE_NAME = 'dcn:live'
118     _VALID_URL = r'https?://(?:www\.)?dcndigital\.ae/(?:#/)?live/(?P<id>\d+)'
119     _TEST = {
120         'url': 'http://www.dcndigital.ae/#/live/6/dubai-tv',
121         'info_dict':
122         {
123             'id': '6',
124             'ext': 'mp4',
125             'title': 'Dubai Al Oula',
126         },
127         'params': {
128             # m3u8 download
129             'skip_download': True,
130         },
131     }
132
133     def _real_extract(self, url):
134         channel_id = self._match_id(url)
135
136         request = compat_urllib_request.Request(
137             'http://admin.mangomolo.com/analytics/index.php/plus/getchanneldetails?channel_id=%s' % channel_id,
138             headers={'Origin': 'http://www.dcndigital.ae'})
139
140         channel = self._download_json(request, channel_id)
141         title = channel.get('title_en') or channel['title_ar']
142
143         webpage = self._download_webpage(
144             'http://admin.mangomolo.com/analytics/index.php/customers/embed/index?'
145             + compat_urllib_parse.urlencode({
146                 'id': base64.b64encode(channel['user_id'].encode()).decode(),
147                 'channelid': base64.b64encode(channel['id'].encode()).decode(),
148                 'signature': channel['signature'],
149                 'countries': 'Q0M=',
150                 'filter': 'DENY',
151             }), channel_id)
152
153         m3u8_url = self._html_search_regex(r'file:\s*"([^"]+)', webpage, 'm3u8 url')
154         formats = self._extract_m3u8_formats(
155             m3u8_url, channel_id, 'mp4', entry_protocol='m3u8_native', m3u8_id='hls')
156
157         rtsp_url = self._search_regex(
158             r'<a[^>]+href="(rtsp://[^"]+)"', webpage, 'rtsp url', fatal=False)
159         if rtsp_url:
160             formats.append({
161                 'url': rtsp_url,
162                 'format_id': 'rtsp',
163             })
164
165         self._sort_formats(formats)
166
167         return {
168             'id': channel_id,
169             'title': title,
170             'formats': formats,
171             'is_live': True,
172         }
173
174
175 class DCNSeasonIE(InfoExtractor):
176     IE_NAME = 'dcn:season'
177     _VALID_URL = r'https?://(?:www\.)?dcndigital\.ae/(?:#/)?program/(?:(?P<show_id>\d+)|season/(?P<season_id>\d+))'
178     _TEST = {
179         'url': 'http://dcndigital.ae/#/program/205024/%D9%85%D8%AD%D8%A7%D8%B6%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%B4%D9%8A%D8%AE-%D8%A7%D9%84%D8%B4%D8%B9%D8%B1%D8%A7%D9%88%D9%8A',
180         'info_dict':
181         {
182             'id': '7910',
183             'title': 'محاضرات الشيخ الشعراوي',
184             'description': '',
185         },
186         'playlist_mincount': 27,
187     }
188
189     def _real_extract(self, url):
190         url, smuggled_data = unsmuggle_url(url, {})
191         show_id, season_id = re.match(self._VALID_URL, url).groups()
192         data = {}
193         if season_id:
194             data['season'] = season_id
195             show_id = smuggled_data.get('show_id')
196             if show_id is None:
197                 request = compat_urllib_request.Request(
198                     'http://admin.mangomolo.com/analytics/index.php/plus/season_info?id=%s' % season_id,
199                     headers={'Origin': 'http://www.dcndigital.ae'})
200                 season = self._download_json(request, season_id)
201                 show_id = season['id']
202         data['show_id'] = show_id
203         request = compat_urllib_request.Request(
204             'http://admin.mangomolo.com/analytics/index.php/plus/show',
205             compat_urllib_parse.urlencode(data),
206             {
207                 'Origin': 'http://www.dcndigital.ae',
208                 'Content-Type': 'application/x-www-form-urlencoded'
209             })
210         show = self._download_json(request, show_id)
211         season_id = season_id or show['default_season']
212         title = show['cat'].get('title_en') or show['cat']['title_ar']
213         description = show['cat'].get('description_en') or show['cat'].get('description_ar')
214         entries = []
215         for video in show['videos']:
216             entries.append({
217                 'url': 'http://www.dcndigital.ae/#/media/%s' % video['id'],
218                 '_type': 'url',
219                 'ie_key': 'DCNVideo',
220             })
221         return {
222             'id': season_id,
223             'title': title,
224             'description': description,
225             'entries': entries,
226             '_type': 'playlist',
227         }