Favourites Playlist

18th of April, 2022

Last time I started a small library called Racket and today I extended it to add functionality for managing a simple ‘favourite tracks’ playlist. The playlist is stored in a format called m3u (the only reason being because it’s the least complicated one that VLC uses). The format is simply like this:

#EXTM3U
file:///path/to/track/1.ogg
file:///path/to/track/2.wav

To start I defined a custom variable called racket-favourites-playlist which stores the path of the playlist:

(defcustom racket-favourites-playlist "~/Music/playlists/Favourites.m3u"
  "File path where favourites playlist is stored."
  :type 'string
  :group 'racket)

Next I added some simple functions to play the playlist in EMMS:

(defun racket-add-favourites ()
  "Add favourites playlist"
  (interactive)
  (emms-add-playlist-file racket-favourites-playlist))

(defun racket-play-favourites ()
  "Play favourites playlist"
  (interactive)
  (emms-play-playlist-file racket-favourites-playlist))

Next comes the fun part: to add the current playing track to the playlist, so that I can quickly add a track I love with a custom keybinding. To find the filename of the current track, I can use the mouthful of a function emms-score-current-selected-track-filename. The function I made avoids making any changes if the track is already in the playlist, and adds an extra newline to the end of the file if one is missing.

(defun racket-add-track-to-favourites ()
  "Add current track to favourites"
  (interactive)
  (let ((line (concat "file://" (emms-score-current-selected-track-filename))))
    (with-current-buffer (or (get-file-buffer racket-favourites-playlist)
                             (find-file-noselect racket-favourites-playlist))
      (save-excursion
        (beginning-of-buffer)
        (if (search-forward-regexp
              (concat "^" (regexp-quote line) "$")
            nil t)
          ;; Don’t do anything if the track is already added
          (message "The track is already inside the playlist.")
          ;; Add to playlist
          (progn 
            (end-of-buffer)
            (unless (eq ?\C-j (char-before))
              (insert "\n"))
            (insert line "\n")
            (save-buffer)
            (message "Track added to playlist.")))))))

I also made two more functions: one to remove the current track from favourites and another to open the playlist file so I can easily reorder it. You can find the full code for Racket here. Finally, I bound each of these functions to a key combination under C-SPC r (C-SPC is where I define all my custom keybindings and the r stands for Racket). You can see the code for that here.