]>
Commit | Line | Data |
---|---|---|
8244288d | 1 | # coding: utf-8 |
e7916255 | 2 | from __future__ import unicode_literals |
8244288d | 3 | |
99afb3dd | 4 | import re |
a54bda3a | 5 | import hashlib |
99afb3dd JMF |
6 | |
7 | from .common import InfoExtractor | |
86916dae S |
8 | from ..utils import ( |
9 | ExtractorError, | |
10 | unified_strdate, | |
11 | ) | |
99afb3dd JMF |
12 | |
13 | ||
14 | class WatIE(InfoExtractor): | |
a54bda3a | 15 | _VALID_URL = r'http://www\.wat\.tv/video/(?P<display_id>.*)-(?P<short_id>.*?)_.*?\.html' |
99afb3dd | 16 | IE_NAME = 'wat.tv' |
c28df247 S |
17 | _TESTS = [ |
18 | { | |
19 | 'url': 'http://www.wat.tv/video/soupe-figues-l-orange-aux-epices-6z1uz_2hvf7_.html', | |
20 | 'md5': 'ce70e9223945ed26a8056d413ca55dc9', | |
21 | 'info_dict': { | |
22 | 'id': '11713067', | |
23 | 'display_id': 'soupe-figues-l-orange-aux-epices', | |
24 | 'ext': 'mp4', | |
25 | 'title': 'Soupe de figues à l\'orange et aux épices', | |
26 | 'description': 'Retrouvez l\'émission "Petits plats en équilibre", diffusée le 18 août 2014.', | |
27 | 'upload_date': '20140819', | |
28 | 'duration': 120, | |
29 | }, | |
30 | }, | |
31 | { | |
32 | 'url': 'http://www.wat.tv/video/gregory-lemarchal-voix-ange-6z1v7_6ygkj_.html', | |
33 | 'md5': 'fbc84e4378165278e743956d9c1bf16b', | |
34 | 'info_dict': { | |
35 | 'id': '11713075', | |
36 | 'display_id': 'gregory-lemarchal-voix-ange', | |
37 | 'ext': 'mp4', | |
38 | 'title': 'Grégory Lemarchal, une voix d\'ange depuis 10 ans (1/3)', | |
39 | 'description': 'md5:b7a849cf16a2b733d9cd10c52906dee3', | |
40 | 'upload_date': '20140816', | |
41 | 'duration': 2910, | |
42 | }, | |
fa800269 | 43 | }, |
c28df247 | 44 | ] |
e7916255 | 45 | |
8244288d JMF |
46 | def download_video_info(self, real_id): |
47 | # 'contentv4' is used in the website, but it also returns the related | |
48 | # videos, we don't need them | |
e7916255 | 49 | info = self._download_json('http://www.wat.tv/interface/contentv3/' + real_id, real_id) |
8244288d JMF |
50 | return info['media'] |
51 | ||
99afb3dd | 52 | def _real_extract(self, url): |
8244288d JMF |
53 | def real_id_for_chapter(chapter): |
54 | return chapter['tc_start'].split('-')[0] | |
99afb3dd | 55 | mobj = re.match(self._VALID_URL, url) |
a54bda3a S |
56 | short_id = mobj.group('short_id') |
57 | display_id = mobj.group('display_id') | |
58 | webpage = self._download_webpage(url, display_id or short_id) | |
8244288d JMF |
59 | real_id = self._search_regex(r'xtpage = ".*-(.*?)";', webpage, 'real id') |
60 | ||
61 | video_info = self.download_video_info(real_id) | |
a54bda3a | 62 | |
86916dae S |
63 | error_desc = video_info.get('error_desc') |
64 | if error_desc: | |
65 | raise ExtractorError( | |
66 | '%s returned error: %s' % (self.IE_NAME, error_desc), expected=True) | |
67 | ||
c28df247 S |
68 | geo_list = video_info.get('geoList') |
69 | country = geo_list[0] if geo_list else '' | |
a54bda3a | 70 | |
8244288d JMF |
71 | chapters = video_info['chapters'] |
72 | first_chapter = chapters[0] | |
a54bda3a S |
73 | files = video_info['files'] |
74 | first_file = files[0] | |
99afb3dd | 75 | |
8244288d JMF |
76 | if real_id_for_chapter(first_chapter) != real_id: |
77 | self.to_screen('Multipart video detected') | |
78 | chapter_urls = [] | |
79 | for chapter in chapters: | |
80 | chapter_id = real_id_for_chapter(chapter) | |
81 | # Yes, when we this chapter is processed by WatIE, | |
82 | # it will download the info again | |
83 | chapter_info = self.download_video_info(chapter_id) | |
84 | chapter_urls.append(chapter_info['url']) | |
85 | entries = [self.url_result(chapter_url) for chapter_url in chapter_urls] | |
86 | return self.playlist_result(entries, real_id, video_info['title']) | |
87 | ||
e7916255 JMF |
88 | upload_date = None |
89 | if 'date_diffusion' in first_chapter: | |
90 | upload_date = unified_strdate(first_chapter['date_diffusion']) | |
8244288d JMF |
91 | # Otherwise we can continue and extract just one part, we have to use |
92 | # the short id for getting the video url | |
a54bda3a S |
93 | |
94 | formats = [{ | |
95 | 'url': 'http://wat.tv/get/android5/%s.mp4' % real_id, | |
96 | 'format_id': 'Mobile', | |
97 | }] | |
98 | ||
99 | fmts = [('SD', 'web')] | |
100 | if first_file.get('hasHD'): | |
101 | fmts.append(('HD', 'webhd')) | |
102 | ||
103 | def compute_token(param): | |
c28df247 S |
104 | timestamp = '%08x' % int(self._download_webpage( |
105 | 'http://www.wat.tv/servertime', real_id, | |
106 | 'Downloading server time').split('|')[0]) | |
a54bda3a S |
107 | magic = '9b673b13fa4682ed14c3cfa5af5310274b514c4133e9b3a81e6e3aba009l2564' |
108 | return '%s/%s' % (hashlib.md5((magic + param + timestamp).encode('ascii')).hexdigest(), timestamp) | |
109 | ||
110 | for fmt in fmts: | |
111 | webid = '/%s/%s' % (fmt[1], real_id) | |
112 | video_url = self._download_webpage( | |
c28df247 | 113 | 'http://www.wat.tv/get%s?token=%s&getURL=1&country=%s' % (webid, compute_token(webid), country), |
a54bda3a S |
114 | real_id, |
115 | 'Downloding %s video URL' % fmt[0], | |
116 | 'Failed to download %s video URL' % fmt[0], | |
117 | False) | |
118 | if not video_url: | |
119 | continue | |
120 | formats.append({ | |
121 | 'url': video_url, | |
122 | 'ext': 'mp4', | |
123 | 'format_id': fmt[0], | |
124 | }) | |
125 | ||
e7916255 JMF |
126 | return { |
127 | 'id': real_id, | |
a54bda3a | 128 | 'display_id': display_id, |
e7916255 JMF |
129 | 'title': first_chapter['title'], |
130 | 'thumbnail': first_chapter['preview'], | |
131 | 'description': first_chapter['description'], | |
132 | 'view_count': video_info['views'], | |
133 | 'upload_date': upload_date, | |
a54bda3a S |
134 | 'duration': first_file['duration'], |
135 | 'formats': formats, | |
e7916255 | 136 | } |