mirror of
https://github.com/gordielachance/plugin.audio.subsonic
synced 2025-02-19 21:20:53 +01:00
Split SubSonic/Plugin parts.
This commit is contained in:
parent
69b94cc6cc
commit
fe27001e90
131
addon.py
131
addon.py
@ -36,7 +36,7 @@ class Plugin(object):
|
|||||||
self.trans_format = addon.getSetting("trans_format")
|
self.trans_format = addon.getSetting("trans_format")
|
||||||
|
|
||||||
# Create connection
|
# Create connection
|
||||||
self.connection = libsonic_extra.Connection(
|
self.connection = libsonic_extra.SubsonicClient(
|
||||||
self.url, self.username, self.password)
|
self.url, self.username, self.password)
|
||||||
|
|
||||||
def build_url(self, query):
|
def build_url(self, query):
|
||||||
@ -48,115 +48,6 @@ class Plugin(object):
|
|||||||
|
|
||||||
return urlparse.urlunparse(parts)
|
return urlparse.urlunparse(parts)
|
||||||
|
|
||||||
def walk_genres(self):
|
|
||||||
"""
|
|
||||||
Request Subsonic's genres list and iterate each item.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getGenres()
|
|
||||||
|
|
||||||
for genre in response["genres"]["genre"]:
|
|
||||||
yield genre
|
|
||||||
|
|
||||||
def walk_artists(self):
|
|
||||||
"""
|
|
||||||
Request SubSonic's index and iterate each item.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getArtists()
|
|
||||||
|
|
||||||
for index in response["artists"]["index"]:
|
|
||||||
for artist in index["artist"]:
|
|
||||||
yield artist
|
|
||||||
|
|
||||||
def walk_album_list2_genre(self, genre):
|
|
||||||
"""
|
|
||||||
Request all albums for a given genre.
|
|
||||||
"""
|
|
||||||
|
|
||||||
offset = 0
|
|
||||||
|
|
||||||
while True:
|
|
||||||
response = self.connection.getAlbumList2(
|
|
||||||
ltype="byGenre", genre=genre, size=500, offset=offset)
|
|
||||||
|
|
||||||
if not response["albumList2"]["album"]:
|
|
||||||
break
|
|
||||||
|
|
||||||
for album in response["albumList2"]["album"]:
|
|
||||||
yield album
|
|
||||||
|
|
||||||
offset += 500
|
|
||||||
|
|
||||||
def walk_album(self, album_id):
|
|
||||||
"""
|
|
||||||
Request Album and iterate each song.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getAlbum(album_id)
|
|
||||||
|
|
||||||
for song in response["album"]["song"]:
|
|
||||||
yield song
|
|
||||||
|
|
||||||
def walk_playlists(self):
|
|
||||||
"""
|
|
||||||
Request SubSonic's playlists and iterate over each item.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getPlaylists()
|
|
||||||
|
|
||||||
for child in response["playlists"]["playlist"]:
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def walk_playlist(self, playlist_id):
|
|
||||||
"""
|
|
||||||
Request SubSonic's playlist items and iterate over each item.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getPlaylist(playlist_id)
|
|
||||||
|
|
||||||
for order, child in enumerate(response["playlist"]["entry"], start=1):
|
|
||||||
child["order"] = order
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def walk_directory(self, directory_id):
|
|
||||||
"""
|
|
||||||
Request a SubSonic music directory and iterate over each item.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getMusicDirectory(directory_id)
|
|
||||||
|
|
||||||
for child in response["directory"]["child"]:
|
|
||||||
if child.get("isDir"):
|
|
||||||
for child in self.walk_directory(child["id"]):
|
|
||||||
yield child
|
|
||||||
else:
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def walk_artist(self, artist_id):
|
|
||||||
"""
|
|
||||||
Request a SubSonic artist and iterate over each album.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getArtist(artist_id)
|
|
||||||
|
|
||||||
for child in response["artist"]["album"]:
|
|
||||||
yield child
|
|
||||||
|
|
||||||
def walk_random_songs(self, size, genre=None, from_year=None,
|
|
||||||
to_year=None):
|
|
||||||
"""
|
|
||||||
Request random songs by genre and/or year and iterate over each song.
|
|
||||||
"""
|
|
||||||
|
|
||||||
response = self.connection.getRandomSongs(
|
|
||||||
size=size, genre=genre, fromYear=from_year, toYear=to_year)
|
|
||||||
|
|
||||||
for song in response["randomSongs"]["song"]:
|
|
||||||
song["id"] = int(song["id"])
|
|
||||||
|
|
||||||
yield song
|
|
||||||
|
|
||||||
def route(self):
|
def route(self):
|
||||||
"""
|
"""
|
||||||
Map a Kodi request to certain action.
|
Map a Kodi request to certain action.
|
||||||
@ -260,7 +151,7 @@ class Plugin(object):
|
|||||||
Display playlists.
|
Display playlists.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for playlist in self.walk_playlists():
|
for playlist in self.connection.walk_playlists():
|
||||||
cover_art_url = self.connection.getCoverArtUrl(
|
cover_art_url = self.connection.getCoverArtUrl(
|
||||||
playlist["coverArt"])
|
playlist["coverArt"])
|
||||||
url = self.build_url({
|
url = self.build_url({
|
||||||
@ -279,7 +170,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
playlist_id = self.addon_args["playlist_id"][0]
|
playlist_id = self.addon_args["playlist_id"][0]
|
||||||
|
|
||||||
for track in self.walk_playlist(playlist_id):
|
for track in self.connection.walk_playlist(playlist_id):
|
||||||
self.add_track(track, show_artist=True)
|
self.add_track(track, show_artist=True)
|
||||||
|
|
||||||
xbmcplugin.setContent(self.addon_handle, "songs")
|
xbmcplugin.setContent(self.addon_handle, "songs")
|
||||||
@ -290,7 +181,7 @@ class Plugin(object):
|
|||||||
Display list of genres menu.
|
Display list of genres menu.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for genre in self.walk_genres():
|
for genre in self.connection.walk_genres():
|
||||||
url = self.build_url({
|
url = self.build_url({
|
||||||
"mode": "albums_by_genre_list",
|
"mode": "albums_by_genre_list",
|
||||||
"foldername": genre["value"].encode("utf-8")})
|
"foldername": genre["value"].encode("utf-8")})
|
||||||
@ -308,7 +199,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
genre = self.addon_args["foldername"][0].decode("utf-8")
|
genre = self.addon_args["foldername"][0].decode("utf-8")
|
||||||
|
|
||||||
for album in self.walk_album_list2_genre(genre):
|
for album in self.connection.walk_album_list_genre(genre):
|
||||||
self.add_album(album, show_artist=True)
|
self.add_album(album, show_artist=True)
|
||||||
|
|
||||||
xbmcplugin.setContent(self.addon_handle, "albums")
|
xbmcplugin.setContent(self.addon_handle, "albums")
|
||||||
@ -319,7 +210,7 @@ class Plugin(object):
|
|||||||
Display artist list
|
Display artist list
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for artist in self.walk_artists():
|
for artist in self.connection.walk_artists():
|
||||||
cover_art_url = self.connection.getCoverArtUrl(artist["id"])
|
cover_art_url = self.connection.getCoverArtUrl(artist["id"])
|
||||||
url = self.build_url({
|
url = self.build_url({
|
||||||
"mode": "album_list",
|
"mode": "album_list",
|
||||||
@ -342,7 +233,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
artist_id = self.addon_args["artist_id"][0]
|
artist_id = self.addon_args["artist_id"][0]
|
||||||
|
|
||||||
for album in self.walk_artist(artist_id):
|
for album in self.connection.walk_artist(artist_id):
|
||||||
self.add_album(album)
|
self.add_album(album)
|
||||||
|
|
||||||
xbmcplugin.setContent(self.addon_handle, "albums")
|
xbmcplugin.setContent(self.addon_handle, "albums")
|
||||||
@ -355,7 +246,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
album_id = self.addon_args["album_id"][0]
|
album_id = self.addon_args["album_id"][0]
|
||||||
|
|
||||||
for track in self.walk_album(album_id):
|
for track in self.connection.walk_album(album_id):
|
||||||
self.add_track(track)
|
self.add_track(track)
|
||||||
|
|
||||||
xbmcplugin.setContent(self.addon_handle, "songs")
|
xbmcplugin.setContent(self.addon_handle, "songs")
|
||||||
@ -384,7 +275,7 @@ class Plugin(object):
|
|||||||
Display random genre list.
|
Display random genre list.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
for genre in self.walk_genres():
|
for genre in self.connection.walk_genres():
|
||||||
url = self.build_url({
|
url = self.build_url({
|
||||||
"mode": "random_by_genre_track_list",
|
"mode": "random_by_genre_track_list",
|
||||||
"foldername": genre["value"].encode("utf-8")})
|
"foldername": genre["value"].encode("utf-8")})
|
||||||
@ -402,7 +293,7 @@ class Plugin(object):
|
|||||||
|
|
||||||
genre = self.addon_args["foldername"][0].decode("utf-8")
|
genre = self.addon_args["foldername"][0].decode("utf-8")
|
||||||
|
|
||||||
for track in self.walk_random_songs(
|
for track in self.connection.walk_random_songs(
|
||||||
size=self.random_count, genre=genre):
|
size=self.random_count, genre=genre):
|
||||||
self.add_track(track, show_artist=True)
|
self.add_track(track, show_artist=True)
|
||||||
|
|
||||||
@ -419,7 +310,7 @@ class Plugin(object):
|
|||||||
to_year = xbmcgui.Dialog().input(
|
to_year = xbmcgui.Dialog().input(
|
||||||
"To year", type=xbmcgui.INPUT_NUMERIC)
|
"To year", type=xbmcgui.INPUT_NUMERIC)
|
||||||
|
|
||||||
for track in self.walk_random_songs(
|
for track in self.connection.walk_random_songs(
|
||||||
size=self.random_count, from_year=from_year, to_year=to_year):
|
size=self.random_count, from_year=from_year, to_year=to_year):
|
||||||
self.add_track(track, show_artist=True)
|
self.add_track(track, show_artist=True)
|
||||||
|
|
||||||
|
@ -3,17 +3,6 @@ import urlparse
|
|||||||
import libsonic
|
import libsonic
|
||||||
|
|
||||||
|
|
||||||
def force_dict(value):
|
|
||||||
"""
|
|
||||||
Coerce the input value to a dict.
|
|
||||||
"""
|
|
||||||
|
|
||||||
if type(value) == dict:
|
|
||||||
return value
|
|
||||||
else:
|
|
||||||
return {}
|
|
||||||
|
|
||||||
|
|
||||||
def force_list(value):
|
def force_list(value):
|
||||||
"""
|
"""
|
||||||
Coerce the input value to a list.
|
Coerce the input value to a list.
|
||||||
@ -34,22 +23,27 @@ def force_list(value):
|
|||||||
return [value]
|
return [value]
|
||||||
|
|
||||||
|
|
||||||
class Connection(libsonic.Connection):
|
class SubsonicClient(libsonic.Connection):
|
||||||
"""
|
"""
|
||||||
Extend `libsonic.Connection` with new features and fix a few issues.
|
Extend `libsonic.Connection` with new features and fix a few issues.
|
||||||
|
|
||||||
- Add library name property.
|
|
||||||
- Parse URL for host and port for constructor.
|
- Parse URL for host and port for constructor.
|
||||||
- Make sure API results are of of uniform type.
|
- Make sure API results are of of uniform type.
|
||||||
|
- Provide methods to intercept URL of binary requests.
|
||||||
:param str name: Name of connection.
|
- Add order property to playlist items.
|
||||||
:param str url: Full URL (including protocol) of SubSonic server.
|
- Add conventient `walk_*' methods to iterate over the API responses.
|
||||||
:param str username: Username of server.
|
|
||||||
:param str password: Password of server.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, url, username, password):
|
def __init__(self, url, username, password):
|
||||||
self._intercept_url = False
|
"""
|
||||||
|
Construct a new SubsonicClient.
|
||||||
|
|
||||||
|
:param str url: Full URL (including scheme) of the SubSonic server.
|
||||||
|
:param str username: Username of the server.
|
||||||
|
:param str password: Password of the server.
|
||||||
|
"""
|
||||||
|
|
||||||
|
self.intercept_url = False
|
||||||
|
|
||||||
# Parse SubSonic URL
|
# Parse SubSonic URL
|
||||||
parts = urlparse.urlparse(url)
|
parts = urlparse.urlparse(url)
|
||||||
@ -69,10 +63,12 @@ class Connection(libsonic.Connection):
|
|||||||
port = parts.port or {"http": 80, "https": 443}[scheme]
|
port = parts.port or {"http": 80, "https": 443}[scheme]
|
||||||
|
|
||||||
# Invoke original constructor
|
# Invoke original constructor
|
||||||
super(Connection, self).__init__(host, username, password, port=port)
|
super(SubsonicClient, self).__init__(
|
||||||
|
host, username, password, port=port)
|
||||||
|
|
||||||
def getArtists(self, *args, **kwargs):
|
def getIndexes(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Improve the getIndexes method. Ensures IDs are integers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _artists_iterator(artists):
|
def _artists_iterator(artists):
|
||||||
@ -85,15 +81,33 @@ class Connection(libsonic.Connection):
|
|||||||
index["artist"] = list(_artists_iterator(index.get("artist")))
|
index["artist"] = list(_artists_iterator(index.get("artist")))
|
||||||
yield index
|
yield index
|
||||||
|
|
||||||
response = super(Connection, self).getArtists(*args, **kwargs)
|
def _children_iterator(children):
|
||||||
response["artists"] = response.get("artists", {})
|
for child in force_list(children):
|
||||||
response["artists"]["index"] = list(
|
child["id"] = int(child["id"])
|
||||||
_index_iterator(response["artists"].get("index")))
|
|
||||||
|
if "parent" in child:
|
||||||
|
child["parent"] = int(child["parent"])
|
||||||
|
if "coverArt" in child:
|
||||||
|
child["coverArt"] = int(child["coverArt"])
|
||||||
|
if "artistId" in child:
|
||||||
|
child["artistId"] = int(child["artistId"])
|
||||||
|
if "albumId" in child:
|
||||||
|
child["albumId"] = int(child["albumId"])
|
||||||
|
|
||||||
|
yield child
|
||||||
|
|
||||||
|
response = super(SubsonicClient, self).getIndexes(*args, **kwargs)
|
||||||
|
response["indexes"] = response.get("indexes", {})
|
||||||
|
response["indexes"]["index"] = list(
|
||||||
|
_index_iterator(response["indexes"].get("index")))
|
||||||
|
response["indexes"]["child"] = list(
|
||||||
|
_children_iterator(response["indexes"].get("child")))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def getPlaylists(self, *args, **kwargs):
|
def getPlaylists(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Improve the getPlaylists method. Ensures IDs are integers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _playlists_iterator(playlists):
|
def _playlists_iterator(playlists):
|
||||||
@ -101,7 +115,7 @@ class Connection(libsonic.Connection):
|
|||||||
playlist["id"] = int(playlist["id"])
|
playlist["id"] = int(playlist["id"])
|
||||||
yield playlist
|
yield playlist
|
||||||
|
|
||||||
response = super(Connection, self).getPlaylists(*args, **kwargs)
|
response = super(SubsonicClient, self).getPlaylists(*args, **kwargs)
|
||||||
response["playlists"]["playlist"] = list(
|
response["playlists"]["playlist"] = list(
|
||||||
_playlists_iterator(response["playlists"].get("playlist")))
|
_playlists_iterator(response["playlists"].get("playlist")))
|
||||||
|
|
||||||
@ -109,66 +123,67 @@ class Connection(libsonic.Connection):
|
|||||||
|
|
||||||
def getPlaylist(self, *args, **kwargs):
|
def getPlaylist(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Improve the getPlaylist method. Ensures IDs are integers and add an
|
||||||
|
order property to each entry.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _entries_iterator(entries):
|
def _entries_iterator(entries):
|
||||||
for entry in force_list(entries):
|
for order, entry in enumerate(force_list(entries), start=1):
|
||||||
entry["id"] = int(entry["id"])
|
entry["id"] = int(entry["id"])
|
||||||
|
entry["order"] = order
|
||||||
yield entry
|
yield entry
|
||||||
|
|
||||||
response = super(Connection, self).getPlaylist(*args, **kwargs)
|
response = super(SubsonicClient, self).getPlaylist(*args, **kwargs)
|
||||||
response["playlist"]["entry"] = list(
|
response["playlist"]["entry"] = list(
|
||||||
_entries_iterator(response["playlist"].get("entry")))
|
_entries_iterator(response["playlist"].get("entry")))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def getArtists(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Improve the getArtists method. Ensures IDs are integers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _artists_iterator(artists):
|
||||||
|
for artist in force_list(artists):
|
||||||
|
artist["id"] = int(artist["id"])
|
||||||
|
yield artist
|
||||||
|
|
||||||
|
def _index_iterator(index):
|
||||||
|
for index in force_list(index):
|
||||||
|
index["artist"] = list(_artists_iterator(index.get("artist")))
|
||||||
|
yield index
|
||||||
|
|
||||||
|
response = super(SubsonicClient, self).getArtists(*args, **kwargs)
|
||||||
|
response["artists"] = response.get("artists", {})
|
||||||
|
response["artists"]["index"] = list(
|
||||||
|
_index_iterator(response["artists"].get("index")))
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
def getArtist(self, *args, **kwargs):
|
def getArtist(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Improve the getArtist method. Ensures IDs are integers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _albums_iterator(albums):
|
def _albums_iterator(albums):
|
||||||
for album in force_list(albums):
|
for album in force_list(albums):
|
||||||
album["id"] = int(album["id"])
|
album["id"] = int(album["id"])
|
||||||
|
|
||||||
|
if "artistId" in album:
|
||||||
|
album["artistId"] = int(album["artistId"])
|
||||||
|
|
||||||
yield album
|
yield album
|
||||||
|
|
||||||
response = super(Connection, self).getArtist(*args, **kwargs)
|
response = super(SubsonicClient, self).getArtist(*args, **kwargs)
|
||||||
response["artist"]["album"] = list(
|
response["artist"]["album"] = list(
|
||||||
_albums_iterator(response["artist"].get("album")))
|
_albums_iterator(response["artist"].get("album")))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
def getAlbum(self, *args, **kwargs):
|
|
||||||
""
|
|
||||||
""
|
|
||||||
|
|
||||||
def _songs_iterator(songs):
|
|
||||||
for song in force_list(songs):
|
|
||||||
song["id"] = int(song["id"])
|
|
||||||
yield song
|
|
||||||
|
|
||||||
response = super(Connection, self).getAlbum(*args, **kwargs)
|
|
||||||
response["album"]["song"] = list(
|
|
||||||
_songs_iterator(response["album"].get("song")))
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def getAlbumList2(self, *args, **kwargs):
|
|
||||||
""
|
|
||||||
""
|
|
||||||
|
|
||||||
def _album_iterator(albums):
|
|
||||||
for album in force_list(albums):
|
|
||||||
album["id"] = int(album["id"])
|
|
||||||
yield album
|
|
||||||
|
|
||||||
response = super(Connection, self).getAlbumList2(*args, **kwargs)
|
|
||||||
response["albumList2"]["album"] = list(
|
|
||||||
_album_iterator(response["albumList2"].get("album")))
|
|
||||||
|
|
||||||
return response
|
|
||||||
|
|
||||||
def getMusicDirectory(self, *args, **kwargs):
|
def getMusicDirectory(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
Improve the getMusicDirectory method. Ensures IDs are integers.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def _children_iterator(children):
|
def _children_iterator(children):
|
||||||
@ -186,20 +201,53 @@ class Connection(libsonic.Connection):
|
|||||||
|
|
||||||
yield child
|
yield child
|
||||||
|
|
||||||
response = super(Connection, self).getMusicDirectory(*args, **kwargs)
|
response = super(SubsonicClient, self).getMusicDirectory(
|
||||||
|
*args, **kwargs)
|
||||||
response["directory"]["child"] = list(
|
response["directory"]["child"] = list(
|
||||||
_children_iterator(response["directory"].get("child")))
|
_children_iterator(response["directory"].get("child")))
|
||||||
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
def getAlbum(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Improve the getAlbum method. Ensures the IDs are real integers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _songs_iterator(songs):
|
||||||
|
for song in force_list(songs):
|
||||||
|
song["id"] = int(song["id"])
|
||||||
|
yield song
|
||||||
|
|
||||||
|
response = super(SubsonicClient, self).getAlbum(*args, **kwargs)
|
||||||
|
response["album"]["song"] = list(
|
||||||
|
_songs_iterator(response["album"].get("song")))
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
|
def getAlbumList2(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
Improve the getAlbumList2 method. Ensures the IDs are real integers.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def _album_iterator(albums):
|
||||||
|
for album in force_list(albums):
|
||||||
|
album["id"] = int(album["id"])
|
||||||
|
yield album
|
||||||
|
|
||||||
|
response = super(SubsonicClient, self).getAlbumList2(*args, **kwargs)
|
||||||
|
response["albumList2"]["album"] = list(
|
||||||
|
_album_iterator(response["albumList2"].get("album")))
|
||||||
|
|
||||||
|
return response
|
||||||
|
|
||||||
def getCoverArtUrl(self, *args, **kwargs):
|
def getCoverArtUrl(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Return an URL to the cover art.
|
Return an URL to the cover art.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._intercept_url = True
|
self.intercept_url = True
|
||||||
url = self.getCoverArt(*args, **kwargs)
|
url = self.getCoverArt(*args, **kwargs)
|
||||||
self._intercept_url = False
|
self.intercept_url = False
|
||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
@ -208,18 +256,21 @@ class Connection(libsonic.Connection):
|
|||||||
Return an URL to the file to stream.
|
Return an URL to the file to stream.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._intercept_url = True
|
self.intercept_url = True
|
||||||
url = self.stream(*args, **kwargs)
|
url = self.stream(*args, **kwargs)
|
||||||
self._intercept_url = False
|
self.intercept_url = False
|
||||||
|
|
||||||
return url
|
return url
|
||||||
|
|
||||||
def _doBinReq(self, *args, **kwargs):
|
def _doBinReq(self, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
Intercept request URL.
|
Intercept request URL to provide the URL of the item that is requested.
|
||||||
|
|
||||||
|
If the URL is intercepted, the request is not executed. A username and
|
||||||
|
password is added to provide direct access to the stream.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if self._intercept_url:
|
if self.intercept_url:
|
||||||
parts = list(urlparse.urlparse(
|
parts = list(urlparse.urlparse(
|
||||||
args[0].get_full_url() + "?" + args[0].data))
|
args[0].get_full_url() + "?" + args[0].data))
|
||||||
parts[4] = dict(urlparse.parse_qsl(parts[4]))
|
parts[4] = dict(urlparse.parse_qsl(parts[4]))
|
||||||
@ -228,4 +279,131 @@ class Connection(libsonic.Connection):
|
|||||||
|
|
||||||
return urlparse.urlunparse(parts)
|
return urlparse.urlunparse(parts)
|
||||||
else:
|
else:
|
||||||
return super(Connection, self)._doBinReq(*args, **kwargs)
|
return super(SubsonicClient, self)._doBinReq(*args, **kwargs)
|
||||||
|
|
||||||
|
def walk_index(self):
|
||||||
|
"""
|
||||||
|
Request SubSonic's index and iterate each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getIndexes()
|
||||||
|
|
||||||
|
for index in response["indexes"]["index"]:
|
||||||
|
for index in index["artist"]:
|
||||||
|
for item in self.walk_directory(index["id"]):
|
||||||
|
yield item
|
||||||
|
|
||||||
|
for child in response["indexes"]["child"]:
|
||||||
|
if child.get("isDir"):
|
||||||
|
for child in self.walk_directory(child["id"]):
|
||||||
|
yield child
|
||||||
|
else:
|
||||||
|
yield child
|
||||||
|
|
||||||
|
def walk_playlists(self):
|
||||||
|
"""
|
||||||
|
Request SubSonic's playlists and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getPlaylists()
|
||||||
|
|
||||||
|
for child in response["playlists"]["playlist"]:
|
||||||
|
yield child
|
||||||
|
|
||||||
|
def walk_playlist(self, playlist_id):
|
||||||
|
"""
|
||||||
|
Request SubSonic's playlist items and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getPlaylist(playlist_id)
|
||||||
|
|
||||||
|
for order, child in response["playlist"]["entry"]:
|
||||||
|
yield child
|
||||||
|
|
||||||
|
def walk_directory(self, directory_id):
|
||||||
|
"""
|
||||||
|
Request a SubSonic music directory and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getMusicDirectory(directory_id)
|
||||||
|
|
||||||
|
for child in response["directory"]["child"]:
|
||||||
|
if child.get("isDir"):
|
||||||
|
for child in self.walk_directory(child["id"]):
|
||||||
|
yield child
|
||||||
|
else:
|
||||||
|
yield child
|
||||||
|
|
||||||
|
def walk_artist(self, artist_id):
|
||||||
|
"""
|
||||||
|
Request a SubSonic artist and iterate over each album.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getArtist(artist_id)
|
||||||
|
|
||||||
|
for child in response["artist"]["album"]:
|
||||||
|
yield child
|
||||||
|
|
||||||
|
def walk_artists(self):
|
||||||
|
"""
|
||||||
|
Request all artists and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getArtists()
|
||||||
|
|
||||||
|
for index in response["artists"]["index"]:
|
||||||
|
for artist in index["artist"]:
|
||||||
|
yield artist
|
||||||
|
|
||||||
|
def walk_genres(self):
|
||||||
|
"""
|
||||||
|
Request all genres and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getGenres()
|
||||||
|
|
||||||
|
for genre in response["genres"]["genre"]:
|
||||||
|
yield genre
|
||||||
|
|
||||||
|
def walk_album_list_genre(self, genre):
|
||||||
|
"""
|
||||||
|
Request all albums for a given genre and iterate over each album.
|
||||||
|
"""
|
||||||
|
|
||||||
|
offset = 0
|
||||||
|
|
||||||
|
while True:
|
||||||
|
response = self.getAlbumList2(
|
||||||
|
ltype="byGenre", genre=genre, size=500, offset=offset)
|
||||||
|
|
||||||
|
if not response["albumList2"]["album"]:
|
||||||
|
break
|
||||||
|
|
||||||
|
for album in response["albumList2"]["album"]:
|
||||||
|
yield album
|
||||||
|
|
||||||
|
offset += 500
|
||||||
|
|
||||||
|
def walk_album(self, album_id):
|
||||||
|
"""
|
||||||
|
Request an alum and iterate over each item.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getAlbum(album_id)
|
||||||
|
|
||||||
|
for song in response["album"]["song"]:
|
||||||
|
yield song
|
||||||
|
|
||||||
|
def walk_random_songs(self, size, genre=None, from_year=None,
|
||||||
|
to_year=None):
|
||||||
|
"""
|
||||||
|
Request random songs by genre and/or year and iterate over each song.
|
||||||
|
"""
|
||||||
|
|
||||||
|
response = self.getRandomSongs(
|
||||||
|
size=size, genre=genre, fromYear=from_year, toYear=to_year)
|
||||||
|
|
||||||
|
for song in response["randomSongs"]["song"]:
|
||||||
|
song["id"] = int(song["id"])
|
||||||
|
|
||||||
|
yield song
|
||||||
|
Loading…
x
Reference in New Issue
Block a user