-
Notifications
You must be signed in to change notification settings - Fork 6
Improve metadata support #13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
94fbdab
653dc83
2fd6d65
a878052
2620913
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -33,6 +33,7 @@ | |
| (require 'tq) | ||
| (require 'cl-lib) | ||
| (require 'subr-x) | ||
| (require 'seq) | ||
|
|
||
|
|
||
| ;;; Customization | ||
|
|
@@ -171,7 +172,8 @@ message from the server.") | |
| (:constructor libmpdel--album-create) | ||
| (:conc-name libmpdel--album-)) | ||
| (name nil :read-only t) | ||
| (artist nil :read-only t)) | ||
| (date nil :read-only t) | ||
| (artists nil :read-only t)) | ||
|
|
||
| (cl-defstruct (libmpdel-song | ||
| (:constructor libmpdel--song-create) | ||
|
|
@@ -180,6 +182,9 @@ message from the server.") | |
| (track nil :read-only t) | ||
| (file nil :read-only t) | ||
| (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) | ||
|
|
@@ -190,6 +195,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-)) | ||
|
|
@@ -205,20 +215,28 @@ message from the server.") | |
| "Return artist name of ENTITY." | ||
| (libmpdel--artist-name (libmpdel-artist entity))) | ||
|
|
||
| (defun libmpdel-artists-name (entity) | ||
pinoaffe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| "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." | ||
| (or (car (libmpdel-artists entity)) | ||
| libmpdel--unknown-artist)) | ||
|
|
||
| (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." | ||
| (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." | ||
|
|
@@ -235,6 +253,18 @@ 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-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.") | ||
|
|
||
|
|
@@ -246,6 +276,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. | ||
|
|
||
|
|
@@ -265,6 +299,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") | ||
|
|
@@ -295,6 +333,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) | ||
|
|
@@ -321,9 +363,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." | ||
|
|
@@ -339,15 +388,28 @@ 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) | ||
pinoaffe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| (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)) | ||
| :album (libmpdel--album-create | ||
| :name (cdr (assq 'Album song-data)) | ||
| :artist (libmpdel--artist-create :name (cdr (assq 'Artist 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)) | ||
| :id (cdr (assq 'Id song-data)) | ||
|
|
@@ -357,6 +419,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)) | ||
| :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." | ||
| (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)) | ||
|
|
@@ -920,12 +993,26 @@ 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)) | ||
| "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" | ||
| (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))) | ||
|
|
||
|
|
@@ -950,14 +1037,24 @@ 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 | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. what is the purpose of this TODO? Are you planning to address it before we get the PR merged?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is a bit of a tradeoff that still needs to be addressed: you cannot get a correct list of all albums along with the associated dates and albumartists using As far as I know, if you want a list of all albums with metadata, you'd need to list all the songs in the entire database using I think that this tradeoff is worth it for artists, since listing all the songs of a particular artist should be an acceptable computational expense - but listing and processing all the songs in the mpd database may however very well be prohibitively computationally expensive. So the tradeoff is:
|
||
| "list album" | ||
| (lambda (data) | ||
| (funcall function | ||
| (seq-uniq | ||
| (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 (album-name) | ||
| (libmpdel--album-create :name album-name | ||
| :artist libmpdel--unknown-artist)) | ||
| (libmpdel-sorted-entries data 'Album)))))) | ||
pinoaffe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| (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." | ||
|
|
@@ -972,12 +1069,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)))))) | ||
pinoaffe marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| (seq-uniq | ||
| (libmpdel--create-albums-from-data data) | ||
| #'libmpdel-equal))))) | ||
|
|
||
| (cl-defgeneric libmpdel-list-songs (entity function) | ||
| "Call FUNCTION with all songs of ENTITY." | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how is the value of "artists" different from the album's artists?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
MPD distinguishes between "AlbumArtist" and "Artist", and this reflects this distinction in libmpdel. Typical real world examples of when these differ are: