Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#48 stream shows a configurable amount of tracks and playlists now #73

Closed
wants to merge 5 commits into from
Closed
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
1 change: 1 addition & 0 deletions README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ Configuration
[soundcloud]
auth_token = 1-1111-1111111
explore_songs = 25
stream_entries = 100


Project resources
Expand Down
1 change: 1 addition & 0 deletions mopidy_soundcloud/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def get_config_schema(self):
schema['auth_token'] = config.Secret()
schema['explore'] = config.Deprecated()
schema['explore_pages'] = config.Deprecated()
schema['stream_entries'] = config.Integer()
return schema

def validate_config(self, config): # no_coverage
Expand Down
5 changes: 4 additions & 1 deletion mopidy_soundcloud/ext.conf
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,7 @@ enabled = True
auth_token =

# Number of songs to fetch in explore section
explore_songs = 25
explore_songs = 25

# Number of tracks and playlists to fetch from user stream
stream_entries = 100
22 changes: 17 additions & 5 deletions mopidy_soundcloud/library.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@

from mopidy_soundcloud.soundcloud import safe_url


logger = logging.getLogger(__name__)


Expand All @@ -27,7 +26,6 @@ def new_folder(name, path):


def simplify_search_query(query):

if isinstance(query, dict):
r = []
for v in query.values():
Expand Down Expand Up @@ -84,6 +82,22 @@ def list_liked(self):
vfs_list[set_id] = new_folder(name, ['sets', set_id])
return vfs_list.values()

def list_stream(self):
vfs_list = collections.OrderedDict()
for data in self.backend.remote.get_user_stream():
try:
name, set_id = data
except (TypeError, ValueError):
logger.debug(
'Adding track "%s" from stream to vfs' % data.name)
vfs_list[data.name] = models.Ref.track(
uri=data.uri, name=data.name
)
else:
logger.debug('Adding playlist "%s" from stream to vfs' % name)
vfs_list[set_id] = new_folder(name, ['sets', set_id])
return vfs_list.values()

def list_user_follows(self):
sets_vfs = collections.OrderedDict()
for (name, user_id) in self.backend.remote.get_followings():
Expand Down Expand Up @@ -166,9 +180,7 @@ def browse(self, uri):
return self.list_liked()
# User stream
if 'stream' == req_type:
return self.tracklist_to_vfs(
self.backend.remote.get_user_stream()
)
return self.list_stream()

# root directory
return self.vfs.get(uri, {}).values()
Expand Down
38 changes: 19 additions & 19 deletions mopidy_soundcloud/soundcloud.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from __future__ import unicode_literals

import collections
import logging
import re
import string
Expand All @@ -13,7 +12,6 @@

import requests


logger = logging.getLogger(__name__)


Expand Down Expand Up @@ -71,6 +69,7 @@ def __init__(self, config):
super(SoundCloudClient, self).__init__()
token = config['auth_token']
self.explore_songs = config.get('explore_songs', 10)
self.stream_entries = config.get('stream_entries', 100)
self.http_client = requests.Session()
self.http_client.headers.update({'Authorization': 'OAuth %s' % token})

Expand All @@ -90,23 +89,24 @@ def user(self):

@cache()
def get_user_stream(self):
# User timeline like playlist which uses undocumented api
# https://api.soundcloud.com/e1/me/stream.json?offset=0
# returns five elements per request
tracks = []
for sid in xrange(0, 2):
stream = self._get('e1/me/stream.json?offset=%s' % sid * 5)
for data in stream.get('collection'):
kind = data.get('type')
# multiple types of track with same data
if 'track' in kind:
tracks.append(self.parse_track(data.get('track')))
if kind == 'playlist':
playlist = data.get('playlist').get('tracks')
if isinstance(playlist, collections.Iterable):
tracks.extend(self.parse_results(playlist))

return self.sanitize_tracks(tracks)
# User timeline like playlist which uses undocumented api:
# https://api.soundcloud.com/e1/me/stream.json?limit=0
# Additional parameters are: 'promoted_playlist=true'
# or 'offset=00000152-cc97-84a0-0000-00002a293ab5'
tracks_and_playlists = []
stream = self._get('e1/me/stream.json?limit=%s' % self.stream_entries)
for data in stream.get('collection'):
kind = data.get('type')
# multiple types of track with same data
if 'track' in kind:
tracks_and_playlists.append(
self.parse_track(data.get('track')))
if 'playlist' in kind:
playlist = data.get('playlist')
tracks_and_playlists.append(
(playlist.get('title'), str(playlist.get('id'))))

