aboutsummaryrefslogtreecommitdiff
path: root/emms-playing-time.el
blob: 5a674b6fd0f99a74c6722ade344ed8904671df02 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
;;; emms-playing-time.el --- Display emms playing time on mode line  -*- lexical-binding: t; -*-

;; Copyright (C) 2005-2021  Free Software Foundation, Inc.

;; Author: William Xu <william.xwl@gmail.com>, Yoni Rabkin (yrk@gnu.org)

;; This file is part of EMMS.

;; EMMS is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 3, or (at your option)
;; any later version.
;;
;; EMMS is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with EMMS; if not, write to the Free Software Foundation,
;; Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.

;;; Commentary:

;; Display playing time on mode line, it looks like: 01:32/04:09.

;; Put this file into your load-path and the following into your
;; ~/.emacs:
;;     (require 'emms-playing-time)
;;     (emms-playing-time 1)

;; Note: `(emms-playing-time -1)' will disable emms-playing-time module
;; completely, and is not recommended. (since some other emms modules
;; may rely on it, such as `emms-lastfm.el')

;; Instead, to toggle displaying playing time on mode line, one could
;; call `emms-playing-time-enable-display' and
;; `emms-playing-time-disable-display'."

;;; Code:

(require 'cl-lib)
(require 'emms-info)
(require 'emms-player-simple)

;;; Customizations

(defgroup emms-playing-time nil
  "Playing-time module for EMMS."
  :group 'emms)

(defcustom emms-playing-time-display-short-p nil
  "Non-nil will only display elapsed time.
e.g., display 02:37 instead of 02:37/05:49."
  :type 'boolean)

(defcustom emms-playing-time-display-format " %s "
  "Format used for displaying playing time."
  :type 'string)

(defcustom emms-playing-time-style 'time
  "Style used for displaying playing time.
Valid styles are `time' (e.g., 01:30/4:20),
 `bar' (e.g., [===>  ]),
and `downtime' (e.g. -03:58)."
  :type 'symbol)

(defcustom emms-playing-time-resume-from-last-played nil
  "If set to Non-nil, emms will resume / seek to
 the last playing time when the track is started again."
  :type 'boolean)


;;; Emms Playing Time

(define-obsolete-variable-alias 'emms-playing-time-display-p
  'emms-playing-time-display-mode "Apr 2021")
(defvar emms-playing-time-display-mode)

(defvar emms-playing-time 0
  "Time elapsed in current track.")

(defvar emms-playing-time-string "")

(defvar emms-playing-time-display-timer nil)

(define-obsolete-variable-alias 'emms-playing-time-p
  'emms-playing-time-mode "Apr 2021")

(defun emms-playing-time-start ()
  "Get ready for display playing time."
  (setq emms-playing-time 0)
  (unless emms-playing-time-display-timer
    (setq emms-playing-time-display-timer
	  (run-at-time t 1 #'emms-playing-time-display))))

(defun emms-playing-time-stop ()
  "Remove playing time on the mode line."
  (if (or (not emms-player-paused-p)
	  emms-player-stopped-p)
      (progn
	(setq emms-playing-time-string "")
	(force-mode-line-update)))
  (emms-cancel-timer emms-playing-time-display-timer)
  (setq emms-playing-time-display-timer nil))

(defun emms-playing-time-pause ()
  "Pause playing time."
  (if emms-player-paused-p
      (emms-playing-time-stop)
    (unless emms-playing-time-display-timer
      (setq emms-playing-time-display-timer
	    (run-at-time t 1 #'emms-playing-time-display)))))

(defun emms-playing-time-seek (sec)
  "Seek forward or backward SEC playing time."
  (setq emms-playing-time (+ emms-playing-time sec))
  (when (< emms-playing-time 0)		; back to start point
    (setq emms-playing-time 0)))

(defun emms-playing-time-set (sec)
  "Set the playing time to SEC."
  (setq emms-playing-time sec)
  (when (< emms-playing-time 0)		; back to start point
    (setq emms-playing-time 0)))

(defun emms-playing-time (arg)
  (declare (obsolete emms-playing-time-mode "Apr 2021"))
  (emms-playing-time-mode (if (and arg (> arg 0)) 1 -1)))

(defun emms-playing-time-track-reset ()
  (emms-track-set (emms-playlist-current-selected-track)
		  'playing-time nil))

(defun emms-playing-time-maybe-seek-to-last-played ()
  (when-let ((last-playing-time
	      (emms-track-get (emms-playlist-current-selected-track)
			      'playing-time)))
    (emms-seek-to last-playing-time)))

(define-minor-mode emms-playing-time-mode
  "Turn on emms playing time if ARG is positive, off otherwise.

Note: `(emms-playing-time -1)' will disable emms-playing-time
module completely, and is not recommended. (since some other emms
modules may rely on it, such as `emms-lastfm.el')

Instead, to toggle displaying playing time on mode line, one
could call `emms-playing-time-enable-display' and
`emms-playing-time-disable-display'."
  :global t
  (if emms-playing-time-mode
      (progn
	;; FIXME: Maybe we shouldn't set this here, and instead the users
        ;; should call `emms-playing-time-display-mode' if that's what
        ;; they want.
	(setq emms-playing-time-display-mode t)
	(emms-playing-time-mode-line)
	(add-hook 'emms-player-started-hook       #'emms-playing-time-start)
	(add-hook 'emms-player-stopped-hook       #'emms-playing-time-stop)
	(add-hook 'emms-player-finished-hook
		  #'emms-playing-time-track-reset)
	(add-hook 'emms-player-finished-hook      #'emms-playing-time-stop)
	(add-hook 'emms-player-paused-hook        #'emms-playing-time-pause)
	(add-hook 'emms-player-seeked-functions   #'emms-playing-time-seek)
	(add-hook 'emms-player-time-set-functions #'emms-playing-time-set)
	(when emms-playing-time-resume-from-last-played
	  (add-hook 'emms-player-started-hook
		    #'emms-playing-time-maybe-seek-to-last-played)))
    (setq emms-playing-time-display-mode nil)
    (emms-playing-time-stop)
    (emms-playing-time-restore-mode-line)
    (remove-hook 'emms-player-started-hook       #'emms-playing-time-start)
    (remove-hook 'emms-player-stopped-hook       #'emms-playing-time-stop)
    (remove-hook 'emms-player-finished-hook      #'emms-playing-time-stop)
    (remove-hook 'emms-player-finished-hook
		 #'emms-playing-time-track-reset)
    (remove-hook 'emms-player-paused-hook        #'emms-playing-time-pause)
    (remove-hook 'emms-player-seeked-functions   #'emms-playing-time-seek)
    (remove-hook 'emms-player-time-set-functions #'emms-playing-time-set)
    (remove-hook 'emms-player-started-hook
		 #'emms-playing-time-maybe-seek-to-last-played)))

;;;###autoload
(define-minor-mode emms-playing-time-display-mode
  "Minor mode to display playing time on mode line."
  :global t)

;;;###autoload
(defun emms-playing-time-enable-display ()
  "Display playing time on mode line."
  (declare (obsolete emms-playing-time-display-mode "Apr 2021"))
  (interactive)
  (setq emms-playing-time-display-mode t))

;;;###autoload
(defun emms-playing-time-disable-display ()
  "Remove playing time from mode line."
  (declare (obsolete emms-playing-time-display-mode "Apr 2021"))
  (interactive)
  (setq emms-playing-time-display-mode nil))

(defun emms-playing-time-display ()
  "Display playing time on the mode line."
  (setq emms-playing-time (round (1+ emms-playing-time)))
  (emms-track-set (emms-playlist-current-selected-track)
		  'playing-time emms-playing-time)
  (setq emms-playing-time-string
        (if (null emms-playing-time-display-mode)
            ""
          (let* ((min (/ emms-playing-time 60))
                 (sec (% emms-playing-time 60))
                 (total-playing-time
                  (or (emms-track-get
                       (emms-playlist-current-selected-track)
                       'info-playing-time)
                      0))
                 (total-min-only (/ total-playing-time 60))
                 (total-sec-only (% total-playing-time 60))
                 (string
	          (cl-case emms-playing-time-style
	            ((downtime)         ; `downtime' style
	             (emms-replace-regexp-in-string
                      " " "0"
                      (if (or emms-playing-time-display-short-p
                              ;; unable to get total playing-time
                              (eq total-playing-time 0))
                          (format "%2d:%2d" min sec)
                        (format "-%2d:%2d"
			        (/ (- total-playing-time emms-playing-time) 60)
			        (% (- total-playing-time sec) 60)))))
		    ((bar)              ; `bar' style
		     (if (zerop total-playing-time)
		         "[==>........]"
                       (let (;; percent based on 10
                             (percent (/ (* emms-playing-time 10)
                                         total-playing-time)))
                         (concat "["
                                 (make-string percent ?=)
                                 ">"
                                 (make-string (- 10 percent) ?\s)
                                 "]"))))
                    (t                  ; `time' style
                     (emms-replace-regexp-in-string
                      " " "0"
                      (if (or emms-playing-time-display-short-p
                              ;; unable to get total playing-time
                              (eq total-playing-time 0))
                          (format "%2d:%2d" min sec)
                        (format "%2d:%2d/%2s:%2s"
                                min sec total-min-only total-sec-only)))))))
            (format emms-playing-time-display-format string))))
  (force-mode-line-update))

(defun emms-playing-time-mode-line ()
  "Add playing time to the mode line."
  (or global-mode-string (setq global-mode-string '("")))
  (unless (member 'emms-playing-time-string
		  global-mode-string)
    (setq global-mode-string
	  (append global-mode-string
		  '(emms-playing-time-string)))))

(defun emms-playing-time-restore-mode-line ()
  "Restore the mode line."
  (setq global-mode-string
	(remove 'emms-playing-time-string global-mode-string))
  (force-mode-line-update))

(provide 'emms-playing-time)

;;; emms-playing-time.el ends here