Merge remote-tracking branch 'upstream/master' into bliptv
[youtube-dl] / youtube_dl / extractor / beeg.py
1 from __future__ import unicode_literals
2
3 from .common import InfoExtractor
4 from ..compat import (
5     compat_chr,
6     compat_ord,
7     compat_urllib_parse_unquote,
8 )
9 from ..utils import (
10     int_or_none,
11     parse_iso8601,
12 )
13
14
15 class BeegIE(InfoExtractor):
16     _VALID_URL = r'https?://(?:www\.)?beeg\.com/(?P<id>\d+)'
17     _TEST = {
18         'url': 'http://beeg.com/5416503',
19         'md5': '46c384def73b33dbc581262e5ee67cef',
20         'info_dict': {
21             'id': '5416503',
22             'ext': 'mp4',
23             'title': 'Sultry Striptease',
24             'description': 'md5:d22219c09da287c14bed3d6c37ce4bc2',
25             'timestamp': 1391813355,
26             'upload_date': '20140207',
27             'duration': 383,
28             'tags': list,
29             'age_limit': 18,
30         }
31     }
32
33     def _real_extract(self, url):
34         video_id = self._match_id(url)
35
36         video = self._download_json(
37             'http://beeg.com/api/v3/video/%s' % video_id, video_id)
38
39         def decrypt_key(key):
40             # Reverse engineered from http://static.beeg.com/cpl/1067.js
41             a = '8RPUUCS35ZWp3ADnKcSmpH71ZusrROo'
42             e = compat_urllib_parse_unquote(key)
43             return ''.join([
44                 compat_chr(compat_ord(e[n]) - compat_ord(a[n % len(a)]) % 25)
45                 for n in range(len(e))])
46
47         def decrypt_url(encrypted_url):
48             encrypted_url = self._proto_relative_url(
49                 encrypted_url.replace('{DATA_MARKERS}', ''), 'http:')
50             key = self._search_regex(
51                 r'/key=(.*?)%2Cend=', encrypted_url, 'key', default=None)
52             if not key:
53                 return encrypted_url
54             return encrypted_url.replace(key, decrypt_key(key))
55
56         formats = []
57         for format_id, video_url in video.items():
58             if not video_url:
59                 continue
60             height = self._search_regex(
61                 r'^(\d+)[pP]$', format_id, 'height', default=None)
62             if not height:
63                 continue
64             formats.append({
65                 'url': decrypt_url(video_url),
66                 'format_id': format_id,
67                 'height': int(height),
68             })
69         self._sort_formats(formats)
70
71         title = video['title']
72         video_id = video.get('id') or video_id
73         display_id = video.get('code')
74         description = video.get('desc')
75
76         timestamp = parse_iso8601(video.get('date'), ' ')
77         duration = int_or_none(video.get('duration'))
78
79         tags = [tag.strip() for tag in video['tags'].split(',')] if video.get('tags') else None
80
81         return {
82             'id': video_id,
83             'display_id': display_id,
84             'title': title,
85             'description': description,
86             'timestamp': timestamp,
87             'duration': duration,
88             'tags': tags,
89             'formats': formats,
90             'age_limit': 18,
91         }