Skip to content

Commit

Permalink
Merge pull request #30 from kutu-dev/feat/stream
Browse files Browse the repository at this point in the history
Feat/stream
  • Loading branch information
kutu-dev authored Sep 29, 2023
2 parents 1c4ce0e + 3835668 commit 83c2936
Show file tree
Hide file tree
Showing 29 changed files with 1,183 additions and 111 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-python@v4
with:
python-version: "3.11"
python-version: "3.11.5"
- uses: Gr1N/setup-poetry@v8
- uses: actions/cache@v3
with:
Expand Down
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ share/python-wheels/
.installed.cfg
*.egg
MANIFEST
poetry.lock

# Code Editors
.vscode
Expand Down
804 changes: 804 additions & 0 deletions poetry.lock

Large diffs are not rendered by default.

30 changes: 24 additions & 6 deletions src/knuckles/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,9 +101,7 @@ def generate_params(self, extra_params: dict[str, Any] = {}) -> dict[str, Any]:

return {**params, "t": token, "s": salt}

def request(
self, endpoint: str, extra_params: dict[str, Any] = {}
) -> dict[str, Any]:
def raw_request(self, endpoint: str, extra_params: dict[str, Any]) -> Response:
"""Make a request to the Subsonic API.
:param endpoint: The endpoint where the request should be made,
Expand All @@ -112,18 +110,38 @@ def request(
:type endpoint: str
:param extra_params: The extra parameters required by the endpoint,
defaults to {}.
:type extra_params: dict[str, Any], optional
:raises code_error: Raises an exception with the format CodeErrorXX or
UnknownCodeError if the request fails.
:return: The JSON data inside the "subsonic-response" object.
:return: The Response object returned by the request.
:rtype: dict[str, Any]
"""

