Merge remote-tracking branch 'ruuk/master'
[youtube-dl] / youtube_dl / extractor / mixcloud.py
1 from __future__ import unicode_literals
2
3 import re
4
5 from .common import InfoExtractor
6 from ..utils import (
7     unified_strdate,
8     ExtractorError,
9 )
10
11
12 class MixcloudIE(InfoExtractor):
13     _VALID_URL = r'^(?:https?://)?(?:www\.)?mixcloud\.com/([^/]+)/([^/]+)'
14     IE_NAME = 'mixcloud'
15
16     _TEST = {
17         'url': 'http://www.mixcloud.com/dholbach/cryptkeeper/',
18         'file': 'dholbach-cryptkeeper.mp3',
19         'info_dict': {
20             'title': 'Cryptkeeper',
21             'description': 'After quite a long silence from myself, finally another Drum\'n\'Bass mix with my favourite current dance floor bangers.',
22             'uploader': 'Daniel Holbach',
23             'uploader_id': 'dholbach',
24             'upload_date': '20111115',
25         },
26     }
27
28     def check_urls(self, url_list):
29         """Returns 1st active url from list"""
30         for url in url_list:
31             try:
32                 # We only want to know if the request succeed
33                 # don't download the whole file
34                 self._request_webpage(url, None, False)
35                 return url
36             except ExtractorError:
37                 url = None
38
39         return None
40
41     def _get_url(self, template_url):
42         return self.check_urls(template_url % i for i in range(30))
43
44     def _real_extract(self, url):
45         mobj = re.match(self._VALID_URL, url)
46         uploader = mobj.group(1)
47         cloudcast_name = mobj.group(2)
48         track_id = '-'.join((uploader, cloudcast_name))
49
50         webpage = self._download_webpage(url, track_id)
51
52         api_url = 'http://api.mixcloud.com/%s/%s/' % (uploader, cloudcast_name)
53         info = self._download_json(
54             api_url, track_id, 'Downloading cloudcast info')
55
56         preview_url = self._search_regex(
57             r'\s(?:data-preview-url|m-preview)="(.+?)"', webpage, 'preview url')
58         song_url = preview_url.replace('/previews/', '/c/originals/')
59         template_url = re.sub(r'(stream\d*)', 'stream%d', song_url)
60         final_song_url = self._get_url(template_url)
61         if final_song_url is None:
62             self.to_screen('Trying with m4a extension')
63             template_url = template_url.replace('.mp3', '.m4a').replace('originals/', 'm4a/64/')
64             final_song_url = self._get_url(template_url)
65         if final_song_url is None:
66             raise ExtractorError(u'Unable to extract track url')
67
68         return {
69             'id': track_id,
70             'title': info['name'],
71             'url': final_song_url,
72             'description': info.get('description'),
73             'thumbnail': info['pictures'].get('extra_large'),
74             'uploader': info['user']['name'],
75             'uploader_id': info['user']['username'],
76             'upload_date': unified_strdate(info['created_time']),
77             'view_count': info['play_count'],
78         }