Skip to content

Commit

Permalink
Merge pull request #41 from kutu-dev/feat/add-add-and-remove-methods-…
Browse files Browse the repository at this point in the history
…to-the-playlist-model

Add add and remove method with property syncthing
  • Loading branch information
kutu-dev authored Jan 13, 2024
2 parents 0b5fff7 + 4d295fb commit b402fa6
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 44 deletions.
55 changes: 55 additions & 0 deletions src/knuckles/models/playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ def update(self) -> Self:
Updates the name, comment and public state of the playlist with the ones
in the parameters of the object.
NOT the playlist list, please use TODO (add_songs)
and TODO (remove_songs) to reflect it in the model.
:return: The object itself to allow method chaining.
:rtype: Self
"""
Expand All @@ -140,3 +143,55 @@ def delete(self) -> Self:
self.__subsonic.playlists.delete_playlist(self.id)

return self

def add_songs(self, song_ids: list[str]) -> Self:
"""Add any number of new songs to the playlist
It's reflected in the songs list in the model.
:param song_ids: A list with the IDs of the songs to add.
:return: The object itself to allow method chaining.
:rtype: Self
"""

self.__subsonic.playlists.update_playlist(self.id, song_ids_to_add=song_ids)

if not self.songs:
self.songs = []

for id_ in song_ids:
self.songs.append(Song(self.__subsonic, id_))

if not self.song_count:
self.song_count = 0

self.song_count += len(song_ids)

return self

def remove_songs(self, songs_indexes: list[int]) -> Self:
"""Remove any number of new songs to the playlist
It's reflected in the songs list in the model.
:param song_indexes: A list with the indexes of the songs to remove.
:return: The object itself to allow method chaining.
:rtype: Self
"""

self.__subsonic.playlists.update_playlist(
self.id, song_indexes_to_remove=songs_indexes
)

if not self.songs:
self.songs = []

for index in songs_indexes:
del self.songs[index]

if not self.song_count:
self.song_count = 0

self.song_count -= len(songs_indexes)

return self
43 changes: 42 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from typing import Any, Protocol

import knuckles
import pytest
from knuckles.subsonic import Subsonic
from responses import GET, Response, matchers

pytest_plugins = [
"tests.subsonic",
"tests.mocks.system",
"tests.mocks.chat",
"tests.mocks.jukebox_control",
Expand All @@ -22,6 +23,46 @@
]


@pytest.fixture
def username() -> str:
return "user"


@pytest.fixture
def password() -> str:
return "password"


@pytest.fixture
def client() -> str:
return "client"


@pytest.fixture
def base_url() -> str:
return "https://example.com"


@pytest.fixture
def subsonic(base_url: str, username: str, password: str, client: str) -> Subsonic:
return knuckles.Subsonic(
url=base_url,
user=username,
password=password,
client=client,
)


@pytest.fixture
def params(username: str, client: str) -> dict[str, str]:
return {
"u": username,
"v": "1.16.1",
"c": client,
"f": "json",
}


@pytest.fixture
def subsonic_response() -> dict[str, Any]:
return {
Expand Down
27 changes: 27 additions & 0 deletions tests/mocks/playlists.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,3 +99,30 @@ def mock_delete_playlist(
mock_generator: MockGenerator, playlist: dict[str, Any]
) -> Response:
return mock_generator("deletePlaylist", {"id": playlist["id"]})


@pytest.fixture
def mock_add_song_to_playlist(
mock_generator: MockGenerator,
playlist: dict[str, Any],
song: dict[str, Any],
) -> Response:
return mock_generator(
"updatePlaylist",
{"playlistId": playlist["id"], "songIdToAdd": song["id"]},
)


@pytest.fixture
def mock_remove_song_to_playlist(
mock_generator: MockGenerator,
playlist: dict[str, Any],
song: dict[str, Any],
) -> Response:
return mock_generator(
"updatePlaylist",
{
"playlistId": playlist["id"],
"songIndexToRemove": 0,
},
)
42 changes: 42 additions & 0 deletions tests/models/test_playlist.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,3 +70,45 @@ def test_delete(
response = response.delete()

assert type(response) is Playlist


@responses.activate
def test_add(
subsonic: Subsonic,
mock_get_playlist: Response,
mock_add_song_to_playlist: Response,
playlist: dict[str, Any],
song: dict[str, Any],
) -> None:
responses.add(mock_get_playlist)
responses.add(mock_add_song_to_playlist)

response = subsonic.playlists.get_playlist(playlist["id"])
# Remove the default songs from the mock_get_playlist mock
response.songs = []
response.song_count = 0

response = response.add_songs([song["id"]])

assert response.songs is not None
assert response.songs[0].id == song["id"]
assert response.song_count == 1


@responses.activate
def test_remove(
subsonic: Subsonic,
mock_get_playlist: Response,
mock_remove_song_to_playlist: Response,
playlist: dict[str, Any],
) -> None:
responses.add(mock_get_playlist)
responses.add(mock_remove_song_to_playlist)

response = subsonic.playlists.get_playlist(playlist["id"])

response = response.remove_songs([0])

assert response.songs is not None
assert response.songs == []
assert response.song_count == 0
43 changes: 0 additions & 43 deletions tests/subsonic.py

This file was deleted.

0 comments on commit b402fa6

Please sign in to comment.