Skip to content

Commit

Permalink
Implement play queue methods and model
Browse files Browse the repository at this point in the history
  • Loading branch information
kutu-dev committed Aug 10, 2023
1 parent a17035e commit bfd6cef
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 7 deletions.
29 changes: 27 additions & 2 deletions src/knuckles/bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from .api import Api
from .models.bookmark import Bookmark
from .models.play_queue import PlayQueue

if TYPE_CHECKING:
from .subsonic import Subsonic
Expand Down Expand Up @@ -65,15 +66,15 @@ def create_bookmark(
"createBookmark", {"id": id, "position": position, "comment": comment}
)

# Fake the structure given by the songs in the API.
# Fake the song structure given by in the API.
return Bookmark(self.subsonic, {"id": id}, position=position, comment=comment)

def update_bookmark(
self, id: str, position: int, comment: str | None = None
) -> Bookmark:
"""Method that internally calls the create_bookmark method
as creating and updating a bookmark uses the same endpoint. Useful for having
more self descriptive code.
more self-descriptive code.
:param id: The ID of the song of the bookmark.
:type id: str
Expand All @@ -99,3 +100,27 @@ def delete_bookmark(self, id: str) -> "Subsonic":
self.api.request("deleteBookmark", {"id": id})

return self.subsonic

def get_play_queue(self) -> PlayQueue:
response = self.api.request("getPlayQueue")["playQueue"]

return PlayQueue(self.subsonic, **response)

def save_play_queue(
self,
song_ids: list[str],
current_song_id: str | None = None,
position: int | None = None,
) -> PlayQueue:
self.api.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:
songs.append({"id": song_id})

return PlayQueue(self.subsonic, songs, current_song_id, position)
58 changes: 58 additions & 0 deletions src/knuckles/models/play_queue.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
from typing import TYPE_CHECKING, Any, Self

from dateutil import parser

from .song import Song
from .user import User

if TYPE_CHECKING:
from ..subsonic import Subsonic


class PlayQueue:
"""Representation of all the data related to a play queue in Subsonic."""

def __init__(
self,
subsonic: "Subsonic",
entry: list[dict[str, Any]],
current: str | None = None,
position: int | None = None,
username: str | None = None,
changed: str | None = None,
changedBy: str | None = None,
) -> None:
self.__subsonic = subsonic
self.current = Song(self.__subsonic, current) if current else None
self.position = position
self.user = User(username) if username else None
self.changed = parser.parse(changed) if changed else None
self.changed_by = changedBy
self.songs = (
[Song(self.__subsonic, **song) for song in entry] if entry else None
)

def generate(self) -> "PlayQueue":
"""Return a new play queue with all the data updated from the API,
using the endpoint that return the most information possible.
Useful for making copies with updated data or updating the object itself
with immutability, e.g., foo = foo.generate().
:return: A new share object with all the data updated.
:rtype: PlayQueue
"""

get_play_queue = self.__subsonic.bookmarks.get_play_queue()

return get_play_queue

def save(self) -> Self:
# TODO This should raise an exception
song_ids: list[str] = [song.id for song in self.songs] if self.songs else []

self.__subsonic.bookmarks.save_play_queue(
song_ids, self.current.id if self.current else None, self.position
)

return self
2 changes: 1 addition & 1 deletion src/knuckles/models/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ def create(self) -> "Playlist":

new_playlist = self.__subsonic.playlists.create_playlist(
# Ignore the None type error as the server
# should return a Error Code 10 in response
# should return an Error Code 10 in response
self.name, # type: ignore[arg-type]
self.comment,
self.public,
Expand Down
7 changes: 6 additions & 1 deletion tests/api/test_bookmarks.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ def test_get_play_queue(
assert response.current.id == song["id"]
assert response.changed == parser.parse(play_queue["changed"])
assert response.changed_by == client
assert type(response.songs) is list
assert response.songs[0].id == song["id"]


Expand All @@ -109,4 +110,8 @@ def test_save_play_queue(
) -> None:
responses.add(mock_save_play_queue)

subsonic.bookmarks.save_play_queue([song["id"]], song["id"], play_queue["position"])
response = subsonic.bookmarks.save_play_queue(
[song["id"]], song["id"], play_queue["position"]
)

assert response.current.id == song["id"]
4 changes: 2 additions & 2 deletions tests/models/test_song_queue.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import responses
from knuckles import Subsonic
from knuckles.models.play_queue import PlayQueue
from responses import Response


Expand Down Expand Up @@ -32,5 +33,4 @@ def test_save(
requested_queue = subsonic.bookmarks.get_play_queue()
requested_queue = requested_queue.save()

assert True is False
# assert type(requested_queue) is PlayQueue
assert type(requested_queue) is PlayQueue
2 changes: 1 addition & 1 deletion tests/models/test_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ def test_user_change_password(
response = subsonic.user_management.get_user(user["username"])
response = response.change_password(new_password)

assert type(response) == User
assert type(response) is User


def test_user_without_api_access(user: dict[str, Any]) -> None:
Expand Down

0 comments on commit bfd6cef

Please sign in to comment.