Merge pull request #8513 from remitamine/dash-sort
[youtube-dl] / youtube_dl / extractor / lifenews.py
1 # encoding: utf-8
2 from __future__ import unicode_literals
3
4 import re
5
6 from .common import InfoExtractor
7 from ..compat import compat_urlparse
8 from ..utils import (
9     determine_ext,
10     int_or_none,
11     remove_end,
12     unified_strdate,
13     ExtractorError,
14 )
15
16
17 class LifeNewsIE(InfoExtractor):
18     IE_NAME = 'lifenews'
19     IE_DESC = 'LIFE | NEWS'
20     _VALID_URL = r'http://lifenews\.ru/(?:mobile/)?(?P<section>news|video)/(?P<id>\d+)'
21
22     _TESTS = [{
23         # single video embedded via video/source
24         'url': 'http://lifenews.ru/news/98736',
25         'md5': '77c95eaefaca216e32a76a343ad89d23',
26         'info_dict': {
27             'id': '98736',
28             'ext': 'mp4',
29             'title': 'Мужчина нашел дома архив оборонного завода',
30             'description': 'md5:3b06b1b39b5e2bea548e403d99b8bf26',
31             'upload_date': '20120805',
32         }
33     }, {
34         # single video embedded via iframe
35         'url': 'http://lifenews.ru/news/152125',
36         'md5': '77d19a6f0886cd76bdbf44b4d971a273',
37         'info_dict': {
38             'id': '152125',
39             'ext': 'mp4',
40             'title': 'В Сети появилось видео захвата «Правым сектором» колхозных полей ',
41             'description': 'Жители двух поселков Днепропетровской области не простили радикалам угрозу лишения плодородных земель и пошли в лобовую. ',
42             'upload_date': '20150402',
43         }
44     }, {
45         # two videos embedded via iframe
46         'url': 'http://lifenews.ru/news/153461',
47         'info_dict': {
48             'id': '153461',
49             'title': 'В Москве спасли потерявшегося медвежонка, который спрятался на дереве',
50             'description': 'Маленький хищник не смог найти дорогу домой и обрел временное убежище на тополе недалеко от жилого массива, пока его не нашла соседская собака.',
51             'upload_date': '20150505',
52         },
53         'playlist': [{
54             'md5': '9b6ef8bc0ffa25aebc8bdb40d89ab795',
55             'info_dict': {
56                 'id': '153461-video1',
57                 'ext': 'mp4',
58                 'title': 'В Москве спасли потерявшегося медвежонка, который спрятался на дереве (Видео 1)',
59                 'description': 'Маленький хищник не смог найти дорогу домой и обрел временное убежище на тополе недалеко от жилого массива, пока его не нашла соседская собака.',
60                 'upload_date': '20150505',
61             },
62         }, {
63             'md5': 'ebb3bf3b1ce40e878d0d628e93eb0322',
64             'info_dict': {
65                 'id': '153461-video2',
66                 'ext': 'mp4',
67                 'title': 'В Москве спасли потерявшегося медвежонка, который спрятался на дереве (Видео 2)',
68                 'description': 'Маленький хищник не смог найти дорогу домой и обрел временное убежище на тополе недалеко от жилого массива, пока его не нашла соседская собака.',
69                 'upload_date': '20150505',
70             },
71         }],
72     }, {
73         'url': 'http://lifenews.ru/video/13035',
74         'only_matching': True,
75     }]
76
77     def _real_extract(self, url):
78         mobj = re.match(self._VALID_URL, url)
79         video_id = mobj.group('id')
80         section = mobj.group('section')
81
82         webpage = self._download_webpage(
83             'http://lifenews.ru/%s/%s' % (section, video_id),
84             video_id, 'Downloading page')
85
86         video_urls = re.findall(
87             r'<video[^>]+><source[^>]+src=["\'](.+?)["\']', webpage)
88
89         iframe_links = re.findall(
90             r'<iframe[^>]+src=["\']((?:https?:)?//embed\.life\.ru/embed/.+?)["\']',
91             webpage)
92
93         if not video_urls and not iframe_links:
94             raise ExtractorError('No media links available for %s' % video_id)
95
96         title = remove_end(
97             self._og_search_title(webpage),
98             ' - Первый по срочным новостям — LIFE | NEWS')
99
100         description = self._og_search_description(webpage)
101
102         view_count = self._html_search_regex(
103             r'<div class=\'views\'>\s*(\d+)\s*</div>', webpage, 'view count', fatal=False)
104         comment_count = self._html_search_regex(
105             r'=\'commentCount\'[^>]*>\s*(\d+)\s*<',
106             webpage, 'comment count', fatal=False)
107
108         upload_date = self._html_search_regex(
109             r'<time[^>]*datetime=\'([^\']+)\'', webpage, 'upload date', fatal=False)
110         if upload_date is not None:
111             upload_date = unified_strdate(upload_date)
112
113         common_info = {
114             'description': description,
115             'view_count': int_or_none(view_count),
116             'comment_count': int_or_none(comment_count),
117             'upload_date': upload_date,
118         }
119
120         def make_entry(video_id, video_url, index=None):
121             cur_info = dict(common_info)
122             cur_info.update({
123                 'id': video_id if not index else '%s-video%s' % (video_id, index),
124                 'url': video_url,
125                 'title': title if not index else '%s (Видео %s)' % (title, index),
126             })
127             return cur_info
128
129         def make_video_entry(video_id, video_url, index=None):
130             video_url = compat_urlparse.urljoin(url, video_url)
131             return make_entry(video_id, video_url, index)
132
133         def make_iframe_entry(video_id, video_url, index=None):
134             video_url = self._proto_relative_url(video_url, 'http:')
135             cur_info = make_entry(video_id, video_url, index)
136             cur_info['_type'] = 'url_transparent'
137             return cur_info
138
139         if len(video_urls) == 1 and not iframe_links:
140             return make_video_entry(video_id, video_urls[0])
141
142         if len(iframe_links) == 1 and not video_urls:
143             return make_iframe_entry(video_id, iframe_links[0])
144
145         entries = []
146
147         if video_urls:
148             for num, video_url in enumerate(video_urls, 1):
149                 entries.append(make_video_entry(video_id, video_url, num))
150
151         if iframe_links:
152             for num, iframe_link in enumerate(iframe_links, len(video_urls) + 1):
153                 entries.append(make_iframe_entry(video_id, iframe_link, num))
154
155         playlist = common_info.copy()
156         playlist.update(self.playlist_result(entries, video_id, title, description))
157         return playlist
158
159
160 class LifeEmbedIE(InfoExtractor):
161     IE_NAME = 'life:embed'
162     _VALID_URL = r'http://embed\.life\.ru/embed/(?P<id>[\da-f]{32})'
163
164     _TEST = {
165         'url': 'http://embed.life.ru/embed/e50c2dec2867350528e2574c899b8291',
166         'md5': 'b889715c9e49cb1981281d0e5458fbbe',
167         'info_dict': {
168             'id': 'e50c2dec2867350528e2574c899b8291',
169             'ext': 'mp4',
170             'title': 'e50c2dec2867350528e2574c899b8291',
171             'thumbnail': 're:http://.*\.jpg',
172         }
173     }
174
175     def _real_extract(self, url):
176         video_id = self._match_id(url)
177
178         webpage = self._download_webpage(url, video_id)
179
180         formats = []
181         for video_url in re.findall(r'"file"\s*:\s*"([^"]+)', webpage):
182             video_url = compat_urlparse.urljoin(url, video_url)
183             ext = determine_ext(video_url)
184             if ext == 'm3u8':
185                 formats.extend(self._extract_m3u8_formats(
186                     video_url, video_id, 'mp4', m3u8_id='m3u8'))
187             else:
188                 formats.append({
189                     'url': video_url,
190                     'format_id': ext,
191                     'preference': 1,
192                 })
193         self._sort_formats(formats)
194
195         thumbnail = self._search_regex(
196             r'"image"\s*:\s*"([^"]+)', webpage, 'thumbnail', default=None)
197
198         return {
199             'id': video_id,
200             'title': video_id,
201             'thumbnail': thumbnail,
202             'formats': formats,
203         }