return self.sanitize_tracks(tracks_and_playlists)

@cache()
def get_explore_categories(self):
Expand Down
35 changes: 3 additions & 32 deletions tests/fixtures/sc-stream.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,38 +6,9 @@ interactions:
Accept-Encoding: ['gzip, deflate']
Authorization: [!!python/unicode 'OAuth 1-35204-61921957-55796ebef403996']
Connection: [keep-alive]
User-Agent: [python-requests/2.4.3 CPython/2.7.8 Linux/3.16.0-28-generic]
User-Agent: [python-requests/2.9.1]
method: GET
uri: https://api.soundcloud.com:443/e1/me/stream.json?offset=0e1/me/stream.json?offset=0e1/me/stream.json?offset=0e1/me/stream.json?offset=0e1/me/stream.json?offset=0&client_id=93e33e327fd8a9b77becd179652272e2
response:
body:
string: !!binary |
H4sIAAAAAAAAAATBwQqAIAwA0H/ZOVxehehDIkJsoqFOdDtF/957L0QVHXSlQREcJJE+HaLv2UzW
dofCepvAFcliJZwyyFfzTG57yTXLZldYIHApFCRzA3ec3w8AAP//AwCP9XBDVwAAAA==
headers:
access-control-allow-headers: ['Accept, Authorization, Content-Type, Origin']
access-control-allow-methods: ['GET, PUT, POST, DELETE']
access-control-allow-origin: ['*']
access-control-expose-headers: [Date]
cache-control: ['private, max-age=0']
content-encoding: [gzip]
content-length: ['106']
content-type: [application/json]
date: ['Fri, 02 Jan 2015 17:03:54 GMT']
server: [am/2]
set-cookie: [_session_auth_key="iuo9QNN6oaPVa3gj9XyKTHZtsxE="]
status: {code: 200, message: OK}
- request:
body: null
headers:
Accept: ['*/*']
Accept-Encoding: ['gzip, deflate']
Authorization: [!!python/unicode 'OAuth 1-35204-61921957-55796ebef403996']
Connection: [keep-alive]
Cookie: [_session_auth_key="iuo9QNN6oaPVa3gj9XyKTHZtsxE="]
User-Agent: [python-requests/2.4.3 CPython/2.7.8 Linux/3.16.0-28-generic]
method: GET
uri: https://api.soundcloud.com:443/e1/me/stream.json?offset=1e1/me/stream.json?offset=1e1/me/stream.json?offset=1e1/me/stream.json?offset=1e1/me/stream.json?offset=1&client_id=93e33e327fd8a9b77becd179652272e2
uri: https://api.soundcloud.com/e1/me/stream.json?limit=10&client_id=93e33e327fd8a9b77becd179652272e2
response:
body:
string: !!binary |
Expand All @@ -52,7 +23,7 @@ interactions:
content-encoding: [gzip]
content-length: ['106']
content-type: [application/json]
date: ['Fri, 02 Jan 2015 17:03:54 GMT']
date: ['Sat, 20 Feb 2016 19:14:11 GMT']
server: [am/2]
status: {code: 200, message: OK}
version: 1
5 changes: 3 additions & 2 deletions tests/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ def setUp(self):
config = SoundCloudExtension().get_config_schema()
config['auth_token'] = '1-35204-61921957-55796ebef403996'
config['explore_songs'] = 10
config['stream_entries'] = 10
# using this user http://maildrop.cc/inbox/mopidytestuser
self.api = SoundCloudClient(config)

Expand Down Expand Up @@ -75,8 +76,8 @@ def test_get_user_liked(self):

@vcr.use_cassette('tests/fixtures/sc-stream.yaml')
def test_get_user_stream(self):
tracks = self.api.get_user_stream()
self.assertIsInstance(tracks, list)
tracks_and_playlists = self.api.get_user_stream()
self.assertIsInstance(tracks_and_playlists, list)

@vcr.use_cassette('tests/fixtures/sc-explore.yaml')
def test_get_explore(self):
Expand Down
1 change: 1 addition & 0 deletions tests/test_extension.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,4 @@ def test_get_config_schema(self):

self.assertIn('auth_token', schema)
self.assertIn('explore_songs', schema)
self.assertIn('stream_entries', schema)