~facundo/encuentro/trunk

« back to all changes in this revision

Viewing changes to external/youtube-dl/youtube_dl/extractor/toggle.py

  • Committer: Facundo Batista
  • Date: 2015-12-27 11:27:15 UTC
  • mto: This revision was merged to the branch mainline in revision 274.
  • Revision ID: facundo@taniquetil.com.ar-20151227112715-ztuasdhqm26hycug
Able to download TEDx.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# coding: utf-8
 
2
from __future__ import unicode_literals
 
3
 
 
4
import json
 
5
import re
 
6
 
 
7
from .common import InfoExtractor
 
8
from ..utils import (
 
9
    determine_ext,
 
10
    ExtractorError,
 
11
    float_or_none,
 
12
    int_or_none,
 
13
    parse_iso8601,
 
14
    sanitized_Request,
 
15
)
 
16
 
 
17
 
 
18
class ToggleIE(InfoExtractor):
 
19
    IE_NAME = 'toggle'
 
20
    _VALID_URL = r'https?://video\.toggle\.sg/(?:en|zh)/(?:series|clips|movies)/(?:[^/]+/)+(?P<id>[0-9]+)'
 
21
    _TESTS = [{
 
22
        'url': 'http://video.toggle.sg/en/series/lion-moms-tif/trailers/lion-moms-premier/343115',
 
23
        'info_dict': {
 
24
            'id': '343115',
 
25
            'ext': 'mp4',
 
26
            'title': 'Lion Moms Premiere',
 
27
            'description': 'md5:aea1149404bff4d7f7b6da11fafd8e6b',
 
28
            'upload_date': '20150910',
 
29
            'timestamp': 1441858274,
 
30
        },
 
31
        'params': {
 
32
            'skip_download': 'm3u8 download',
 
33
        }
 
34
    }, {
 
35
        'note': 'DRM-protected video',
 
36
        'url': 'http://video.toggle.sg/en/movies/dug-s-special-mission/341413',
 
37
        'info_dict': {
 
38
            'id': '341413',
 
39
            'ext': 'wvm',
 
40
            'title': 'Dug\'s Special Mission',
 
41
            'description': 'md5:e86c6f4458214905c1772398fabc93e0',
 
42
            'upload_date': '20150827',
 
43
            'timestamp': 1440644006,
 
44
        },
 
45
        'params': {
 
46
            'skip_download': 'DRM-protected wvm download',
 
47
        }
 
48
    }, {
 
49
        # this also tests correct video id extraction
 
50
        'note': 'm3u8 links are geo-restricted, but Android/mp4 is okay',
 
51
        'url': 'http://video.toggle.sg/en/series/28th-sea-games-5-show/28th-sea-games-5-show-ep11/332861',
 
52
        'info_dict': {
 
53
            'id': '332861',
 
54
            'ext': 'mp4',
 
55
            'title': '28th SEA Games (5 Show) -  Episode  11',
 
56
            'description': 'md5:3cd4f5f56c7c3b1340c50a863f896faa',
 
57
            'upload_date': '20150605',
 
58
            'timestamp': 1433480166,
 
59
        },
 
60
        'params': {
 
61
            'skip_download': 'DRM-protected wvm download',
 
62
        },
 
63
        'skip': 'm3u8 links are geo-restricted'
 
64
    }, {
 
65
        'url': 'http://video.toggle.sg/en/clips/seraph-sun-aloysius-will-suddenly-sing-some-old-songs-in-high-pitch-on-set/343331',
 
66
        'only_matching': True,
 
67
    }, {
 
68
        'url': 'http://video.toggle.sg/zh/series/zero-calling-s2-hd/ep13/336367',
 
69
        'only_matching': True,
 
70
    }, {
 
71
        'url': 'http://video.toggle.sg/en/series/vetri-s2/webisodes/jeeva-is-an-orphan-vetri-s2-webisode-7/342302',
 
72
        'only_matching': True,
 
73
    }, {
 
74
        'url': 'http://video.toggle.sg/en/movies/seven-days/321936',
 
75
        'only_matching': True,
 
76
    }]
 
77
 
 
78
    _FORMAT_PREFERENCES = {
 
79
        'wvm-STBMain': -10,
 
80
        'wvm-iPadMain': -20,
 
81
        'wvm-iPhoneMain': -30,
 
82
        'wvm-Android': -40,
 
83
    }
 
84
    _API_USER = 'tvpapi_147'
 
85
    _API_PASS = '11111'
 
86
 
 
87
    def _real_extract(self, url):
 
88
        video_id = self._match_id(url)
 
89
 
 
90
        webpage = self._download_webpage(
 
91
            url, video_id, note='Downloading video page')
 