response: Response = requests.get(
return requests.get(
url=f"{self.url}/rest/{endpoint}",
params=self.generate_params(extra_params),
)

def json_request(
self, endpoint: str, extra_params: dict[str, Any] = {}
) -> dict[str, Any]:
"""Make a request to the Subsonic API and returns a JSON response.
Don't use with binary data endpoints.
:param endpoint: The endpoint where the request should be made,
only specifies the route name, without slashes.
E.g. "ping", "getLicense", etc.
:type endpoint: str
:param extra_params: The extra parameters required by the endpoint,
defaults to {}.
:type extra_params: dict[str, Any], optional
:raises code_error: Raises an exception with the format CodeErrorXX or
UnknownCodeError if the request fails.
:return: The JSON data inside the "subsonic-response" object.
:rtype: dict[str, Any]
"""

response = self.raw_request(endpoint, extra_params)

json_response: dict[str, Any] = response.json()["subsonic-response"]

if json_response["status"] == "failed":
Expand Down
11 changes: 5 additions & 6 deletions src/knuckles/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def get_bookmarks(self) -> list[Bookmark]:
:rtype: list[Bookmark]
"""

response = self.api.request("getBookmarks")["bookmarks"]["bookmark"]
response = self.api.json_request("getBookmarks")["bookmarks"]["bookmark"]

return [Bookmark(self.subsonic, **bookmark) for bookmark in response]

Expand Down Expand Up @@ -62,7 +62,7 @@ def create_bookmark(
:rtype: Bookmark
"""

self.api.request(
self.api.json_request(
"createBookmark", {"id": id, "position": position, "comment": comment}
)

Expand Down Expand Up @@ -97,7 +97,7 @@ def delete_bookmark(self, id: str) -> "Subsonic":
:rtype: Subsonic
"""

self.api.request("deleteBookmark", {"id": id})
self.api.json_request("deleteBookmark", {"id": id})

return self.subsonic

Expand All @@ -108,7 +108,7 @@ def get_play_queue(self) -> PlayQueue:
:rtype: PlayQueue
"""

response = self.api.request("getPlayQueue")["playQueue"]
response = self.api.json_request("getPlayQueue")["playQueue"]

return PlayQueue(self.subsonic, **response)

Expand All @@ -132,12 +132,11 @@ def save_play_queue(
:rtype: PlayQueue
"""

self.api.request(
self.api.json_request(
"savePlayQueue",
{"id": song_ids, "current": current_song_id, "position": position},
)

# TODO This approach is expensive, a better one is preferred
# Fake the song structure given by in the API.
songs = []
for song_id in song_ids:
Expand Down
24 changes: 13 additions & 11 deletions src/knuckles/browsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,9 @@ def get_music_folders(self) -> list[MusicFolder]:
:rtype: list[MusicFolder]
"""

response = self.api.request("getMusicFolders")["musicFolders"]["musicFolder"]
response = self.api.json_request("getMusicFolders")["musicFolders"][
"musicFolder"
]

return [MusicFolder(self.subsonic, **music_folder) for music_folder in response]

Expand All @@ -39,7 +41,7 @@ def get_genres(self) -> list[Genre]:
:rtype: list[Genre]
"""

response = self.api.request("getGenres")["genres"]["genre"]
response = self.api.json_request("getGenres")["genres"]["genre"]

return [Genre(self.subsonic, **genre) for genre in response]

Expand All @@ -49,7 +51,7 @@ def get_genre(self, name: str) -> Genre | None:
:param name: The name of the genre to get.
:type name: str
:return: A genre object that correspond with the given name
or None if if no genre found.
or None if is no genre found.
:rtype: Genre | None
"""

Expand All @@ -71,9 +73,9 @@ def get_artists(self, music_folder_id: str | None = None) -> list[Artist]:
:rtype: list[Artist]
"""

response = self.api.request("getArtists", {"musicFolderId": music_folder_id})[
"artists"
]["index"]
response = self.api.json_request(
"getArtists", {"musicFolderId": music_folder_id}
)["artists"]["index"]

artists: list[Artist] = []

Expand All @@ -94,7 +96,7 @@ def get_artist(self, id: str) -> Artist:
:rtype: Artist
"""

response = self.api.request("getArtist", {"id": id})["artist"]
response = self.api.json_request("getArtist", {"id": id})["artist"]

return Artist(self.subsonic, **response)

Expand All @@ -108,7 +110,7 @@ def get_album(self, id: str) -> Album:
:rtype: Album
"""

response = self.api.request("getAlbum", {"id": id})["album"]
response = self.api.json_request("getAlbum", {"id": id})["album"]

return Album(self.subsonic, **response)

Expand All @@ -121,7 +123,7 @@ def get_album_info(self, id: str) -> AlbumInfo:
:rtype: AlbumInfo
"""

response = self.api.request("getAlbumInfo2", {"id": id})["albumInfo"]
response = self.api.json_request("getAlbumInfo2", {"id": id})["albumInfo"]

return AlbumInfo(self.subsonic, id, **response)

Expand All @@ -135,14 +137,14 @@ def get_song(self, id: str) -> Song:
:rtype: Song
"""

response = self.api.request("getSong", {"id": id})["song"]
response = self.api.json_request("getSong", {"id": id})["song"]

return Song(self.subsonic, **response)

def get_artist_info(
self, id: str, count: int | None = None, include_not_present: bool | None = None
) -> ArtistInfo:
response = self.api.request(
response = self.api.json_request(
"getArtistInfo2",
{"id": id, "count": count, "includeNotPresent": include_not_present},
)["artistInfo2"]
Expand Down
4 changes: 2 additions & 2 deletions src/knuckles/chat.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def add_chat_message(self, message: str) -> "Subsonic":
:rtype: Self
"""

self.api.request("addChatMessage", {"message": message})
self.api.json_request("addChatMessage", {"message": message})

return self.subsonic

Expand All @@ -37,7 +37,7 @@ def get_chat_messages(self) -> list[ChatMessage]:
:rtype: list[ChatMessage]
"""

response: list[dict[str, Any]] = self.api.request("getChatMessages")[
response: list[dict[str, Any]] = self.api.json_request("getChatMessages")[
"chatMessages"
]["chatMessage"]

Expand Down
8 changes: 4 additions & 4 deletions src/knuckles/internet_radio.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def get_internet_radio_stations(
:rtype: list[InternetRadioStation]
"""

response = self.api.request("getInternetRadioStations")[
response = self.api.json_request("getInternetRadioStations")[
"internetRadioStations"
]["internetRadioStation"]

Expand Down Expand Up @@ -67,7 +67,7 @@ def create_internet_radio_station(
:rtype: Subsonic
"""

self.api.request(
self.api.json_request(
"createInternetRadioStation",
{"streamUrl": stream_url, "name": name, "homepageUrl": homepage_url},
)
Expand All @@ -92,7 +92,7 @@ def update_internet_radio_station(
:rtype: Subsonic
"""

self.api.request(
self.api.json_request(
"updateInternetRadioStation",
{
"id": id,
Expand All @@ -113,6 +113,6 @@ def delete_internet_radio_station(self, id: str) -> "Subsonic":
:rtype: Subsonic
"""

self.api.request("deleteInternetRadioStation", {"id": id})
self.api.json_request("deleteInternetRadioStation", {"id": id})

return self.subsonic
22 changes: 11 additions & 11 deletions src/knuckles/jukebox.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ def get(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "get"})[
response = self.api.json_request("jukeboxControl", {"action": "get"})[
"jukeboxPlaylist"
]

Expand All @@ -40,7 +40,7 @@ def status(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "status"})[
response = self.api.json_request("jukeboxControl", {"action": "status"})[
"jukeboxStatus"
]

Expand All @@ -55,7 +55,7 @@ def set(self, id: str) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "set", "id": id})[
response = self.api.json_request("jukeboxControl", {"action": "set", "id": id})[
"jukeboxStatus"
]

Expand All @@ -70,7 +70,7 @@ def start(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "start"})[
response = self.api.json_request("jukeboxControl", {"action": "start"})[
"jukeboxStatus"
]

Expand All @@ -84,7 +84,7 @@ def stop(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "stop"})[
response = self.api.json_request("jukeboxControl", {"action": "stop"})[
"jukeboxStatus"
]

Expand All @@ -102,7 +102,7 @@ def skip(self, index: int, offset: float = 0) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request(
response = self.api.json_request(
"jukeboxControl", {"action": "skip", "index": index, "offset": offset}
)["jukeboxStatus"]

Expand All @@ -118,7 +118,7 @@ def add(self, id: str) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "add", "id": id})[
response = self.api.json_request("jukeboxControl", {"action": "add", "id": id})[
"jukeboxStatus"
]

Expand All @@ -132,7 +132,7 @@ def clear(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "clear"})[
response = self.api.json_request("jukeboxControl", {"action": "clear"})[
"jukeboxStatus"
]

Expand All @@ -148,7 +148,7 @@ def remove(self, index: int) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request(
response = self.api.json_request(
"jukeboxControl", {"action": "remove", "index": index}
)["jukeboxStatus"]

Expand All @@ -162,7 +162,7 @@ def shuffle(self) -> Jukebox:
:rtype: Jukebox
"""

response = self.api.request("jukeboxControl", {"action": "shuffle"})[
response = self.api.json_request("jukeboxControl", {"action": "shuffle"})[
"jukeboxStatus"
]

Expand All @@ -182,7 +182,7 @@ def set_gain(self, gain: float) -> Jukebox:
if not 1 > gain > 0:
raise ValueError("The gain should be between 0 and 1 (inclusive)")

response = self.api.request(
response = self.api.json_request(
"jukeboxControl", {"action": "setGain", "gain": gain}
)["jukeboxStatus"]

Expand Down
Loading

0 comments on commit 83c2936

Please sign in to comment.