Skip to content

Instantly share code, notes, and snippets.

@rctay
Last active November 14, 2018 19:52
Show Gist options
  • Save rctay/9065133 to your computer and use it in GitHub Desktop.
Save rctay/9065133 to your computer and use it in GitHub Desktop.
SoundCloud set/playlist shuffle via Python + Requests + mpg123. Ctrl-C for next (press Ctrl-C in quick succession to quit), Ctrl-Z/fg to pause/resume
import requests
import soundcloud
import random
import socket
import subprocess
SOUNDCLOUD_API_KEY = '00000000000000000000000000000000'
PLAYLIST_URL = 'https://soundcloud.com/nervomusic/sets/nervomusic-com'
client = soundcloud.Client(client_id=SOUNDCLOUD_API_KEY)
playlist = client.get('/resolve', url=PLAYLIST_URL)
class Player(object):
def __init__(self):
self.p = None
self.reset()
def reset(self):
if self.p:
self.close()
self.p = subprocess.Popen(['mpg123', '-'], stdin=subprocess.PIPE)
def write(self, chunk):
self.p.stdin.write(chunk)
def close(self):
self.p.stdin.close()
self.p.wait()
p = Player()
CHUNK_SZ = 512
while True:
try:
random.shuffle(playlist.tracks)
for track in playlist.tracks:
print track['title']
done = False
first = True
pos, sz = None, None
while not done:
headers = {}
if pos > 0:
headers['Range'] = "bytes=%d-" % pos
try:
# go through soundcloud api always, in case stream url expires
stream = client.get(track['stream_url'], allow_redirects=False)
req = requests.get(stream.location, stream=True, headers=headers)
except requests.exceptions.HTTPError as e:
print "stream got error", str(e)
done = True
continue
if first:
first = False
sz = int(req.headers['content-length'])
pos = 0
try:
for chunk in req.iter_content(CHUNK_SZ):
pos += len(chunk)
try:
p.write(chunk)
except IOError as e:
import errno
if e.errno in [errno.EPIPE, errno.EINVAL]:
print "broken pipe"
p.reset()
else:
print "io error", str(e)
raise
# in case the stream may be exhausted but we have not read the whole
# response
done = pos >= sz
if not done:
print "more to read, retrying"
except socket.error as e:
print str(e), "retrying..."
done = False
except KeyboardInterrupt:
# behaves like a next
done = True
req.close()
except KeyboardInterrupt:
break
p.close()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment