Skip to content
This repository was archived by the owner on May 21, 2024. It is now read-only.
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions download.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"""

import argparse, requests, urllib2
import track, playlist
import track, playlist, likes


def print_download_stats(stats):
Expand All @@ -26,13 +26,18 @@ def print_download_stats(stats):
parser.add_argument('--track', '-t', help="Track full URL")
parser.add_argument('--playlist', '-p', help="Public or shared playlist URL")
parser.add_argument('--all', '-a', help="User URL. Download all tracks for all public playlists")
parser.add_argument('--likes', '-l', help="Download all of a user's likes.")
parser.add_argument('--id', help='Client ID', required=True)
parser.add_argument('--dir', help='Output directory.')
parser.add_argument(
'--override', '-d', action='store_true',
help='Override file if it exists. Defaults to false')
args = parser.parse_args()

dir = 'mp3'
if args.dir:
dir = args.dir
else:
dir = 'mp3'

error_msg = None
try:
Expand All @@ -47,6 +52,10 @@ def print_download_stats(stats):
error_msg = 'Error: User not found'
stats = playlist.download_all(args.id, args.all, base_dir=dir, override=args.override)
print_download_stats(stats)
elif args.likes:
error_msg = 'Error: User not found'
stats = likes.download_all_likes(args.id, args.likes, base_dir=dir, override=args.override)
print_download_stats(stats)
else:
parser.print_help()
print '\nError: you must specify either a track, a public (or shared) playlist or a user'
Expand Down
89 changes: 89 additions & 0 deletions likes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
# -*- coding: utf-8 -*-

import requests, os.path, soundcloud
from collections import Counter
import utils, track

# I need to make an instance of Resource from `soundcloud` but it's not working,
# so, this....
class ResourceDuck(object):
"""Object wrapper for resources.

Provides an object interface to resources returned by the Soundcloud API.
"""
def __init__(self, obj):
self.obj = obj
if hasattr(self, 'origin'):
self.origin = Resource(self.origin)

def __getstate__(self):
return self.obj.items()

def __setstate__(self, items):
if not hasattr(self, 'obj'):
self.obj = {}
for key, val in items:
self.obj[key] = val

def __getattr__(self, name):
if name in self.obj:
return self.obj.get(name)
raise AttributeError

def fields(self):
return self.obj

def keys(self):
return self.obj.keys()


def download_all_likes(client_id, user_url, base_dir, override=False):
"""Download all of a user's likes."""
downloaded = 0
skipped = 0
errors = 0

client = soundcloud.Client(client_id=client_id)
user = client.get('/resolve', url=user_url)

print "Finding likes..."

likes = []
current_url = '/users/%d/favorites?limit=100&offset=0&linked_partitioning=1' % (user.id)
while True:
print "."
query = client.get(current_url)

collection = query.fields()['collection']
wrapped_collection = []
for item in collection:
wrapped_collection.append(ResourceDuck(item))

likes.extend(wrapped_collection)

if 'next_href' in query.fields():
next_href = query.fields()['next_href']
start = next_href.find('/users/')
current_url = next_href[start:]
else:
break

print 'Downloading %d likes...' % len(likes)

for like in likes:
try:
done = track.download(client, like, base_dir, override)
if done: downloaded = downloaded + 1
else: skipped = skipped + 1
except requests.exceptions.HTTPError, err:
if err.response.status_code == 404:
print 'Error: could not download'
errors = errors + 1
else:
raise

print 'Likes downloaded.'

return Counter({
'downloaded': downloaded, 'skipped': skipped, 'errors': errors
})
10 changes: 10 additions & 0 deletions utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,15 @@ def create_dir(dir):

def build_file_name(dir, title):
"""Build the file name"""
title = title.replace("<", "[")
title = title.replace(">", "]")
title = title.replace(":", ";")
title = title.replace("\"", "'")
title = title.replace("/", " ")
title = title.replace("\\", " ")
title = title.replace("|", " ")
title = title.replace("?", " ")
title = title.replace("*", " ")

file_name = re.sub('/', '', title) + ".mp3"
return os.path.join(dir, file_name)