diff options
| -rwxr-xr-x | youtube-dl | 4 | ||||
| -rwxr-xr-x | youtube_dl/__init__.py | 122 | 
2 files changed, 125 insertions, 1 deletions
| diff --git a/youtube-dl b/youtube-dl index 1d4ebea41..1ce120007 100755 --- a/youtube-dl +++ b/youtube-dl @@ -3637,7 +3637,7 @@ class MixcloudIE(InfoExtractor):  			url_list = jsonData[fmt]  		return url_list -			 +  	def check_urls(self, url_list):  		"""Returns 1st active url from list"""  		for url in url_list: @@ -3729,6 +3729,8 @@ class MixcloudIE(InfoExtractor):  		except UnavailableVideoError, err:  			self._downloader.trouble(u'ERROR: unable to download file') + +  class PostProcessor(object):  	"""Post Processor class. diff --git a/youtube_dl/__init__.py b/youtube_dl/__init__.py index e6b7be110..1ce120007 100755 --- a/youtube_dl/__init__.py +++ b/youtube_dl/__init__.py @@ -3608,6 +3608,127 @@ class InfoQIE(InfoExtractor):  		except UnavailableVideoError, err:  			self._downloader.trouble(u'\nERROR: unable to download ' + video_url) +class MixcloudIE(InfoExtractor): +	"""Information extractor for www.mixcloud.com""" +	_VALID_URL = r'^(?:https?://)?(?:www\.)?mixcloud\.com/([\w\d-]+)/([\w\d-]+)' +	IE_NAME = u'mixcloud' + +	def __init__(self, downloader=None): +		InfoExtractor.__init__(self, downloader) + +	def report_download_json(self, file_id): +		"""Report JSON download.""" +		self._downloader.to_screen(u'[%s] Downloading json' % self.IE_NAME) + +	def report_extraction(self, file_id): +		"""Report information extraction.""" +		self._downloader.to_screen(u'[%s] %s: Extracting information' % (self.IE_NAME, file_id)) + +	def get_urls(self, jsonData, fmt, bitrate='best'): +		"""Get urls from 'audio_formats' section in json""" +		file_url = None +		try: +			bitrate_list = jsonData[fmt] +			if bitrate is None or bitrate == 'best' or bitrate not in bitrate_list: +				bitrate = max(bitrate_list) # select highest + +			url_list = jsonData[fmt][bitrate] +		except TypeError: # we have no bitrate info. +			url_list = jsonData[fmt] +				 +		return url_list + +	def check_urls(self, url_list): +		"""Returns 1st active url from list""" +		for url in url_list: +			try: +				urllib2.urlopen(url) +				return url +			except (urllib2.URLError, httplib.HTTPException, socket.error), err: +				url = None + +		return None + +	def _print_formats(self, formats): +		print 'Available formats:' +		for fmt in formats.keys(): +			for b in formats[fmt]: +				try: +					ext = formats[fmt][b][0] +					print '%s\t%s\t[%s]' % (fmt, b, ext.split('.')[-1]) +				except TypeError: # we have no bitrate info +					ext = formats[fmt][0] +					print '%s\t%s\t[%s]' % (fmt, '??', ext.split('.')[-1]) +					break + +	def _real_extract(self, url): +		mobj = re.match(self._VALID_URL, url) +		if mobj is None: +			self._downloader.trouble(u'ERROR: invalid URL: %s' % url) +			return +		# extract uploader & filename from url +		uploader = mobj.group(1).decode('utf-8') +		file_id = uploader + "-" + mobj.group(2).decode('utf-8') + +		# construct API request +		file_url = 'http://www.mixcloud.com/api/1/cloudcast/' + '/'.join(url.split('/')[-3:-1]) + '.json' +		# retrieve .json file with links to files +		request = urllib2.Request(file_url) +		try: +			self.report_download_json(file_url) +			jsonData = urllib2.urlopen(request).read() +		except (urllib2.URLError, httplib.HTTPException, socket.error), err: +			self._downloader.trouble(u'ERROR: Unable to retrieve file: %s' % str(err)) +			return + +		# parse JSON +		json_data = json.loads(jsonData) +		player_url = json_data['player_swf_url'] +		formats = dict(json_data['audio_formats']) + +		req_format = self._downloader.params.get('format', None) +		bitrate = None + +		if self._downloader.params.get('listformats', None): +			self._print_formats(formats) +			return + +		if req_format is None or req_format == 'best': +			for format_param in formats.keys(): +				url_list = self.get_urls(formats, format_param) +				# check urls +				file_url = self.check_urls(url_list) +				if file_url is not None: +					break # got it! +		else: +			if req_format not in formats.keys(): +				self._downloader.trouble(u'ERROR: format is not available') +				return + +			url_list = self.get_urls(formats, req_format) +			file_url = self.check_urls(url_list) +			format_param = req_format + +		# We have audio +		self._downloader.increment_downloads() +		try: +			# Process file information +			self._downloader.process_info({ +				'id':		file_id.decode('utf-8'), +				'url':		file_url.decode('utf-8'), +				'uploader':	uploader.decode('utf-8'), +				'upload_date':	u'NA', +				'title':	json_data['name'], +				'stitle':	_simplify_title(json_data['name']), +				'ext':		file_url.split('.')[-1].decode('utf-8'), +				'format':	(format_param is None and u'NA' or format_param.decode('utf-8')), +				'thumbnail':    json_data['thumbnail_url'], +				'description':  json_data['description'], +				'player_url':	player_url.decode('utf-8'), +			}) +		except UnavailableVideoError, err: +			self._downloader.trouble(u'ERROR: unable to download file') +  class PostProcessor(object): @@ -4008,6 +4129,7 @@ def gen_extractors():  		XVideosIE(),  		SoundcloudIE(),  		InfoQIE(), +		MixcloudIE(),  		GenericIE()  	] | 
