Compare commits

...

20 commits

Author SHA1 Message Date
ebb2dab571
add pkbuild 2025-02-05 18:55:01 +01:00
62429f22bd Update mopidy_subidy/playback.py 2025-02-04 16:41:22 +00:00
vincent
4bc641e95a resolv conflict 2021-01-14 17:49:49 +01:00
vincent
5ce65f0a08 change argument 2021-01-14 17:31:05 +01:00
vincent
b5e0de1e4d correct warning 2020-11-24 14:53:17 +01:00
Frederick
e8493923c1 Update version 2020-11-19 09:14:44 +01:00
Frederick
32f74f28e9 Merge branch 'master' of https://github.com/brynedwards/mopidy-subidy 2020-11-19 09:08:10 +01:00
Frederick
cf588481c6 Add note about maintenance 2020-11-19 09:06:50 +01:00
vincent
876bec6711 correct conflict 2020-11-15 10:21:08 +01:00
vincent
7064dd9e50 reformating 2020-11-03 20:38:01 +01:00
vincent
81a62cdca4 add random mode in browse and search 2020-11-03 20:36:28 +01:00
vincent
1bc9e35d83 add exact to search artist 2020-11-02 23:12:39 +01:00
vincent
6857653cdb modifyng search_by_artist_and_album 2020-11-02 21:13:27 +01:00
vincent
511a101c2c modify artist search to retur all artist track 2020-11-02 19:54:41 +01:00
vincent
f7090127fe black reformating 2020-11-02 16:34:21 +01:00
vincent
31023236ae correct formatting 2020-11-02 16:25:57 +01:00
vincent
eff25672d9 improve research by artist 2020-11-02 16:08:50 +01:00
Bryn Edwards
584209c134 comment 2020-03-25 08:03:46 +00:00
Bryn Edwards
ee3e36408d formatting 2020-03-14 18:57:55 +00:00
Bryn Edwards
713845090c Make repeated getAlbumList2 requests with offset to get all albums 2020-03-14 18:43:53 +00:00
7 changed files with 137 additions and 18 deletions

35
PKGBUILD Normal file
View 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"
}

View file

@ -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>`_.

View file

@ -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")
)
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"))
)
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"))
)
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,9 +199,12 @@ 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])
return SearchResult(artists=self.subsonic_api.get_artists_as_artists())

View file

@ -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

View file

@ -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)

View file

@ -8,6 +8,7 @@ DIRECTORY = "directory"
VDIR = "vdir"
PREFIX = "subidy"
SEARCH = "search"
RANDOM = "random"
regex = re.compile(r"(\w+?):(\w+?)(?::|$)(.+?)?$")

View file

@ -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