Compare commits
20 commits
Author | SHA1 | Date | |
---|---|---|---|
ebb2dab571 | |||
62429f22bd | |||
![]() |
4bc641e95a | ||
![]() |
5ce65f0a08 | ||
![]() |
b5e0de1e4d | ||
![]() |
e8493923c1 | ||
![]() |
32f74f28e9 | ||
![]() |
cf588481c6 | ||
![]() |
876bec6711 | ||
![]() |
7064dd9e50 | ||
![]() |
81a62cdca4 | ||
![]() |
1bc9e35d83 | ||
![]() |
6857653cdb | ||
![]() |
511a101c2c | ||
![]() |
f7090127fe | ||
![]() |
31023236ae | ||
![]() |
eff25672d9 | ||
![]() |
584209c134 | ||
![]() |
ee3e36408d | ||
![]() |
713845090c |
7 changed files with 137 additions and 18 deletions
35
PKGBUILD
Normal file
35
PKGBUILD
Normal file
|
@ -0,0 +1,35 @@
|
|||
# Maintainer: Matthew Gamble <git@matthewgamble.net>
|
||||
# Contributor: Frederick Gnodtke <fgnodtke at cronosx dot de>
|
||||
|
||||
pkgname=mopidy-subidy
|
||||
pkgver=1.3.0
|
||||
pkgrel=2
|
||||
pkgdesc="Mopidy extension for playing music from Subsonic servers"
|
||||
arch=("any")
|
||||
url="https://git.hannover.ccc.de/lubiana/mopidy-subidy/releases"
|
||||
license=('BSD')
|
||||
depends=(
|
||||
"mopidy"
|
||||
"python"
|
||||
"python-setuptools"
|
||||
"python-pykka"
|
||||
"python-pysonic"
|
||||
)
|
||||
source=("https://git.hannover.ccc.de/lubiana/mopidy-subidy/archive/1.0.0.tar.gz")
|
||||
sha256sums=("ed78ce86da58fb42f6ddf9a8de72169d23521125b269b51054d69375b57c5b73")
|
||||
|
||||
build() {
|
||||
cd "mopidy-subidy"
|
||||
|
||||
python setup.py build
|
||||
}
|
||||
|
||||
package() {
|
||||
cd "mopidy-subidy"
|
||||
|
||||
PYTHONHASHSEED=0 python setup.py install --root="${pkgdir}" --optimize=1 --skip-build
|
||||
|
||||
install -Dm644 LICENSE "${pkgdir}/usr/share/licenses/mopidy-subidy/LICENSE"
|
||||
install -Dm644 README.rst "${pkgdir}/usr/share/doc/mopidy-subidy/README.rst"
|
||||
install -Dm644 CHANGELOG.rst "${pkgdir}/usr/share/doc/mopidy-subidy/CHANGELOG.rst"
|
||||
}
|
|
@ -14,6 +14,8 @@ Mopidy-Subidy
|
|||
:target: https://codecov.io/gh/Prior99/mopidy-subidy
|
||||
:alt: Test coverage
|
||||
|
||||
**This library is actively looking for maintainers to help out as I do not have the time or need to maintain this anymore. Please contact me if you feel that you could maintain this.**
|
||||
|
||||
A Subsonic backend for Mopidy using `py-sonic
|
||||
<https://github.com/crustymonkey/py-sonic>`_.
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
dict(id="artists", name="Artists"),
|
||||
dict(id="albums", name="Albums"),
|
||||
dict(id="rootdirs", name="Directories"),
|
||||
dict(id="random", name="Random"),
|
||||
]
|
||||
# Create a dict with the keys being the `id`s in `vdir_templates`
|
||||
# and the values being objects containing the vdir `id`,
|
||||
|
@ -52,6 +53,9 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
def browse_rootdirs(self):
|
||||
return self.subsonic_api.get_rootdirs_as_refs()
|
||||
|
||||
def browse_random_songs(self):
|
||||
return self.subsonic_api.get_random_songs_as_refs()
|
||||
|
||||
def browse_diritems(self, directory_id):
|
||||
return self.subsonic_api.get_diritems_as_refs(directory_id)
|
||||
|
||||
|
@ -82,7 +86,7 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
|
||||
def browse(self, browse_uri):
|
||||
if browse_uri == uri.get_vdir_uri("root"):
|
||||
root_vdir_names = ["rootdirs", "artists", "albums"]
|
||||
root_vdir_names = ["rootdirs", "artists", "albums", "random"]
|
||||
root_vdirs = [
|
||||
self._vdirs[vdir_name] for vdir_name in root_vdir_names
|
||||
]
|
||||
|
@ -96,6 +100,9 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
return self.browse_artists()
|
||||
elif browse_uri == uri.get_vdir_uri("albums"):
|
||||
return self.browse_albums()
|
||||
elif browse_uri == uri.get_vdir_uri("random"):
|
||||
return self.browse_random_songs()
|
||||
|
||||
else:
|
||||
uri_type = uri.get_type(browse_uri)
|
||||
if uri_type == uri.DIRECTORY:
|
||||
|
@ -138,15 +145,34 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
return SearchResult(tracks=[track])
|
||||
|
||||
def search_by_artist_and_album(self, artist_name, album_name):
|
||||
artists = self.subsonic_api.get_raw_artists()
|
||||
artist = next(
|
||||
item for item in artists if artist_name in item.get("name")
|
||||
artists = self.subsonic_api.find_raw(artist_name).get("artist")
|
||||
if artists is None:
|
||||
return None
|
||||
tracks = []
|
||||
for artist in artists:
|
||||
for album in self.subsonic_api.get_raw_albums(artist.get("id")):
|
||||
if album_name in album.get("name"):
|
||||
tracks.extend(
|
||||
self.subsonic_api.get_songs_as_tracks(album.get("id"))
|
||||
)
|
||||
albums = self.subsonic_api.get_raw_albums(artist.get("id"))
|
||||
album = next(item for item in albums if album_name in item.get("title"))
|
||||
return SearchResult(
|
||||
tracks=self.subsonic_api.get_songs_as_tracks(album.get("id"))
|
||||
return SearchResult(tracks=tracks)
|
||||
|
||||
def search_by_artist(self, artist_name, exact):
|
||||
result = self.subsonic_api.find_raw(artist_name)
|
||||
if result is None:
|
||||
return None
|
||||
tracks = []
|
||||
for artist in result.get("artist"):
|
||||
if exact:
|
||||
if not artist.get("name") == artist_name:
|
||||
continue
|
||||
|
||||
tracks.extend(
|
||||
self.subsonic_api.get_artist_as_songs_as_tracks_iter(
|
||||
artist.get("id")
|
||||
)
|
||||
)
|
||||
return SearchResult(uri=uri.get_search_uri(artist_name), tracks=tracks)
|
||||
|
||||
def get_distinct(self, field, query):
|
||||
search_result = self.search(query)
|
||||
|
@ -173,8 +199,11 @@ class SubidyLibraryProvider(backend.LibraryProvider):
|
|||
query.get("artist")[0], query.get("album")[0]
|
||||
)
|
||||
if "artist" in query:
|
||||
return self.subsonic_api.find_as_search_result(
|
||||
query.get("artist")[0]
|
||||
return self.search_by_artist(query.get("artist")[0], exact)
|
||||
if "comment" in query:
|
||||
if query.get("comment")[0] == "random":
|
||||
return SearchResult(
|
||||
tracks=self.subsonic_api.get_random_songs_as_tracks()
|
||||
)
|
||||
if "any" in query:
|
||||
return self.subsonic_api.find_as_search_result(query.get("any")[0])
|
||||
|
|
|
@ -16,3 +16,6 @@ class SubidyPlaybackProvider(backend.PlaybackProvider):
|
|||
censored_url = self.subsonic_api.get_censored_song_stream_uri(song_id)
|
||||
logger.debug("Loading song from subsonic with url: '%s'" % censored_url)
|
||||
return self.subsonic_api.get_song_stream_uri(song_id)
|
||||
|
||||
def should_download(self, uri):
|
||||
return True
|
||||
|
|
|
@ -101,7 +101,7 @@ class SubsonicApi:
|
|||
exclude_songs=False,
|
||||
):
|
||||
try:
|
||||
response = self.connection.search2(
|
||||
response = self.connection.search3(
|
||||
query.encode("utf-8"),
|
||||
MAX_SEARCH_RESULTS if not exclude_artists else 0,
|
||||
0,
|
||||
|
@ -119,7 +119,7 @@ class SubsonicApi:
|
|||
% response.get("status")
|
||||
)
|
||||
return None
|
||||
return response.get("searchResult2")
|
||||
return response.get("searchResult3")
|
||||
|
||||
def find_as_search_result(
|
||||
self,
|
||||
|
@ -410,9 +410,30 @@ class SubsonicApi:
|
|||
return songs
|
||||
return []
|
||||
|
||||
def get_raw_album_list(self, ltype, size=MAX_LIST_RESULTS):
|
||||
def get_raw_random_song(self, size=MAX_LIST_RESULTS):
|
||||
try:
|
||||
response = self.connection.getAlbumList2(ltype=ltype, size=size)
|
||||
response = self.connection.getRandomSongs(size)
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Connecting to subsonic failed when loading ramdom song list."
|
||||
)
|
||||
return []
|
||||
if response.get("status") != RESPONSE_OK:
|
||||
logger.warning(
|
||||
"Got non-okay status code from subsonic: %s"
|
||||
% response.get("status")
|
||||
)
|
||||
return []
|
||||
songs = response.get("randomSongs").get("song")
|
||||
if songs is not None:
|
||||
return songs
|
||||
return []
|
||||
|
||||
def get_more_albums(self, ltype, size=MAX_LIST_RESULTS, offset=0):
|
||||
try:
|
||||
response = self.connection.getAlbumList2(
|
||||
ltype=ltype, size=size, offset=offset
|
||||
)
|
||||
except Exception:
|
||||
logger.warning(
|
||||
"Connecting to subsonic failed when loading album list."
|
||||
|
@ -429,6 +450,24 @@ class SubsonicApi:
|
|||
return albums
|
||||
return []
|
||||
|
||||
def get_raw_album_list(self, ltype, size=MAX_LIST_RESULTS):
|
||||
"""
|
||||
Subsonic servers don't offer any way to retrieve the total number
|
||||
of albums to get, and the spec states that the max number returned
|
||||
for `getAlbumList2` is 500. To get all the albums, we make a
|
||||
`getAlbumList2` request each time the response contains 500 albums. If
|
||||
it does not, we assume we have all the albums and return them.
|
||||
"""
|
||||
offset = 0
|
||||
total = []
|
||||
albums = self.get_more_albums(ltype, size, offset)
|
||||
total = albums
|
||||
while len(albums) == size:
|
||||
offset = offset + size
|
||||
albums = self.get_more_albums(ltype, size, offset)
|
||||
total = total + albums
|
||||
return total
|
||||
|
||||
def get_albums_as_refs(self, artist_id=None):
|
||||
albums = (
|
||||
self.get_raw_album_list("alphabeticalByName")
|
||||
|
@ -475,6 +514,16 @@ class SubsonicApi:
|
|||
for diritem in self.get_raw_dir(directory_id)
|
||||
]
|
||||
|
||||
def get_random_songs_as_refs(self):
|
||||
return [
|
||||
self.raw_song_to_ref(song) for song in self.get_raw_random_song(75)
|
||||
]
|
||||
|
||||
def get_random_songs_as_tracks(self):
|
||||
return [
|
||||
self.raw_song_to_track(song) for song in self.get_raw_random_song()
|
||||
]
|
||||
|
||||
def get_artists_as_artists(self):
|
||||
return [
|
||||
self.raw_artist_to_artist(artist)
|
||||
|
|
|
@ -8,6 +8,7 @@ DIRECTORY = "directory"
|
|||
VDIR = "vdir"
|
||||
PREFIX = "subidy"
|
||||
SEARCH = "search"
|
||||
RANDOM = "random"
|
||||
|
||||
regex = re.compile(r"(\w+?):(\w+?)(?::|$)(.+?)?$")
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
[metadata]
|
||||
name = Mopidy-Subidy
|
||||
version = 1.0.0
|
||||
version = 1.1.0
|
||||
url = https://github.com/Prior99/mopidy-subidy
|
||||
author = prior99
|
||||
author_email = fgnodtke@cronosx.de
|
||||
|
|
Loading…
Add table
Reference in a new issue