emms-state.el 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. ;;; emms-state.el --- Display track description and playing time in the mode line
  2. ;; Copyright © 2015, 2016 Alex Kost
  3. ;; Author: Alex Kost <alezost@gmail.com>
  4. ;; Created: 22 Jan 2015
  5. ;; Version: 0.2
  6. ;; Package-Requires: ((emms "0"))
  7. ;; URL: https://github.com/alezost/emms-state.el
  8. ;; Keywords: emms
  9. ;; This program is free software; you can redistribute it and/or modify
  10. ;; it under the terms of the GNU General Public License as published by
  11. ;; the Free Software Foundation, either version 3 of the License, or
  12. ;; (at your option) any later version.
  13. ;; This program is distributed in the hope that it will be useful,
  14. ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. ;; GNU General Public License for more details.
  17. ;; You should have received a copy of the GNU General Public License
  18. ;; along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. ;;; Commentary:
  20. ;; This package provides a minor mode (`emms-state-mode') for displaying
  21. ;; description and playing time of the current track (played by EMMS) in
  22. ;; the mode line. A typical mode line string would look like this (it
  23. ;; may be configured with `emms-state-mode-line-string' variable):
  24. ;;
  25. ;; ⏵ 1:19(5:14) Chopin - Waltz in a-moll, Op.34 No.2
  26. ;; To install the package manually, add the following to your init file:
  27. ;;
  28. ;; (add-to-list 'load-path "/path/to/emms-state-dir")
  29. ;; (autoload 'emms-state-mode "emms-state" nil t)
  30. ;; This package is intended to be used instead of `emms-mode-line' and
  31. ;; `emms-playing-time' modes and it is strongly recommended to disable
  32. ;; these modes before enabling `emms-state-mode' (keep in mind that
  33. ;; these modes are enabled automatically if you use `emms-all' or
  34. ;; `emms-devel' setup function).
  35. ;;; Code:
  36. (require 'emms-mode-line)
  37. (require 'emms-playing-time)
  38. (defgroup emms-state nil
  39. "Display track description and playing time in the mode line."
  40. :group 'emms)
  41. (defface emms-state-title
  42. '((t nil))
  43. "Face used for the title of the current track."
  44. :group 'emms-state)
  45. (defface emms-state-total-playing-time
  46. '((t :inherit font-lock-constant-face))
  47. "Face used for the total playing time."
  48. :group 'emms-state)
  49. (defface emms-state-current-playing-time
  50. '((t :inherit font-lock-variable-name-face))
  51. "Face used for the current playing time."
  52. :group 'emms-state)
  53. (defcustom emms-state-play "⏵"
  54. "String used to denote the 'play' state."
  55. :type 'string
  56. :group 'emms-state)
  57. (defcustom emms-state-pause "⏸"
  58. "String used to denote the 'pause' state."
  59. :type 'string
  60. :group 'emms-state)
  61. (defcustom emms-state-stop "⏹"
  62. "String used to denote the 'stop' state."
  63. :type 'string
  64. :group 'emms-state)
  65. (defvar emms-state-mode-line-string
  66. '(" " emms-state " "
  67. (emms-state-current-playing-time
  68. (:propertize emms-state-current-playing-time
  69. face emms-state-current-playing-time))
  70. (emms-state-total-playing-time
  71. ("("
  72. (:propertize emms-state-total-playing-time
  73. face emms-state-total-playing-time)
  74. ")"))
  75. emms-mode-line-string)
  76. "Mode line string with the EMMS info.")
  77. (put 'emms-state-mode-line-string 'risky-local-variable t)
  78. (defvar emms-state nil
  79. "Mode line construct for the state of the current EMMS process.")
  80. (defvar emms-state-current-playing-time nil
  81. "Mode line construct for the current playing time of the track.")
  82. (defvar emms-state-total-playing-time nil
  83. "Mode line construct for the total playing time of the track.")
  84. (defun emms-state-format-time (time)
  85. "Convert TIME into a human readable string.
  86. TIME is a number of seconds."
  87. (let* ((minutes (/ time 60))
  88. (seconds (% time 60))
  89. (hours (/ minutes 60))
  90. (minutes (% minutes 60)))
  91. (if (zerop hours)
  92. (format "%d:%02d" minutes seconds)
  93. (format "%d:%02d:%02d" hours minutes seconds))))
  94. (defun emms-state ()
  95. "Return string displaying the state of the current EMMS process."
  96. (if emms-player-playing-p
  97. (if emms-player-paused-p
  98. emms-state-pause
  99. emms-state-play)
  100. emms-state-stop))
  101. (defun emms-state-set-state ()
  102. "Update the value of `emms-state' variable."
  103. (setq emms-state (emms-state)))
  104. (defun emms-state-set-total-playing-time (&optional _)
  105. "Update the value of `emms-state-total-playing-time' variable.
  106. Optional argument is used to be compatible with
  107. `emms-track-updated-functions'."
  108. (let ((time (emms-track-get (emms-playlist-current-selected-track)
  109. 'info-playing-time)))
  110. (setq emms-state-total-playing-time
  111. (and time (emms-state-format-time time)))))
  112. (defun emms-state-set-current-playing-time ()
  113. "Update the value of `emms-state-current-playing-time' variable."
  114. (setq emms-state-current-playing-time
  115. (unless (zerop emms-playing-time)
  116. (emms-state-format-time emms-playing-time))))
  117. ;;; Playing time functions for hooks
  118. (defun emms-state-timer-start ()
  119. "Start timer for the current playing time."
  120. (unless emms-playing-time-display-timer
  121. (setq emms-playing-time-display-timer
  122. (run-at-time t 1 'emms-state-playing-time-step))))
  123. (defun emms-state-timer-stop ()
  124. "Stop timer for the current playing time."
  125. (emms-cancel-timer emms-playing-time-display-timer)
  126. (setq emms-playing-time-display-timer nil)
  127. (emms-state-playing-time-update))
  128. (defun emms-state-playing-time-step ()
  129. "Shift the current playing time by one second."
  130. (setq emms-playing-time (round (1+ emms-playing-time)))
  131. (emms-state-playing-time-update))
  132. (defun emms-state-playing-time-update ()
  133. "Update the current playing time in the mode line."
  134. (emms-state-set-current-playing-time)
  135. (force-mode-line-update))
  136. (defun emms-state-playing-time-start ()
  137. "Start displaying the current playing time."
  138. (setq emms-playing-time 0)
  139. (emms-state-timer-start))
  140. (defun emms-state-playing-time-stop ()
  141. "Stop displaying the current playing time."
  142. (setq emms-playing-time 0)
  143. (emms-state-timer-stop))
  144. (defun emms-state-playing-time-pause ()
  145. "Pause displaying the current playing time."
  146. (if emms-player-paused-p
  147. (emms-state-timer-stop)
  148. (emms-state-timer-start)))
  149. (defalias 'emms-state-playing-time-seek 'emms-playing-time-seek)
  150. (defalias 'emms-state-playing-time-set 'emms-playing-time-set)
  151. ;;; Commands
  152. ;;;###autoload
  153. (define-minor-mode emms-state-mode
  154. "Minor mode for displaying some EMMS info in the mode line.
  155. This mode is intended to be a substitution for `emms-mode-line'
  156. and `emms-playing-time'."
  157. :global t
  158. (or global-mode-string (setq global-mode-string '("")))
  159. (let (hook-action activep)
  160. (if emms-state-mode
  161. ;; Turn on.
  162. (progn
  163. (setq hook-action 'add-hook
  164. activep t)
  165. (when emms-player-playing-p (emms-mode-line-alter))
  166. (emms-state-toggle-mode-line 1))
  167. ;; Turn off.
  168. (setq hook-action 'remove-hook
  169. activep nil)
  170. (emms-state-playing-time-stop)
  171. (emms-mode-line-restore-titlebar)
  172. (emms-state-toggle-mode-line -1))
  173. (force-mode-line-update)
  174. (setq emms-mode-line-active-p activep
  175. emms-playing-time-p activep
  176. emms-playing-time-display-p activep)
  177. (funcall hook-action 'emms-track-updated-functions
  178. 'emms-mode-line-alter)
  179. (funcall hook-action 'emms-player-started-hook
  180. 'emms-mode-line-alter)
  181. (funcall hook-action 'emms-track-updated-functions
  182. 'emms-state-set-total-playing-time)
  183. (funcall hook-action 'emms-player-started-hook
  184. 'emms-state-set-total-playing-time)
  185. (funcall hook-action 'emms-player-started-hook
  186. 'emms-state-set-state)
  187. (funcall hook-action 'emms-player-stopped-hook
  188. 'emms-state-set-state)
  189. (funcall hook-action 'emms-player-finished-hook
  190. 'emms-state-set-state)
  191. (funcall hook-action 'emms-player-paused-hook
  192. 'emms-state-set-state)
  193. (funcall hook-action 'emms-player-started-hook
  194. 'emms-state-playing-time-start)
  195. (funcall hook-action 'emms-player-stopped-hook
  196. 'emms-state-playing-time-stop)
  197. (funcall hook-action 'emms-player-finished-hook
  198. 'emms-state-playing-time-stop)
  199. (funcall hook-action 'emms-player-paused-hook
  200. 'emms-state-playing-time-pause)
  201. (funcall hook-action 'emms-player-seeked-functions
  202. 'emms-state-playing-time-seek)
  203. (funcall hook-action 'emms-player-time-set-functions
  204. 'emms-state-playing-time-set)))
  205. (defun emms-state-toggle-mode-line (&optional arg)
  206. "Toggle displaying EMMS status info in the mode line.
  207. With prefix argument ARG, enable status info if ARG is positive,
  208. disable otherwise.
  209. Unlike `emms-state-mode', this function will just remove
  210. `emms-state-mode-line-string' from `global-mode-string'. The
  211. playing timer will still go on."
  212. (interactive "P")
  213. (if (or (and (null arg)
  214. (not (memq 'emms-state-mode-line-string
  215. global-mode-string)))
  216. (and arg
  217. (> (prefix-numeric-value arg) 0)))
  218. (add-to-list 'global-mode-string
  219. 'emms-state-mode-line-string
  220. 'append)
  221. (setq global-mode-string
  222. (remove 'emms-state-mode-line-string
  223. global-mode-string)))
  224. (force-mode-line-update))
  225. (provide 'emms-state)
  226. ;;; emms-state.el ends here