-def server_numbers(first, boundaries):
- """ Server numbers to try in descending order of probable availability.
- Starting from first (i.e. the number of the server hosting the preview file)
- and going further and further up to the higher boundary and down to the
- lower one in an alternating fashion. Namely:
-
- server_numbers(2, (1, 5))
-
- # Where the preview server is 2, min number is 1 and max is 5.
- # Yields: 2, 3, 1, 4, 5
-
- Why not random numbers or increasing sequences? Since from what I've seen,
- full length files seem to be hosted on servers whose number is closer to
- that of the preview; to be confirmed.
- """
- zip_longest = getattr(itertools, 'zip_longest', None)
- if zip_longest is None:
- # python 2.x
- zip_longest = itertools.izip_longest
-
- if len(boundaries) != 2:
- raise ValueError("boundaries should be a two-element tuple")
- min, max = boundaries
- highs = range(first + 1, max + 1)
- lows = range(first - 1, min - 1, -1)
- rest = filter(
- None, itertools.chain.from_iterable(zip_longest(highs, lows)))
- yield first
- for n in rest:
- yield n
+class MixcloudUserIE(MixcloudPlaylistBaseIE):
+ _VALID_URL = r'https?://(?:www\.)?mixcloud\.com/(?P<id>[^/]+)/(?P<type>uploads|favorites|listens|stream)?/?$'
+ IE_NAME = 'mixcloud:user'
+
+ _TESTS = [{
+ 'url': 'http://www.mixcloud.com/dholbach/',
+ 'info_dict': {
+ 'id': 'dholbach_uploads',
+ 'title': 'Daniel Holbach (uploads)',
+ 'description': 'md5:b60d776f0bab534c5dabe0a34e47a789',
+ },
+ 'playlist_mincount': 36,
+ }, {
+ 'url': 'http://www.mixcloud.com/dholbach/uploads/',
+ 'info_dict': {
+ 'id': 'dholbach_uploads',
+ 'title': 'Daniel Holbach (uploads)',
+ 'description': 'md5:b60d776f0bab534c5dabe0a34e47a789',
+ },
+ 'playlist_mincount': 36,
+ }, {
+ 'url': 'http://www.mixcloud.com/dholbach/favorites/',
+ 'info_dict': {
+ 'id': 'dholbach_favorites',
+ 'title': 'Daniel Holbach (favorites)',
+ 'description': 'md5:b60d776f0bab534c5dabe0a34e47a789',
+ },
+ # 'params': {
+ # 'playlist_items': '1-100',
+ # },
+ 'playlist_mincount': 396,
+ }, {
+ 'url': 'http://www.mixcloud.com/dholbach/listens/',
+ 'info_dict': {
+ 'id': 'dholbach_listens',
+ 'title': 'Daniel Holbach (listens)',
+ 'description': 'md5:b60d776f0bab534c5dabe0a34e47a789',
+ },
+ # 'params': {
+ # 'playlist_items': '1-100',
+ # },
+ 'playlist_mincount': 1623,
+ 'skip': 'Large list',
+ }, {
+ 'url': 'https://www.mixcloud.com/FirstEar/stream/',
+ 'info_dict': {
+ 'id': 'FirstEar_stream',
+ 'title': 'First Ear (stream)',
+ 'description': 'Curators of good music\r\n\r\nfirstearmusic.com',
+ },
+ 'playlist_mincount': 271,
+ }]
+
+ _TITLE_KEY = 'displayName'
+ _DESCRIPTION_KEY = 'biog'
+ _ROOT_TYPE = 'user'
+ _NODE_TEMPLATE = '''slug
+ url'''
+
+ def _get_playlist_title(self, title, slug):
+ return '%s (%s)' % (title, slug)
+
+
+class MixcloudPlaylistIE(MixcloudPlaylistBaseIE):
+ _VALID_URL = r'https?://(?:www\.)?mixcloud\.com/(?P<user>[^/]+)/playlists/(?P<playlist>[^/]+)/?$'
+ IE_NAME = 'mixcloud:playlist'
+
+ _TESTS = [{
+ 'url': 'https://www.mixcloud.com/maxvibes/playlists/jazzcat-on-ness-radio/',
+ 'info_dict': {
+ 'id': 'maxvibes_jazzcat-on-ness-radio',
+ 'title': 'Ness Radio sessions',
+ },
+ 'playlist_mincount': 59,
+ }]
+ _TITLE_KEY = 'name'
+ _DESCRIPTION_KEY = 'description'
+ _ROOT_TYPE = 'playlist'
+ _NODE_TEMPLATE = '''cloudcast {
+ slug
+ url
+ }'''
+
+ def _get_cloudcast(self, node):
+ return node.get('cloudcast') or {}