From 4bee8dd0951a15ac7554a3baa6555d55359f57ac Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 09:26:46 +0200 Subject: [PATCH 1/2] Add support for multiple album artists --- README.org | 2 +- libmpdel.el | 29 ++++++++++++++++++++--------- test/libmpdel-test.el | 31 +++++++++++++++++-------------- 3 files changed, 38 insertions(+), 24 deletions(-) diff --git a/README.org b/README.org index 5310377..97c42fb 100644 --- a/README.org +++ b/README.org @@ -43,7 +43,7 @@ The library is implemented around a set of entities. | *Name* | *Type* | *Fields* | *Description* | |------------------+-----------+----------------------+---------------------------------------------------------| | song | structure | name, album, file, … | | -| album | structure | name, date, artist | | +| album | structure | name, date, artists | | | artist | structure | name | | | genre | structure | name | | | directory | structure | name, path | | diff --git a/libmpdel.el b/libmpdel.el index b0c6209..4bf0f34 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -173,7 +173,7 @@ message from the server.") (:conc-name libmpdel--album-)) (name nil :read-only t) (date nil :read-only t) - (artist nil :read-only t)) + (artists nil :read-only t)) (cl-defstruct (libmpdel-song (:constructor libmpdel--song-create) @@ -214,16 +214,23 @@ message from the server.") "Return artist name of ENTITY." (libmpdel--artist-name (libmpdel-artist entity))) +(defun libmpdel-artists-name (entity) + "Return semicolon separated string of artists names of ENTITY." + (string-join (mapcar #'libmpdel--artist-name + (libmpdel-artists entity)) + "; ")) + (cl-defgeneric libmpdel-artist (entity) - "Return artist of ENTITY.") + "Return artist of ENTITY." + (car (libmpdel-artists entity))) -(cl-defmethod libmpdel-artist ((artist libmpdel-artist)) - "Return ARTIST." - artist) +(cl-defmethod libmpdel-artists ((artist libmpdel-artist)) + "Return singleton list containing ARTIST." + (list artist)) -(cl-defmethod libmpdel-artist ((album libmpdel-album)) +(cl-defmethod libmpdel-artists ((album libmpdel-album)) "Return the ALBUM's artist." - (libmpdel--album-artist album)) + (libmpdel--album-artists album)) (cl-defmethod libmpdel-artist ((song libmpdel-song)) "Return the SONG's artist." @@ -414,7 +421,7 @@ If the SONG's name is nil, return the filename instead." (libmpdel--album-create :name (cdr (assq 'Album song-data)) :date (cdr (assq 'Date song-data)) - :artist (libmpdel--artist-create :name (cdr (assq 'Artist song-data))))) + :artists (libmpdel--artists-create (libmpdel-entries song-data 'AlbumArtist)))) (defun libmpdel--create-albums-from-data (data) "Return a list of albums from DATA, a server's response." @@ -983,7 +990,11 @@ If HANDLER is nil, ignore response." (cl-defmethod libmpdel-entity-to-criteria ((album libmpdel-album)) "Return search query matching all songs from ALBUM." (format "%s album %S" - (libmpdel-entity-to-criteria (libmpdel-artist album)) + (string-join + (mapcar (lambda (artist) + (format "albumartist %S" (libmpdel-entity-name artist))) + (libmpdel-artists album)) + " ") (libmpdel-entity-name album))) (cl-defmethod libmpdel-entity-to-criteria ((genre libmpdel-genre)) diff --git a/test/libmpdel-test.el b/test/libmpdel-test.el index 6b939c6..b1de2bd 100644 --- a/test/libmpdel-test.el +++ b/test/libmpdel-test.el @@ -54,15 +54,15 @@ (ert-deftest libmpdel-test-artist () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) - (song (libmpdel--song-create :name "The song" :album album))) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) + (song (libmpdel--song-create :name "The song" :album album :artists (list artist)))) (should (equal artist (libmpdel-artist artist))) (should (equal artist (libmpdel-artist album))) (should (equal artist (libmpdel-artist song))))) (ert-deftest libmpdel-test-artist-name () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) (song (libmpdel--song-create :name "The song" :album album))) (should (equal "The Artist" (libmpdel-artist-name artist))) (should (equal "The Artist" (libmpdel-artist-name album))) @@ -70,7 +70,7 @@ (ert-deftest libmpdel-test-album-name () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) (song (libmpdel--song-create :name "The song" :album album))) (should-error (libmpdel-album-name artist)) (should (equal "The Album" (libmpdel-album-name album))) @@ -78,7 +78,7 @@ (ert-deftest libmpdel-test-album () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) (song (libmpdel--song-create :name "The song" :album album))) (should-error (libmpdel-album artist)) (should (equal album (libmpdel-album album))) @@ -86,7 +86,7 @@ (ert-deftest libmpdel-test-entity-name () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) (song (libmpdel--song-create :name "The song" :album album)) (stored-playlist (libmpdel--stored-playlist-create :name "The playlist"))) (should (equal "The Artist" (libmpdel-entity-name artist))) @@ -101,7 +101,7 @@ (ert-deftest libmpdel-test-entity-parent () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist)) + (album (libmpdel--album-create :name "The Album" :artists (list artist))) (song (libmpdel--song-create :name "The song" :album album)) (stored-playlist (libmpdel--stored-playlist-create :name "The playlist"))) (should (equal 'artists (libmpdel-entity-parent artist))) @@ -122,6 +122,7 @@ (Performer . "The Pianist") (Performer . "The Singer") (Genre . "The Genre") + (AlbumArtist . "The Albumartist") (Artist . "The Artist"))))) (should (equal "The song" (libmpdel-entity-name song))) (should (equal "foo/song.ogg" (libmpdel-song-file song))) @@ -131,7 +132,7 @@ (should (equal "The Album" (libmpdel-entity-name (libmpdel-album song)))) (should (equal (list "The Violinist" "The Pianist" "The Singer") (mapcar #'libmpdel-entity-name (libmpdel-performers song)))) - (should (equal "The Artist" (libmpdel-entity-name (libmpdel-artist (libmpdel-album song))))))) + (should (equal "The Albumartist" (libmpdel-entity-name (libmpdel-artist (libmpdel-album song))))))) (ert-deftest libmpdel-test-current-playlist-p () (should (libmpdel-current-playlist-p 'current-playlist)) @@ -279,20 +280,22 @@ (ert-deftest libmpdel-test-playlist-add-no-string-id-sends-findadd () (let* ((artist (libmpdel--artist-create :name "The Artist")) - (album (libmpdel--album-create :name "The Album" :artist artist))) + (album (libmpdel--album-create :name "The Album" :artists (list artist)))) (libmpdel-test--with-connection (libmpdel-playlist-add album 'current-playlist) - (should (equal '("findadd artist \"The Artist\" album \"The Album\"") + (should (equal '("findadd albumartist \"The Artist\" album \"The Album\"") (last commands)))))) (ert-deftest libmpdel-test-playlist-add-sends-findadd () (let ((song (libmpdel--create-song-from-data '((Title . "S") (Album . "A") + (AlbumArtist . "Art") + (AlbumArtist . "Bart") (Artist . "Art"))))) (libmpdel-test--with-connection (libmpdel-playlist-add song 'current-playlist) - (should (equal '("findadd artist \"Art\" album \"A\" title \"S\"") + (should (equal '("findadd albumartist \"Art\" albumartist \"Bart\" album \"A\" title \"S\"") (last commands)))))) @@ -333,9 +336,9 @@ (let* ((artist1 (libmpdel--artist-create :name "artist1")) (artist1-bis (libmpdel--artist-create :name "artist1")) (artist2 (libmpdel--artist-create :name "artist2")) - (album1 (libmpdel--album-create :name "album1" :artist artist1)) - (album1-bis (libmpdel--album-create :name "album1" :artist artist1)) - (album2 (libmpdel--album-create :name "album2" :artist artist1)) + (album1 (libmpdel--album-create :name "album1" :artists (list artist1))) + (album1-bis (libmpdel--album-create :name "album1" :artists (list artist1))) + (album2 (libmpdel--album-create :name "album2" :artists (list artist1))) (song1 (libmpdel--song-create :name "name" :file "file" From 0cbed64c54e28f5ba6dd3d0fc0d622b5b61393fd Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 09:27:27 +0200 Subject: [PATCH 2/2] Add support for multiple song artists --- libmpdel.el | 18 +++++++++++++----- test/libmpdel-test.el | 5 +++-- 2 files changed, 16 insertions(+), 7 deletions(-) diff --git a/libmpdel.el b/libmpdel.el index 4bf0f34..f872aff 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -184,6 +184,7 @@ message from the server.") (album nil :read-only t) (performers nil :read-only t) (genres nil :read-only t) + (artists nil :read-only t) (disc nil :read-only t) (date nil :read-only t) (id nil :read-only t) @@ -222,7 +223,8 @@ message from the server.") (cl-defgeneric libmpdel-artist (entity) "Return artist of ENTITY." - (car (libmpdel-artists entity))) + (or (car (libmpdel-artists entity)) + libmpdel--unknown-artist)) (cl-defmethod libmpdel-artists ((artist libmpdel-artist)) "Return singleton list containing ARTIST." @@ -232,9 +234,9 @@ message from the server.") "Return the ALBUM's artist." (libmpdel--album-artists album)) -(cl-defmethod libmpdel-artist ((song libmpdel-song)) - "Return the SONG's artist." - (libmpdel-artist (libmpdel--song-album song))) +(cl-defmethod libmpdel-artists ((song libmpdel-song)) + "Return the SONG's artists." + (libmpdel--song-artists song)) (defun libmpdel-album-name (entity) "Return album name of ENTITY." @@ -406,6 +408,7 @@ If the SONG's name is nil, return the filename instead." :file (cdr (assq 'file song-data)) :performers (libmpdel--artists-create (libmpdel-entries song-data 'Performer)) :genres (libmpdel--genres-create (libmpdel-entries song-data 'Genre)) + :artists (libmpdel--artists-create (libmpdel-entries song-data 'Artist)) :album (libmpdel--create-album-from-data song-data) :date (cdr (assq 'Date song-data)) :disc (cdr (assq 'Disc song-data)) @@ -1004,7 +1007,12 @@ If HANDLER is nil, ignore response." (cl-defmethod libmpdel-entity-to-criteria ((song libmpdel-song)) "Return search query matching SONG." - (format "%s title %S" + (format "%s %s title %S" + (string-join + (mapcar (lambda (artist) + (format "artist %S" (libmpdel-entity-name artist))) + (libmpdel-artists song)) + " ") (libmpdel-entity-to-criteria (libmpdel-album song)) (libmpdel-entity-name song))) diff --git a/test/libmpdel-test.el b/test/libmpdel-test.el index b1de2bd..9c45489 100644 --- a/test/libmpdel-test.el +++ b/test/libmpdel-test.el @@ -63,7 +63,7 @@ (ert-deftest libmpdel-test-artist-name () (let* ((artist (libmpdel--artist-create :name "The Artist")) (album (libmpdel--album-create :name "The Album" :artists (list artist))) - (song (libmpdel--song-create :name "The song" :album album))) + (song (libmpdel--song-create :name "The song" :album album :artists (list artist)))) (should (equal "The Artist" (libmpdel-artist-name artist))) (should (equal "The Artist" (libmpdel-artist-name album))) (should (equal "The Artist" (libmpdel-artist-name song))))) @@ -132,6 +132,7 @@ (should (equal "The Album" (libmpdel-entity-name (libmpdel-album song)))) (should (equal (list "The Violinist" "The Pianist" "The Singer") (mapcar #'libmpdel-entity-name (libmpdel-performers song)))) + (should (equal "The Artist" (libmpdel-entity-name (libmpdel-artist song)))) (should (equal "The Albumartist" (libmpdel-entity-name (libmpdel-artist (libmpdel-album song))))))) (ert-deftest libmpdel-test-current-playlist-p () @@ -295,7 +296,7 @@ (Artist . "Art"))))) (libmpdel-test--with-connection (libmpdel-playlist-add song 'current-playlist) - (should (equal '("findadd albumartist \"Art\" albumartist \"Bart\" album \"A\" title \"S\"") + (should (equal '("findadd artist \"Art\" albumartist \"Art\" albumartist \"Bart\" album \"A\" title \"S\"") (last commands))))))