Discussion:
[emms-help] Two new EMMS functions
Ian Dunn
2016-04-14 12:08:36 UTC
Permalink
I've created two interactive functions for EMMS that I think other people may find useful. Both of them are included in this email at the bottom, as well as a helper function for one of them.

The first is 'emms-add-file-from-cache', which, as it sounds, adds a file from the EMMS cache database to the
current EMMS playlist. The second is a function to interactively select and play one of the tracks in the current EMMS playlist.

Both of these functions use 'when-let' from subr-x, so I don't know if that creates a compatibility issue. If it does, I'd be happy to quickly fix them.

I hope other people will find these as useful as I do.
--
Ian Dunn

;;;###autoload
(defun emms-add-file-from-cache ()
"Interactively add a file from EMMS cache."
;; Marked as interactive-only because ‘completing-read’ is used, forcing
;; interaction with the user.
(declare (interactive-only t))
(interactive)
(when-let (file-name (completing-read "File: " emms-cache-db))
(emms-add-file file-name)))

(defun emms--collect-playlist-tracks (&optional playlist-buffer)
"Collect a hash table of tracks from PLAYLIST-BUFFER.

The returned hash table will have the track descriptions as the key,
and the point in the playlist buffer as the value.

If PLAYLIST-BUFFER is not specified, then it will default to the
current EMMS playlist."
(let ((l (make-hash-table :test #'equal)))
(with-current-buffer (or playlist-buffer emms-playlist-buffer)
(goto-char (point-min))
(emms-walk-tracks
(puthash (emms-info-track-description (emms-playlist-track-at)) (point) l)))
l))

;;;###autoload
(defun emms-select-playlist-track ()
"Select a track in the current playlist."
;; Marked as interactive-only because ‘completing-read’ is used, forcing
;; interaction with the user.
(declare (interactive-only t))
(interactive)
(let ((l (emms--collect-playlist-tracks emms-playlist-buffer)))
(when-let (key (completing-read "Track: " l))
(with-current-emms-playlist
(goto-char (gethash key l))
(emms-playlist-mode-play-smart)))))
Yoni Rabkin
2016-04-15 19:18:37 UTC
Permalink
Post by Ian Dunn
I've created two interactive functions for EMMS that I think other
people may find useful. Both of them are included in this email at
the bottom, as well as a helper function for one of them.
The first is 'emms-add-file-from-cache', which, as it sounds, adds a file from the EMMS cache database to the
current EMMS playlist. The second is a function to interactively
select and play one of the tracks in the current EMMS playlist.
Both of these functions use 'when-let' from subr-x, so I don't
know if that creates a compatibility issue. If it does, I'd be happy
to quickly fix them.
I hope other people will find these as useful as I do.
I like the idea behind `emms-select-playlist-track'. But I can see
renaming it to something like `emms-play-playlist-track' because it
actually plays the track.

However, I would change it so it doesn't create yet another copy of the
playlist as a hash-table which now needs to be kept synchronized. The
playlist-mode buffer is already a data structure and it's unclear how
long the playlist would need to be in this case in order to be slower
than a hash-table.

I don't know why `when-let' or `subr-x' would be an issue. As long as
they are available on all recent versions of Emacs I don't see a
problem.
--
"Cut your own wood and it will warm you twice"
Ian Dunn
2016-04-16 16:48:50 UTC
Permalink
Post by Yoni Rabkin
I like the idea behind `emms-select-playlist-track'. But I can see
renaming it to something like `emms-play-playlist-track' because it
actually plays the track.
That makes sense.
Post by Yoni Rabkin
However, I would change it so it doesn't create yet another copy of the
playlist as a hash-table which now needs to be kept synchronized. The
playlist-mode buffer is already a data structure and it's unclear how
long the playlist would need to be in this case in order to be slower
than a hash-table.
The purpose of the hash table in emms-select-playlist-track (or emms-play-playlist-track, as it may be) is to present the user with an understandable representation of each track. I chose to use the description as a key and the position as the value simply because that seemed easier at the time.

I realize that the tracks themselves are data structures, but I'm not sure that's going to help this function. I see emms-player-start, which takes a track, but it looks like it doesn't select the track, rendering the mode-line and playlist buffer both useless, as they will have the wrong track selected. I am only just learning about emms-player-start and this problem. Is there a better way to do this in EMMS?
--
Ian Dunn
Ian Dunn
2016-04-23 15:57:34 UTC
Permalink
After looking over some EMMS internals, I realized that EMMS uses text properties for each track. I'm not sure if this is what you were trying to tell me before, but it was what I ultimately took away from this.

First, I've got a pair of functions to select and play a given track.


(defun emms-find-track-in-playlist-buffer (track &optional playlist-buffer)
"Find EMMS track TRACK in PLAYLIST-BUFFER.

The current EMMS playlist buffer is used if PLAYLIST-BUFFER is nil."
(with-current-buffer (or playlist-buffer emms-playlist-buffer)
(text-property-any (point-min) (point-max) 'emms-track track)))

(defun emms-player-play-track (track)
"Select and play EMMS track TRACK. in the current playlist."
(with-current-emms-playlist
(when-let (pt (emms-find-track-in-playlist-buffer track))
(when emms-player-playing-p
(emms-stop))
(emms-playlist-select pt)
(emms-player-start track))))


I think these two functions will lessen the confusion I experienced for other people attempting to work with EMMS.

Now, the simplified version of emms-play-playlist-track:


;;;###autoload
(defun emms-play-playlist-track ()
"Select a track in the current playlist."
;; Marked as interactive-only because ‘completing-read’ is used, forcing
;; interaction with the user.
(declare (interactive-only t))
(interactive)
(with-current-emms-playlist
(when-let ((trk (completing-read "Track: " (split-string (buffer-string) "[\n\r]" t))))
(emms-player-play-track (get-text-property 0 'emms-track trk)))))


I offer these functions, along with emms-add-file-from-cache, to EMMS for its own use. I often use helm or ivy for completion, and at the very least, these functions work well with ivy (my current preference). I don't think these functions belong in either package, but in EMMS itself, as they don't depend on either completion method. If I'm not mistaken, they will also work well with ido (But I haven't verified this, so I'm assuming).
--
Ian Dunn
Yoni Rabkin
2016-04-23 20:20:36 UTC
Permalink
Is the goal to be able to select a track from an Emms playlist without
ever visiting the playlist buffer?
--
"Cut your own wood and it will warm you twice"
Ian Dunn
2016-04-24 01:03:49 UTC
Permalink
Post by Yoni Rabkin
Is the goal to be able to select a track from an Emms playlist without
ever visiting the playlist buffer?
Yes. I apologize for not making that clear.
--
Ian Dunn
Loading...