al-emms.el 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. ;;; al-emms.el --- Additional functionality for EMMS
  2. ;; Copyright © 2013–2016, 2019 Alex Kost
  3. ;; This program is free software; you can redistribute it and/or modify
  4. ;; it under the terms of the GNU General Public License as published by
  5. ;; the Free Software Foundation, either version 3 of the License, or
  6. ;; (at your option) any later version.
  7. ;;
  8. ;; This program is distributed in the hope that it will be useful,
  9. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. ;; GNU General Public License for more details.
  12. ;;
  13. ;; You should have received a copy of the GNU General Public License
  14. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. ;;; Code:
  16. (require 'emms)
  17. (defun al/emms-seek-forward (seconds)
  18. "Seek by SECONDS forward.
  19. Interactively, define SECONDS with a numeric prefix."
  20. (interactive "p")
  21. (when emms-player-playing-p
  22. (emms-player-seek seconds)))
  23. (defun al/emms-seek-backward (seconds)
  24. "Seek by SECONDS backward.
  25. Interactively, define SECONDS with a numeric prefix."
  26. (interactive "p")
  27. (al/emms-seek-forward (- seconds)))
  28. (defun al/emms-seek-to (seconds)
  29. "Seek the current player to SECONDS.
  30. Interactively, prompt for the number of minutes.
  31. With prefix, prompt for the number of seconds."
  32. (interactive
  33. (list (if current-prefix-arg
  34. (read-number "Seconds to seek to: ")
  35. (* 60 (read-number "Minutes to seek to: ")))))
  36. (emms-seek-to seconds))
  37. (defun al/emms-source-add-and-play (source &rest args)
  38. "Add the tracks of SOURCE to EMMS playlist and play the first one."
  39. (with-current-emms-playlist
  40. (goto-char (point-max))
  41. (let ((first-new-track (point)))
  42. (apply #'emms-playlist-insert-source source args)
  43. (emms-playlist-select first-new-track)))
  44. (emms-stop)
  45. (emms-start))
  46. (defun al/emms-first ()
  47. "Start playing the first track in the EMMS playlist."
  48. (interactive)
  49. (when emms-player-playing-p
  50. (emms-stop))
  51. (emms-playlist-current-select-first)
  52. (emms-start))
  53. (declare-function al/emms-mpv-playing-radio? "al-emms-mpv" ())
  54. (declare-function al/emms-mpv-show-radio-description "al-emms-mpv" ())
  55. (declare-function al/emms-mpv-show-metadata "al-emms-mpv" ())
  56. ;;;###autoload
  57. (defun al/emms-show (&optional arg)
  58. "Describe the current EMMS track in the minibuffer.
  59. If ARG is specified, show metadata of the track."
  60. (interactive "P")
  61. (require 'al-emms-mpv)
  62. (cond (arg
  63. (al/emms-mpv-show-metadata))
  64. ((al/emms-mpv-playing-radio?)
  65. (al/emms-mpv-show-radio-description))
  66. (t
  67. (message (format emms-show-format
  68. (emms-track-description
  69. (emms-playlist-current-selected-track)))))))
  70. ;;; Track description
  71. (defvar al/emms-track-description-use-time
  72. (require 'emms-state nil t)
  73. "If non-nil, `al/emms-full-track-description' adds playing time
  74. to the track description.")
  75. (declare-function emms-state-format-time "emms-state" (time))
  76. (defun al/emms-full-track-description (track)
  77. "Return a full description of TRACK.
  78. Intended to be used for `emms-track-description-function'."
  79. (let ((artist (emms-track-get track 'info-artist))
  80. (title (emms-track-get track 'info-title))
  81. (time (and al/emms-track-description-use-time
  82. (emms-track-get track 'info-playing-time)))
  83. (tracknum (emms-track-get track 'info-tracknumber))
  84. (album (emms-track-get track 'info-album))
  85. (year (emms-track-get track 'info-year)))
  86. (let ((name (cond
  87. ((and artist title) (concat artist " – " title))
  88. (title title))))
  89. (if (null name)
  90. (emms-track-simple-description track)
  91. (when tracknum
  92. (setq name (format "%02d. %s" (string-to-number tracknum) name)))
  93. (cond
  94. ((and album year)
  95. (setq name (format "%s [%s – %s]" name year album)))
  96. (year
  97. (setq name (format "%s [%s]" name year)))
  98. (album
  99. (setq name (format "%s [%s]" name album))))
  100. (if time
  101. (concat name " (" (emms-state-format-time time) ")")
  102. name)))))
  103. (defun al/emms-short-track-description (track)
  104. "Return a short description of TRACK suitable for mode-line."
  105. (or (emms-track-get track 'info-title)
  106. (let ((type (emms-track-type track)))
  107. (cond ((eq 'file type)
  108. (file-name-nondirectory (emms-track-name track)))
  109. ((eq 'url type)
  110. (url-file-nondirectory (emms-format-url-track-name
  111. (emms-track-name track))))
  112. (t (concat (symbol-name type)
  113. ": " (emms-track-name track)))))))
  114. ;;; Mode line
  115. (require 'emms-mode-line)
  116. (defvar al/emms-mode-line-song-function
  117. 'al/emms-short-track-description
  118. "Default function used in `al/emms-mode-line-song-string'.")
  119. (defun al/emms-mode-line-song-string ()
  120. "Format the currently playing song.
  121. Intended to be used for `emms-mode-line-mode-line-function'."
  122. (format emms-mode-line-format
  123. (funcall al/emms-mode-line-song-function
  124. (emms-playlist-current-selected-track))))
  125. ;;; Misc
  126. (declare-function wget "wget" t)
  127. ;;;###autoload
  128. (defun al/emms-playlist-wget ()
  129. "Run `wget' on the URL track at point."
  130. (interactive)
  131. (let* ((track (emms-playlist-track-at))
  132. (type (emms-track-get track 'type))
  133. (url (emms-track-get track 'name)))
  134. (unless (eq type 'url)
  135. (user-error "Current track is not of 'url' type."))
  136. (wget url)))
  137. (defvar al/emms-split-track-regexp
  138. (rx (group (+? any))
  139. " - "
  140. (group (+ any)))
  141. "Regexp used by `al/emms-split-track-name'.")
  142. (defun al/emms-split-track-name (name)
  143. "Assuming NAME is \"ARTIST - TITLE\" string, return (ALIST TITLE) list."
  144. (string-match al/emms-split-track-regexp name)
  145. (list (match-string 1 name)
  146. (match-string 2 name)))
  147. (provide 'al-emms)
  148. ;;; al-emms.el ends here