[videomore] Add extractor (Closes #8040)
[youtube-dl] / youtube_dl / extractor / videomore.py
1 # coding: utf-8
2 from __future__ import unicode_literals
3
4 import re
5
6 from .common import InfoExtractor
7 from ..utils import (
8     int_or_none,
9     parse_age_limit,
10     parse_iso8601,
11     xpath_text,
12 )
13
14
15 class VideomoreIE(InfoExtractor):
16     _VALID_URL = r'videomore:(?P<sid>\d+)$|https?://videomore\.ru/(?:(?:embed|[^/]+/[^/]+)/|[^/]+\?.*\btrack_id=)(?P<id>\d+)(?:[/?#&]|\.(?:xml|json)|$)'
17     _TESTS = [{
18         'url': 'http://videomore.ru/kino_v_detalayah/5_sezon/367617',
19         'md5': '70875fbf57a1cd004709920381587185',
20         'info_dict': {
21             'id': '367617',
22             'ext': 'flv',
23             'title': 'В гостях Алексей Чумаков и Юлия Ковальчук',
24             'description': 'В гостях – лучшие романтические комедии года, «Выживший» Иньярриту и «Стив Джобс» Дэнни Бойла.',
25             'thumbnail': 're:^https?://.*\.jpg',
26             'duration': 2910,
27             'age_limit': 16,
28             'view_count': int,
29         },
30     }, {
31         'url': 'http://videomore.ru/elki_3?track_id=364623',
32         'only_matching': True,
33     }, {
34         'url': 'http://videomore.ru/embed/364623',
35         'only_matching': True,
36     }, {
37         'url': 'http://videomore.ru/video/tracks/364623.xml',
38         'only_matching': True,
39     }, {
40         'url': 'http://videomore.ru/video/tracks/364623.json',
41         'only_matching': True,
42     }, {
43         'url': 'http://videomore.ru/video/tracks/158031/quotes/33248',
44         'only_matching': True,
45     }, {
46         'url': 'videomore:367617',
47         'only_matching': True,
48     }]
49
50     @staticmethod
51     def _extract_url(webpage):
52         mobj = re.search(
53             r'<object[^>]+data=(["\'])https?://videomore.ru/player\.swf\?.*config=(?P<url>https?://videomore\.ru/(?:[^/]+/)+\d+\.xml).*\1',
54             webpage)
55         if mobj:
56             return mobj.group('url')
57
58     def _real_extract(self, url):
59         mobj = re.match(self._VALID_URL, url)
60         video_id = mobj.group('sid') or mobj.group('id')
61
62         video = self._download_xml(
63             'http://videomore.ru/video/tracks/%s.xml' % video_id,
64             video_id, 'Downloading video XML')
65
66         video_url = xpath_text(video, './/video_url', 'video url', fatal=True)
67         formats = self._extract_f4m_formats(video_url, video_id, f4m_id='hds')
68
69         data = self._download_json(
70             'http://videomore.ru/video/tracks/%s.json' % video_id,
71             video_id, 'Downloadinng video JSON')
72
73         title = data.get('title') or data['project_title']
74         description = data.get('description') or data.get('description_raw')
75         timestamp = parse_iso8601(data.get('published_at'))
76         duration = int_or_none(data.get('duration'))
77         view_count = int_or_none(data.get('views'))
78         age_limit = parse_age_limit(data.get('min_age'))
79         thumbnails = [{
80             'url': thumbnail,
81         } for thumbnail in data.get('big_thumbnail_urls', [])]
82
83         return {
84             'id': video_id,
85             'title': title,
86             'description': description,
87             'thumbnails': thumbnails,
88             'timestamp': timestamp,
89             'duration': duration,
90             'view_count': view_count,
91             'age_limit': age_limit,
92             'formats': formats,
93         }
94
95
96 class VideomoreVideoIE(InfoExtractor):
97     IE_NAME = 'videomore:video'
98     _VALID_URL = r'https?://videomore\.ru/(?:(?:[^/]+/){2})?(?P<id>[^/?#&]+)[/?#&]*$'
99     _TESTS = [{
100         # single video with og:video:iframe
101         'url': 'http://videomore.ru/elki_3',
102         'info_dict': {
103             'id': '364623',
104             'ext': 'flv',
105             'title': 'Ёлки 3',
106             'description': '',
107             'thumbnail': 're:^https?://.*\.jpg',
108             'duration': 5579,
109             'age_limit': 6,
110             'view_count': int,
111         },
112         'params': {
113             'skip_download': True,
114         },
115     }, {
116         # season single serie with og:video:iframe
117         'url': 'http://videomore.ru/poslednii_ment/1_sezon/14_seriya',
118         'only_matching': True,
119     }, {
120         'url': 'http://videomore.ru/sejchas_v_seti/serii_221-240/226_vypusk',
121         'only_matching': True,
122     }, {
123         # single video without og:video:iframe
124         'url': 'http://videomore.ru/marin_i_ego_druzya',
125         'info_dict': {
126             'id': '359073',
127             'ext': 'flv',
128             'title': '1 серия. Здравствуй, Аквавилль!',
129             'description': 'md5:c6003179538b5d353e7bcd5b1372b2d7',
130             'thumbnail': 're:^https?://.*\.jpg',
131             'duration': 754,
132             'age_limit': 6,
133             'view_count': int,
134         },
135         'params': {
136             'skip_download': True,
137         },
138     }]
139
140     @classmethod
141     def suitable(cls, url):
142         return False if VideomoreIE.suitable(url) else super(VideomoreVideoIE, cls).suitable(url)
143
144     def _real_extract(self, url):
145         display_id = self._match_id(url)
146
147         webpage = self._download_webpage(url, display_id)
148
149         video_url = self._og_search_property(
150             'video:iframe', webpage, 'video url', default=None)
151
152         if not video_url:
153             video_id = self._search_regex(
154                 (r'config\s*:\s*["\']https?://videomore\.ru/video/tracks/(\d+)\.xml',
155                  r'track-id=["\'](\d+)',
156                  r'xcnt_product_id\s*=\s*(\d+)'), webpage, 'video id')
157             video_url = 'videomore:%s' % video_id
158
159         return self.url_result(video_url, VideomoreIE.ie_key())
160
161
162 class VideomoreSeasonIE(InfoExtractor):
163     IE_NAME = 'videomore:season'
164     _VALID_URL = r'https?://videomore\.ru/(?!embed)(?P<id>[^/]+/[^/?#&]+)[/?#&]*$'
165     _TESTS = [{
166         'url': 'http://videomore.ru/molodezhka/sezon_promo',
167         'info_dict': {
168             'id': 'molodezhka/sezon_promo',
169             'title': 'Молодежка Промо',
170         },
171         'playlist_mincount': 12,
172     }]
173
174     def _real_extract(self, url):
175         display_id = self._match_id(url)
176
177         webpage = self._download_webpage(url, display_id)
178
179         title = self._og_search_title(webpage)
180
181         entries = [
182             self.url_result(item) for item in re.findall(
183                 r'<a[^>]+href="((?:https?:)?//videomore\.ru/%s/[^/]+)"[^>]+class="widget-item-desc"'
184                 % display_id, webpage)]
185
186         return self.playlist_result(entries, display_id, title)