Emacs can be a mobile music client…

I was screwing around with playlists on my desktop and had meant to see how well things work on my phone… Turns out it works pretty well.

I’m going to assume that if you’re reading this, you probably already know how to install Termux on your phone, and from there install emacs.

Once you’ve got that out of the way, install mpv and either (or both) exiftools or mediainfo. All of which should be installable with pkg install whatever. I was kind of surprised to find mpv available, and it of course doesn’t play video, but it does audio pretty well.

Then we add EMMS to emacs by adding this to our init.el or whatever you’re using.

(use-package emms
  :ensure t
  :config
  (require 'emms-info-mediainfo)
  (require 'emms-history)
  (require 'emms-lyrics)
  (require 'emms-mode-line)
  (require 'emms-tag-editor)
      (setq emms-player-list '(emms-player-mpv))
      (setq emms-info-functions '(emms-info-mediainfo))
      (emms-all)
      (customize-set-variable 'emms-player-mpv-update-metadata t)
      (emms-history-load)
      (emms-lyrics 1)
      (emms-cache 1)
      )

Restart emacs or eval that and wait for it to finish with emms. Now we have a functioning music player. You’ll probably want to run emms-add-directory-tree and add any local music you may have (remember to set up external storage in termux if you’re using an SD card). This is going to probably take a long time. Took about half an hour on my phone.

Now we can play all of our local music, make playlists, etc. All of the usual emms things. The only thing I couldn’t do that I wanted to do was have a way of saving emms playlists with added text. If you just save a playlist, none of the supported formats handle arbitrary text, and thus you’ll probably lose any notes you added to the playlist. Boo.

All isn’t lost though…emms playlists are just buffers full of text, with the tracks represented by text with track data added as text properties…you can look at it with describe-char with the point on a track. So what we need is a way to save a buffer with text properties. Emacs strips off text properties when it saves a buffer, and while there may be a way to make it not do so, I don’t know it. We can certainly make a way though… Disclaimer: I suck at elisp (still…) so I did get chatgpt to help with bits of it.

(defun skunk/save-buffer-with-properties (file)
  "Save the current buffer text and properties into FILE."
  (interactive "FSave buffer with properties: ")
  (let ((data (list (buffer-string)
                    (buffer-text-properties (point-min) (point-max)))))
    (with-temp-file file
      (prin1 data (current-buffer)))))

(defun skunk/load-buffer-with-properties (file)
  "Load FILE saved with `my-save-buffer-with-properties`."
  (interactive "fLoad buffer with properties: ")
  (let ((data (with-temp-buffer
                (insert-file-contents file)
                (read (current-buffer)))))
    (let ((buf (generate-new-buffer (file-name-nondirectory file))))
      (switch-to-buffer buf)
      (insert (car data))
      (set-text-properties (point-min) (point-max) nil)
      (dolist (prop (cadr data))
        (let ((start (nth 0 prop))
              (end   (nth 1 prop))
              (plist (nth 2 prop)))
          (add-text-properties start end plist)))
      buf)))

(defun buffer-text-properties (start end)
  "Return all text properties in region as a list."
  (let (props)
    (while (< start end)
      (let* ((next (or (next-property-change start nil end) end))
             (plist (text-properties-at start)))
        (push (list start next plist) props)
        (setq start next)))
    (nreverse props)))

(defun skunk/buffer-to-playlist ()
  "Convert a normal buffer to an EMMS playlist."
  (setq-local emms-playlist-buffer-p t)
  (emms-playlist-mode)
  )

(defun skunk/load-freeform-playlist (playlist)
  "Load a freeform playlist and convert the buffer into a valid EMMS playlist."
  (interactive "fPlaylist:")
  (skunk/load-buffer-with-properties playlist)
  (skunk/buffer-to-playlist)
  )

You can use skunk/load-freeform-playlist and skunk/save-buffer-with-properties to load and save playlists with arbitrary text in them. I mostly wanted them for my playlists with streamlinks, but I can see other uses for it as well. It probably wouldn’t be all that hard to do something like automatically add podcasts and stuff to a playlist, maybe on a timer or something. But that’s something for future nerdery…