92
 
 
93
        api_user = self._search_regex(
 
94
            r'apiUser\s*:\s*(["\'])(?P<user>.+?)\1', webpage, 'apiUser',
 
95
            default=self._API_USER, group='user')
 
96
        api_pass = self._search_regex(
 
97
            r'apiPass\s*:\s*(["\'])(?P<pass>.+?)\1', webpage, 'apiPass',
 
98
            default=self._API_PASS, group='pass')
 
99
 
 
100
        params = {
 
101
            'initObj': {
 
102
                'Locale': {
 
103
                    'LocaleLanguage': '',
 
104
                    'LocaleCountry': '',
 
105
                    'LocaleDevice': '',
 
106
                    'LocaleUserState': 0
 
107
                },
 
108
                'Platform': 0,
 
109
                'SiteGuid': 0,
 
110
                'DomainID': '0',
 
111
                'UDID': '',
 
112
                'ApiUser': api_user,
 
113
                'ApiPass': api_pass
 
114
            },
 
115
            'MediaID': video_id,
 
116
            'mediaType': 0,
 
117
        }
 
118
 
 
119
        req = sanitized_Request(
 
120
            'http://tvpapi.as.tvinci.com/v2_9/gateways/jsonpostgw.aspx?m=GetMediaInfo',
 
121
            json.dumps(params).encode('utf-8'))
 
122
        info = self._download_json(req, video_id, 'Downloading video info json')
 
123
 
 
124
        title = info['MediaName']
 
125
 
 
126
        formats = []
 
127
        for video_file in info.get('Files', []):
 
128
            video_url, vid_format = video_file.get('URL'), video_file.get('Format')
 
129
            if not video_url or not vid_format:
 
130
                continue
 
131
            ext = determine_ext(video_url)
 
132
            vid_format = vid_format.replace(' ', '')
 
133
            # if geo-restricted, m3u8 is inaccessible, but mp4 is okay
 
134
            if ext == 'm3u8':
 
135
                m3u8_formats = self._extract_m3u8_formats(
 
136
                    video_url, video_id, ext='mp4', m3u8_id=vid_format,
 
137
                    note='Downloading %s m3u8 information' % vid_format,
 
138
                    errnote='Failed to download %s m3u8 information' % vid_format,
 
139
                    fatal=False)
 
140
                if m3u8_formats:
 
141
                    formats.extend(m3u8_formats)
 
142
            elif ext in ('mp4', 'wvm'):
 
143
                # wvm are drm-protected files
 
144
                formats.append({
 
145
                    'ext': ext,
 
146
                    'url': video_url,
 
147
                    'format_id': vid_format,
 
148
                    'preference': self._FORMAT_PREFERENCES.get(ext + '-' + vid_format) or -1,
 
149
                    'format_note': 'DRM-protected video' if ext == 'wvm' else None
 
150
                })
 
151
        if not formats:
 
152
            # Most likely because geo-blocked
 
153
            raise ExtractorError('No downloadable videos found', expected=True)
 
154
        self._sort_formats(formats)
 
155
 
 
156
        duration = int_or_none(info.get('Duration'))
 
157
        description = info.get('Description')
 
158
        created_at = parse_iso8601(info.get('CreationDate') or None)
 
159
 
 
160
        average_rating = float_or_none(info.get('Rating'))
 
161
        view_count = int_or_none(info.get('ViewCounter') or info.get('view_counter'))
 
162
        like_count = int_or_none(info.get('LikeCounter') or info.get('like_counter'))
 
163
 
 
164
        thumbnails = []
 
165
        for picture in info.get('Pictures', []):
 
166
            if not isinstance(picture, dict):
 
167
                continue
 
168
            pic_url = picture.get('URL')
 
169
            if not pic_url:
 
170
                continue
 
171
            thumbnail = {
 
172
                'url': pic_url,
 
173
            }
 
174
            pic_size = picture.get('PicSize', '')
 
175
            m = re.search(r'(?P<width>\d+)[xX](?P<height>\d+)', pic_size)
 
176
            if m:
 
177
                thumbnail.update({
 
178
                    'width': int(m.group('width')),
 
179
                    'height': int(m.group('height')),
 
180
                })
 
181
            thumbnails.append(thumbnail)
 
182
 
 
183
        return {
 
184
            'id': video_id,
 
185
            'title': title,
 
186
            'description': description,
 
187
            'duration': duration,
 
188
            'timestamp': created_at,
 
189
            'average_rating': average_rating,
 
190
            'view_count': view_count,
 
191
            'like_count': like_count,
 
192
            'thumbnails': thumbnails,
 
193
            'formats': formats,
 
194
        }