-
Notifications
You must be signed in to change notification settings - Fork 685
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
Soundcloud backend #339
Soundcloud backend #339
Changes from 17 commits
081c83f
c1f0292
af7fb08
5332647
da56b18
10eb425
ab98e35
7836140
6bf854a
ed14c47
b8055b5
e894c96
f24b0fb
12a3448
a2ce6d0
bcd2eee
57895e1
d7f093b
272c185
7f94568
3386353
9f4dfb9
8e50a94
023a038
1ab2740
ea17017
5dcd5fd
df3cf02
f27d2fe
a5b864b
9aed118
14286bf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
.. soundcloud-backend: | ||
|
||
************************************************* | ||
:mod:`mopidy.backends.soundcloud` -- SoundCloud backend | ||
************************************************* | ||
|
||
.. automodule:: mopidy.backends.soudcloud | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/soudcloud/soundcloud/ |
||
:synopsis: Backend for the SoundCloud music streaming service |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
"""A backend for playing music from Soundcloud. | ||
|
||
This backend handles URIs starting with ``soundcloud:``. | ||
|
||
See :ref:`music-from-soundcloud-storage` for further instructions on using this | ||
backend. | ||
|
||
**Issues:** | ||
|
||
https://github.com/mopidy/mopidy/issues?labels=Soundcloud+backend | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've created a label now. Please do a s/Soundcloud/SoundCloud/ |
||
|
||
**Dependencies:** | ||
|
||
.. literalinclude:: ../../../requirements/soundcloud.txt | ||
|
||
**Settings:** | ||
|
||
- :attr:`mopidy.settings.SOUNDCLOUD_AUTH_TOKEN` | ||
- :attr:`mopidy.settings.SOUNDCLOUD_EXPLORE` | ||
""" | ||
|
||
from __future__ import unicode_literals | ||
|
||
# flake8: noqa | ||
from .actor import SoundcloudBackend |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
from __future__ import unicode_literals | ||
|
||
import logging | ||
import pykka | ||
|
||
from mopidy import settings | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sort this block of imports. Should be in the opposite order. |
||
from mopidy.backends import base | ||
|
||
|
||
from .library import SoundcloudLibraryProvider | ||
from .playlists import SoundcloudPlaylistsProvider | ||
from .soundcloud import SoundCloudClient | ||
|
||
logger = logging.getLogger('mopidy.backends.soundcloud') | ||
|
||
|
||
class SoundcloudBackend(pykka.ThreadingActor, base.Backend): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/Soundcloud/SoundCloud/ There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And same for the rest of the class names. I won't comment on all of them. |
||
def __init__(self, audio): | ||
super(SoundcloudBackend, self).__init__() | ||
|
||
if not settings.SOUNDCLOUD_AUTH_TOKEN: | ||
logger.error(("In order to use SoundCloud backend " | ||
"you must provide settings.SOUNDCLOUD_AUTH_TOKEN. " | ||
"Get yours at http://www.mopidy.com/authenticate")) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What happens if you ignore this error and just try to use the SoundCloud backend? I guess something will crash with an There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I just ran into this case. Because I got a traceback about |
||
else: | ||
self.sc_api = SoundCloudClient( | ||
settings.SOUNDCLOUD_AUTH_TOKEN) | ||
|
||
self.library = SoundcloudLibraryProvider(backend=self) | ||
self.playback = base.BasePlaybackProvider(audio=audio, backend=self) | ||
self.playlists = SoundcloudPlaylistsProvider(backend=self) | ||
|
||
self.uri_schemes = ['soundcloud'] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
from __future__ import unicode_literals | ||
|
||
import logging | ||
|
||
from mopidy.backends import base | ||
from mopidy.models import SearchResult | ||
|
||
logger = logging.getLogger('mopidy.backends.soundcloud') | ||
|
||
|
||
class SoundcloudLibraryProvider(base.BaseLibraryProvider): | ||
def __init__(self, *args, **kwargs): | ||
super(SoundcloudLibraryProvider, self).__init__(*args, **kwargs) | ||
|
||
def find_exact(self, **query): | ||
return self.search(**query) | ||
|
||
def search(self, **query): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should maybe add some TODOs here if there are more stuff than we can make work with the SoundCloud search API. I'm thinking of things like:
If some of these features are not supported by SoundCloud, it should probably be documented in a docstring on the function. |
||
print(query) | ||
if not query: | ||
return | ||
|
||
for (field, val) in query.iteritems(): | ||
|
||
# TODO: Devise method for searching SoundCloud via artists | ||
if field == "album" and query['album'] == "SoundCloud": | ||
return SearchResult( | ||
uri='soundcloud:search', | ||
tracks=self.backend.sc_api.search(query['artist']) or []) | ||
elif field == "any": | ||
return SearchResult( | ||
uri='soundcloud:search', | ||
tracks=self.backend.sc_api.search(val[0]) or []) | ||
else: | ||
return [] | ||
|
||
def lookup(self, uri): | ||
try: | ||
id = uri.split('//')[1] | ||
logger.debug(u'SoundCloud track id for %s: %s' % (uri, id)) | ||
return [self.backend.sc_api.get_track(id, True)] | ||
except Exception as error: | ||
logger.debug(u'Failed to lookup %s: %s', uri, error) | ||
return [] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
from __future__ import unicode_literals | ||
|
||
import logging | ||
|
||
from mopidy import settings | ||
from mopidy.backends import base, listener | ||
from mopidy.models import Playlist | ||
|
||
logger = logging.getLogger('mopidy.backends.soundcloud.playlists') | ||
|
||
|
||
class SoundcloudPlaylistsProvider(base.BasePlaylistsProvider): | ||
|
||
def __init__(self, *args, **kwargs): | ||
super(SoundcloudPlaylistsProvider, self).__init__(*args, **kwargs) | ||
self.refresh() | ||
|
||
def create(self, name): | ||
pass # TODO | ||
|
||
def delete(self, uri): | ||
pass # TODO | ||
|
||
def lookup(self, uri): | ||
for playlist in self._playlists: | ||
if playlist.uri == uri: | ||
return playlist | ||
|
||
def refresh(self): | ||
logger.info('Loading playlists from SoundCloud') | ||
username = self.backend.sc_api.get_user().get('username') | ||
playlists = [] | ||
|
||
liked = Playlist( | ||
uri='soundcloud:playlist-liked', | ||
name="%s's liked on SoundCloud" % username, | ||
tracks=self.backend.sc_api.get_favorites() | ||
) | ||
playlists.append(liked) | ||
|
||
stream = Playlist( | ||
uri='soundcloud:playlist-user', | ||
name="%s's stream on SoundCloud" % username, | ||
tracks=self.backend.sc_api.get_user_stream() | ||
) | ||
playlists.append(stream) | ||
|
||
for (name, uri, tracks) in self.backend.sc_api.get_sets(): | ||
scset = Playlist( | ||
uri='soundcloud:%s' % uri, | ||
name=name, | ||
tracks=tracks | ||
) | ||
playlists.append(scset) | ||
|
||
for cat in settings.SOUNDCLOUD_EXPLORE: | ||
|
||
(category, section) = cat.split('/') | ||
logger.info('Fetching Explore playlist %s from SoundCloud' % section) | ||
tracks = self.backend.sc_api.get_explore_category( | ||
category, section) | ||
|
||
exp = Playlist( | ||
uri='soundcloud:cat-%s' % section.lower(), | ||
name='Explore %s on SoundCloud' % section, | ||
tracks=tracks | ||
) | ||
playlists.append(exp) | ||
|
||
self._playlists = playlists | ||
listener.BackendListener.send('playlists_loaded') | ||
|
||
def save(self, playlist): | ||
pass # TODO |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
***
rows should have equal length with the header text.