Emacs user interface for Music Player Daemon (https://www.musicpd.org/), a flexible, powerful, server-side application for playing music.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.6KB

  1. ;;; mpdel-playlist.el --- Display and manipulate MPD playlists -*- lexical-binding: t; -*-
  2. ;; Copyright (C) 2017-2020 Damien Cassou
  3. ;; Author: Damien Cassou <damien@cassou.me>
  4. ;; Keywords: multimedia
  5. ;; Url: https://gitlab.petton.fr/mpdel/mpdel
  6. ;; Package-requires: ((emacs "25.1"))
  7. ;; Version: 1.0.0
  8. ;; This program is free software; you can redistribute it and/or modify
  9. ;; it under the terms of the GNU General Public License as published by
  10. ;; the Free Software Foundation, either version 3 of the License, or
  11. ;; (at your option) any later version.
  12. ;; This program is distributed in the hope that it will be useful,
  13. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ;; GNU General Public License for more details.
  16. ;; You should have received a copy of the GNU General Public License
  17. ;; along with this program. If not, see <https://www.gnu.org/licenses/>.
  18. ;;; Commentary:
  19. ;; Let the user view and manipulate MPD's current playlist and stored
  20. ;; playlists.
  21. ;;; Code:
  22. (require 'mpdel-core)
  23. (require 'mpdel-tablist)
  24. ;;; Customization
  25. (defgroup mpdel-playlist nil
  26. "Display and manipulate MPD playlists."
  27. :group 'libmpdel)
  28. (defface mpdel-playlist-current-song-face
  29. '((t . (:inherit font-lock-keyword-face)))
  30. "Face to highlight current song in playlist."
  31. :group 'mpdel-playlist)
  32. ;;; `navigel' major-mode configuration
  33. (navigel-method mpdel navigel-entity-tablist-mode ((_entity (eql current-playlist)))
  34. (mpdel-playlist-current-playlist-mode))
  35. (navigel-method mpdel navigel-entity-tablist-mode ((_entity libmpdel-stored-playlist))
  36. (mpdel-playlist-stored-playlist-mode))
  37. (navigel-method mpdel navigel-delete ((songs list) &context (major-mode mpdel-playlist-mode) &optional _callback)
  38. (libmpdel-playlist-delete songs navigel-entity))
  39. ;;; Private functions
  40. (defun mpdel-playlist--highlight ()
  41. "Highlight currently played song in current buffer."
  42. (save-excursion
  43. (when (navigel-go-to-entity (libmpdel-current-song))
  44. (let ((inhibit-read-only t))
  45. (put-text-property (line-beginning-position) (line-end-position)
  46. 'face 'mpdel-playlist-current-song-face)))))
  47. ;;; Private functions
  48. (defun mpdel-playlist--register-to-hooks ()
  49. "Register to several hooks to refresh automatically refresh the current buffer.."
  50. (let ((buffer (current-buffer)))
  51. (let* ((refresh-fn (lambda ()
  52. (with-current-buffer buffer
  53. (navigel-refresh))))
  54. (playlist navigel-entity)
  55. (hooks (if (libmpdel-stored-playlist-p playlist)
  56. '(libmpdel-stored-playlist-changed-hook)
  57. '(libmpdel-current-playlist-changed-hook
  58. libmpdel-current-song-changed-hook
  59. libmpdel-player-changed-hook))))
  60. (dolist (hook hooks)
  61. (add-hook hook refresh-fn))
  62. (add-hook 'kill-buffer-hook
  63. (lambda () (dolist (hook hooks) (remove-hook hook refresh-fn)))
  64. nil t))))
  65. ;;; Public functions
  66. ;;;###autoload
  67. (defun mpdel-playlist-open ()
  68. "Display the current playlist."
  69. (interactive)
  70. (mpdel-core-open 'current-playlist))
  71. (define-key mpdel-core-map (kbd "l") #'mpdel-playlist-open)
  72. ;;;###autoload
  73. (defun mpdel-playlist-open-stored-playlist ()
  74. "Ask for a stored playlist and open it."
  75. (interactive)
  76. (libmpdel-funcall-on-stored-playlist #'mpdel-core-open))
  77. (defun mpdel-playlist-play ()
  78. "Start playing the song at point."
  79. (interactive)
  80. (if (derived-mode-p 'mpdel-playlist-current-playlist-mode)
  81. (libmpdel-play-song (navigel-entity-at-point))
  82. (mpdel-core-insert-current-playlist)))
  83. (defun mpdel-playlist-move-up ()
  84. "Move selected songs up in the current playlist."
  85. (interactive)
  86. (let ((songs (mpdel-core-selected-entities)))
  87. (when songs
  88. (libmpdel-playlist-move-up songs))))
  89. (defun mpdel-playlist-move-down ()
  90. "Move selected songs down in the current playlist."
  91. (interactive)
  92. (let ((songs (mpdel-core-selected-entities)))
  93. (when songs
  94. (libmpdel-playlist-move-down songs))))
  95. (defun mpdel-playlist-save ()
  96. "Save current playlist into a new stored playlist.
  97. Ask for stored playlist name."
  98. (interactive)
  99. (if (libmpdel-current-playlist-p navigel-entity)
  100. (call-interactively #'libmpdel-playlist-save)
  101. (user-error "You can only save from the current playlist")))
  102. ;;; Modes
  103. (defvar mpdel-playlist-mode-map
  104. (let ((map (make-sparse-keymap)))
  105. map)
  106. "Keybindings for `mpdel-playlist-mode'.")
  107. (define-derived-mode mpdel-playlist-mode mpdel-tablist-mode "MPDel Playlist"
  108. (add-hook 'navigel-init-done-hook #'mpdel-playlist--register-to-hooks nil t))
  109. (defvar mpdel-playlist-current-playlist-mode-map
  110. (let ((map (make-sparse-keymap)))
  111. (define-key map (kbd "<M-up>") #'mpdel-playlist-move-up)
  112. (define-key map (kbd "<M-down>") #'mpdel-playlist-move-down)
  113. (define-key map (kbd "C-x C-s") #'mpdel-playlist-save)
  114. (define-key map (kbd "P") #'mpdel-playlist-play)
  115. map)
  116. "Keybindings for `mpdel-playlist-current-playlist-mode'.")
  117. (define-derived-mode mpdel-playlist-current-playlist-mode mpdel-playlist-mode "MPDel Current playlist"
  118. "Major mode to display the current playlist."
  119. (add-hook 'navigel-changed-hook #'mpdel-playlist--highlight nil t))
  120. (defvar mpdel-playlist-stored-playlist-mode-map
  121. (let ((map (make-sparse-keymap)))
  122. map)
  123. "Keybindings for `mpdel-playlist-stored-playlist-mode'.")
  124. (define-derived-mode mpdel-playlist-stored-playlist-mode mpdel-playlist-mode "MPDel Stored playlist"
  125. "Major mode to display a stored playlist.")
  126. (provide 'mpdel-playlist)
  127. ;;; mpdel-playlist.el ends here