From 94fbdab3d23855c9d041af7ca11f2fe8d6985eae Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Thu, 29 May 2025 23:07:06 +0200 Subject: [PATCH 1/5] Add date field to albums --- README.org | 2 +- libmpdel.el | 47 +++++++++++++++++++++++++++++-------------- test/libmpdel-test.el | 3 +++ 3 files changed, 36 insertions(+), 16 deletions(-) diff --git a/README.org b/README.org index 7746a88..23a783d 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, artist | | +| album | structure | name, date, artist | | | artist | structure | name | | | directory | structure | name, path | | | stored-playlist | structure | name | A named user-specified sequence of songs | diff --git a/libmpdel.el b/libmpdel.el index 5db54ba..8dae672 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -33,6 +33,7 @@ (require 'tq) (require 'cl-lib) (require 'subr-x) +(require 'seq) ;;; Customization @@ -171,6 +172,7 @@ message from the server.") (:constructor libmpdel--album-create) (:conc-name libmpdel--album-)) (name nil :read-only t) + (date nil :read-only t) (artist nil :read-only t)) (cl-defstruct (libmpdel-song @@ -321,9 +323,16 @@ If the SONG's name is nil, return the filename instead." "Return the track number of SONG within its album." (or (libmpdel--song-track song) "")) -(defun libmpdel-entity-date (song) - "Return the date of SONG." - (or (libmpdel--song-date song) "")) +(cl-defgeneric libmpdel-entity-date (entity) + "Return the date of ENTITY.") + +(cl-defmethod libmpdel-entity-date ((album libmpdel-album)) + "Return ALBUM's date." + (libmpdel--album-date album)) + +(cl-defmethod libmpdel-entity-date ((song libmpdel-song)) + "Return SONG's date." + (libmpdel--song-date song)) (defun libmpdel-song-disc (song) "Return the disc number of SONG within its album." @@ -345,9 +354,7 @@ If the SONG's name is nil, return the filename instead." :name (cdr (assq 'Title song-data)) :track (cdr (assq 'Track song-data)) :file (cdr (assq 'file song-data)) - :album (libmpdel--album-create - :name (cdr (assq 'Album song-data)) - :artist (libmpdel--artist-create :name (cdr (assq 'Artist song-data)))) + :album (libmpdel--create-album-from-data song-data) :date (cdr (assq 'Date song-data)) :disc (cdr (assq 'Disc song-data)) :id (cdr (assq 'Id song-data)) @@ -357,6 +364,17 @@ If the SONG's name is nil, return the filename instead." "Return a list of songs from DATA, a server's response." (mapcar #'libmpdel--create-song-from-data (libmpdel-group-data data))) +(defun libmpdel--create-album-from-data (album-data) + "Return an album from ALBUM-DATA, a server's response." + (libmpdel--album-create + :name (cdr (assq 'Album album-data)) + :date (cdr (assq 'Date album-data)) + :artist (libmpdel--artist-create :name (assq 'Artist album-data)))) + +(defun libmpdel--create-albums-from-data (data) + "Return a list of albums from DATA, a server's response." + (mapcar #'libmpdel--create-album-from-data (libmpdel-group-data data))) + (defun libmpdel-current-playlist-p (entity) "Return non-nil if ENTITY is the current playlist." (eq entity 'current-playlist)) @@ -950,14 +968,13 @@ If HANDLER is nil, ignore response." (cl-defmethod libmpdel-list ((_entity (eql albums)) function) "Call FUNCTION with all albums as parameter." (libmpdel-send-command + ;; TODO: compute all albums by listing all songs "list album" (lambda (data) (funcall function - (mapcar - (lambda (album-name) - (libmpdel--album-create :name album-name - :artist libmpdel--unknown-artist)) - (libmpdel-sorted-entries data 'Album)))))) + (seq-uniq + (libmpdel--create-albums-from-data data) + #'libmpdel-equal))))) (cl-defmethod libmpdel-list ((_entity (eql stored-playlists)) function) "Call FUNCTION with all stored playlists as parameter." @@ -972,12 +989,12 @@ If HANDLER is nil, ignore response." (cl-defmethod libmpdel-list ((artist libmpdel-artist) function) "Call FUNCTION with all albums of ARTIST as parameter." (libmpdel-send-command - `("list album %s" ,(libmpdel-entity-to-criteria artist)) + `("find %s sort AlbumSort" ,(libmpdel-entity-to-criteria artist)) (lambda (data) (funcall function - (mapcar - (lambda (album-name) (libmpdel--album-create :name album-name :artist artist)) - (libmpdel-sorted-entries data 'Album)))))) + (seq-uniq + (libmpdel--create-albums-from-data data) + #'libmpdel-equal))))) (cl-defgeneric libmpdel-list-songs (entity function) "Call FUNCTION with all songs of ENTITY." diff --git a/test/libmpdel-test.el b/test/libmpdel-test.el index 0edad04..7ce9868 100644 --- a/test/libmpdel-test.el +++ b/test/libmpdel-test.el @@ -116,10 +116,13 @@ (let ((song (libmpdel--create-song-from-data '((Title . "The song") (file . "foo/song.ogg") + (Date . "1970-01-01") (Album . "The Album") (Artist . "The Artist"))))) (should (equal "The song" (libmpdel-entity-name song))) (should (equal "foo/song.ogg" (libmpdel-song-file song))) + (should (equal "1970-01-01" (libmpdel-entity-date song))) + (should (equal "1970-01-01" (libmpdel-entity-date (libmpdel-album song)))) (should (equal "The Album" (libmpdel-entity-name (libmpdel-album song)))) (should (equal "The Artist" (libmpdel-entity-name (libmpdel-artist (libmpdel-album song))))))) From 653dc831b106737fab9795f88cf516116176ad1c Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 08:46:32 +0200 Subject: [PATCH 2/5] Add genres field to songs --- README.org | 2 ++ libmpdel.el | 49 +++++++++++++++++++++++++++++++++++++++++++ test/libmpdel-test.el | 2 ++ 3 files changed, 53 insertions(+) diff --git a/README.org b/README.org index 23a783d..5310377 100644 --- a/README.org +++ b/README.org @@ -45,6 +45,7 @@ The library is implemented around a set of entities. | song | structure | name, album, file, … | | | album | structure | name, date, artist | | | artist | structure | name | | +| genre | structure | name | | | directory | structure | name, path | | | stored-playlist | structure | name | A named user-specified sequence of songs | | search-criteria | structure | type, what | Read the [[https://www.musicpd.org/doc/protocol/database.html][protocol documentation]] | @@ -52,6 +53,7 @@ The library is implemented around a set of entities. |------------------+-----------+----------------------+---------------------------------------------------------| | artists | symbol | /none/ | Represent the set of all artists | | albums | symbol | /none/ | Represent the set of all albums | +| genres | symbol | /none/ | Represent the set of all genres | | directories | symbol | /none/ | Represent all directories in ~libmpdel-music-directory~ | | current-playlist | symbol | /none/ | Represent the currently played sequence of songs | | stored-playlists | symbol | /none/ | Represent the set of all stored playlists | diff --git a/libmpdel.el b/libmpdel.el index 8dae672..3864860 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -182,6 +182,7 @@ message from the server.") (track nil :read-only t) (file nil :read-only t) (album nil :read-only t) + (genres nil :read-only t) (disc nil :read-only t) (date nil :read-only t) (id nil :read-only t) @@ -192,6 +193,11 @@ message from the server.") (:conc-name libmpdel--stored-playlist-)) (name nil :read-only t)) +(cl-defstruct (libmpdel-genre + (:constructor libmpdel--genre-create) + (:conc-name libmpdel--genre-)) + (name nil :read-only t)) + (cl-defstruct (libmpdel-search-criteria (:constructor libmpdel-search-criteria-create) (:conc-name libmpdel--search-criteria-)) @@ -237,6 +243,14 @@ message from the server.") "Return SONG's album." (libmpdel--song-album song)) +(cl-defmethod libmpdel-genres ((song libmpdel-song)) + "Return SONG's genres." + (libmpdel--song-genres song)) + +(cl-defmethod libmpdel-genres ((genre libmpdel-genre)) + "Return singleton list GENRE." + (list genre)) + (cl-defgeneric libmpdel-entity-name (entity) "Return the name of ENTITY.") @@ -248,6 +262,10 @@ message from the server.") "Return ALBUM's name." (libmpdel--album-name album)) +(cl-defmethod libmpdel-entity-name ((genre libmpdel-genre)) + "Return GENRE's name." + (libmpdel--genre-name genre)) + (cl-defmethod libmpdel-entity-name ((song libmpdel-song)) "Return SONG's name. @@ -267,6 +285,10 @@ If the SONG's name is nil, return the filename instead." "Return a string describing the `albums' entity." "All albums") +(cl-defmethod libmpdel-entity-name ((_entity (eql genres))) + "Return a string describing the `genres' entity." + "All genres") + (cl-defmethod libmpdel-entity-name ((_entity (eql current-playlist))) "Return a string describing the `current-playlist' entity." "Current playlist") @@ -297,6 +319,10 @@ If the SONG's name is nil, return the filename instead." "Return ALBUM's artist." (libmpdel-artist album)) +(cl-defmethod libmpdel-entity-parent ((_genre libmpdel-genre)) + "Return the `genres' entity." + 'genres) + (cl-defmethod libmpdel-entity-parent ((_artist libmpdel-artist)) "Return the `artists' entity." 'artists) @@ -348,12 +374,19 @@ If the SONG's name is nil, return the filename instead." (when (and (stringp pos) (not (string= pos ""))) (string-to-number pos)))) +(defun libmpdel--genres-create (genre-names) + "Return a list of genres whose names are GENRE-NAMES." + (mapcar (lambda (name) + (libmpdel--genre-create :name name)) + genre-names)) + (defun libmpdel--create-song-from-data (song-data) "Return a song from SONG-DATA, a server's response." (libmpdel--song-create :name (cdr (assq 'Title song-data)) :track (cdr (assq 'Track song-data)) :file (cdr (assq 'file song-data)) + :genres (libmpdel--genres-create (libmpdel-entries song-data 'Genre)) :album (libmpdel--create-album-from-data song-data) :date (cdr (assq 'Date song-data)) :disc (cdr (assq 'Disc song-data)) @@ -941,6 +974,11 @@ If HANDLER is nil, ignore response." (libmpdel-entity-to-criteria (libmpdel-artist album)) (libmpdel-entity-name album))) +(cl-defmethod libmpdel-entity-to-criteria ((genre libmpdel-genre)) + "Return search query matching all songs from GENRE." + (format "genre %S" + (libmpdel-entity-name genre))) + (cl-defmethod libmpdel-entity-to-criteria ((song libmpdel-song)) "Return search query matching SONG." (format "%s title %S" @@ -976,6 +1014,17 @@ If HANDLER is nil, ignore response." (libmpdel--create-albums-from-data data) #'libmpdel-equal))))) +(cl-defmethod libmpdel-list ((_entity (eql genres)) function) + "Call FUNCTION with all genres as parameter." + (libmpdel-send-command + "list genre" + (lambda (data) + (funcall function + (mapcar + (lambda (genre-name) + (libmpdel--genre-create :name genre-name)) + (libmpdel-sorted-entries data 'Genre)))))) + (cl-defmethod libmpdel-list ((_entity (eql stored-playlists)) function) "Call FUNCTION with all stored playlists as parameter." (libmpdel-send-command diff --git a/test/libmpdel-test.el b/test/libmpdel-test.el index 7ce9868..179a8e5 100644 --- a/test/libmpdel-test.el +++ b/test/libmpdel-test.el @@ -118,11 +118,13 @@ (file . "foo/song.ogg") (Date . "1970-01-01") (Album . "The Album") + (Genre . "The Genre") (Artist . "The Artist"))))) (should (equal "The song" (libmpdel-entity-name song))) (should (equal "foo/song.ogg" (libmpdel-song-file song))) (should (equal "1970-01-01" (libmpdel-entity-date song))) (should (equal "1970-01-01" (libmpdel-entity-date (libmpdel-album song)))) + (should (equal (list "The Genre") (mapcar #'libmpdel-entity-name (libmpdel-genres song)))) (should (equal "The Album" (libmpdel-entity-name (libmpdel-album song)))) (should (equal "The Artist" (libmpdel-entity-name (libmpdel-artist (libmpdel-album song))))))) From 2fd6d658c62bc97f8430073c618d2074967b4090 Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 09:10:26 +0200 Subject: [PATCH 3/5] Add performers field to songs --- libmpdel.el | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libmpdel.el b/libmpdel.el index 3864860..592eb97 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -183,6 +183,7 @@ message from the server.") (file nil :read-only t) (album nil :read-only t) (genres nil :read-only t) + (performers nil :read-only t) (disc nil :read-only t) (date nil :read-only t) (id nil :read-only t) @@ -251,6 +252,10 @@ message from the server.") "Return singleton list GENRE." (list genre)) +(cl-defmethod libmpdel-performers ((song libmpdel-song)) + "Return SONG's performers." + (libmpdel--song-performers song)) + (cl-defgeneric libmpdel-entity-name (entity) "Return the name of ENTITY.") @@ -374,6 +379,12 @@ If the SONG's name is nil, return the filename instead." (when (and (stringp pos) (not (string= pos ""))) (string-to-number pos)))) +(defun libmpdel--artists-create (artist-names) + "Return a list of artists whose names are ARTIST-NAMES." + (mapcar (lambda (name) + (libmpdel--artist-create :name name)) + artist-names)) + (defun libmpdel--genres-create (genre-names) "Return a list of genres whose names are GENRE-NAMES." (mapcar (lambda (name) @@ -387,6 +398,7 @@ If the SONG's name is nil, return the filename instead." :track (cdr (assq 'Track song-data)) :file (cdr (assq 'file song-data)) :genres (libmpdel--genres-create (libmpdel-entries song-data 'Genre)) + :performers (libmpdel--artists-create (libmpdel-entries song-data 'Performer)) :album (libmpdel--create-album-from-data song-data) :date (cdr (assq 'Date song-data)) :disc (cdr (assq 'Disc song-data)) From a878052831c644d27c3bf9f37497964d581221c5 Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 09:26:46 +0200 Subject: [PATCH 4/5] 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 592eb97..14618b3 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 album-data)) :date (cdr (assq 'Date album-data)) - :artist (libmpdel--artist-create :name (assq 'Artist album-data)))) + :artists (libmpdel--artists-create (libmpdel-entries album-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 179a8e5..0769985 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))) @@ -118,6 +118,7 @@ (file . "foo/song.ogg") (Date . "1970-01-01") (Album . "The Album") + (AlbumArtist . "The Albumartist") (Genre . "The Genre") (Artist . "The Artist"))))) (should (equal "The song" (libmpdel-entity-name song))) @@ -126,7 +127,7 @@ (should (equal "1970-01-01" (libmpdel-entity-date (libmpdel-album song)))) (should (equal (list "The Genre") (mapcar #'libmpdel-entity-name (libmpdel-genres song)))) (should (equal "The Album" (libmpdel-entity-name (libmpdel-album 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)) @@ -274,20 +275,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)))))) @@ -328,9 +331,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 2620913e7f2d45a4c8decba57368ece5d86b62e7 Mon Sep 17 00:00:00 2001 From: pinoaffe Date: Fri, 30 May 2025 09:27:27 +0200 Subject: [PATCH 5/5] 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 14618b3..5f29f4e 100644 --- a/libmpdel.el +++ b/libmpdel.el @@ -184,6 +184,7 @@ message from the server.") (album nil :read-only t) (genres nil :read-only t) (performers 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)) :genres (libmpdel--genres-create (libmpdel-entries song-data 'Genre)) :performers (libmpdel--artists-create (libmpdel-entries song-data 'Performer)) + :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 0769985..01be9ad 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))))) @@ -127,6 +127,7 @@ (should (equal "1970-01-01" (libmpdel-entity-date (libmpdel-album song)))) (should (equal (list "The Genre") (mapcar #'libmpdel-entity-name (libmpdel-genres song)))) (should (equal "The Album" (libmpdel-entity-name (libmpdel-album 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 () @@ -290,7 +291,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))))))