summaryrefslogtreecommitdiffhomepage
path: root/lib/media/jao-emms-info-track.el
blob: 839ef7305bfc923ebcecbc2affa5ba270e2662dd (plain)
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
;; jao-emms-info-track.el -- utilities to show tracks -*- lexical-binding:t; -*-

;; Copyright (C) 2009, 2010, 2013, 2017, 2020, 2021 Jose Antonio Ortega Ruiz

;; Author: Jose Antonio Ortega Ruiz <jao@gnu.org>
;; Start date: Sat Jul 04, 2009 13:47

;; This file 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 of the License, or
;; (at your option) any later version.

;; This file 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 this program.  If not, see <http://www.gnu.org/licenses/>.

;;; Code:

(require 'emms)
(require 'emms-tag-editor)
(require 'emms-player-mpd)
(require 'jao-osd)
(require 'jao-emms)
(require 'jao-minibuffer)

(defgroup jao-emms-faces nil "Faces"
  :group 'faces
  :group 'jao-emms)

(defface jao-emms-font-lock-album '((t (:foreground "lightgoldenrod2")))
  "Album name in EMMS track message."
  :group 'jao-emms-faces)

(defface jao-emms-font-lock-track '((t (:bold t)))
  "Track number in EMMS track message."
  :group 'jao-emms-faces)

(defface jao-emms-font-lock-title '((t (:foreground "dodgerblue2")))
  "Track title in EMMS track message."
  :group 'jao-emms-faces)

(defface jao-emms-font-lock-artist '((t (:foreground "dodgerblue3")))
  "Artist name in EMMS track message."
  :group 'jao-emms-faces)

(defcustom jao-emms-show-osd-p nil
  "Whether to show osd notices on track change"
  :group 'jao-emms)



(defun jao-emms-info-track-stream (track)
  "Return track info for streams"
  (let ((name (emms-track-name track))
        (title (or (emms-track-get track 'title nil)
                   (car (emms-track-get track 'metadata nil))
                   (car (split-string (shell-command-to-string "mpc status")
                                      "\n")))))
    (format "♪ %s (%s)" (or title "") (if title (emms-track-type track) name))))

(defsubst jao--put-face (str face)
  (put-text-property 0 (length str) 'face face str)
  str)

(defun jao-emms--to-number (x)
  (or (and (numberp x) x)
      (and (stringp x)
           (string-match "\\`\\(:?[0-9]+\\)" x)
           (string-to-number (match-string 1 x)))))

(defun jao-emms--fmt-time (x suffix)
  (if x (format "%02d:%02d%s" (/ x 60) (mod x 60) (or suffix "")) ""))

(defun jao-emms--fmt-song-times (track lapsed pre post)
  (if lapsed
      (let ((time (when track (emms-track-get track 'info-playing-time))))
        (format "%s%s%s%s"
                (or pre "")
                (jao-emms--fmt-time lapsed (when time "/"))
                (jao-emms--fmt-time time "")
                (or post "")))
    ""))

(defun jao-emms-info-track-file (track &optional lapsed plen titlesep)
  "Return a description of the current track."
  (let* ((no (jao-emms--to-number (emms-track-get track 'info-tracknumber "0")))
         (time (emms-track-get track 'info-playing-time))
         (year (emms-track-get track 'info-year))
         (year (if year (format " (%s)" year) ""))
         (artist (emms-track-get track 'info-artist ""))
         (composer (emms-track-get track 'info-composer nil))
         (title (emms-track-get track 'info-title ""))
         (album (emms-track-get track 'info-album))
         (last-played (or (emms-track-get track 'last-played) '(0 0 0)))
         (play-count (or (emms-track-get track 'play-count) 0))
         (playlength (if plen (format "/%02d" (string-to-number plen)) "")))
    (if (or (not title) (not album))
        (emms-track-simple-description track)
      (format "🎵 %s%s%s%s%s%s%s"
              (jao--put-face (if (zerop no) "" (format "%02d%s " no playlength))
                             'jao-emms-font-lock-track)
              (jao--put-face title
                             'jao-emms-font-lock-title)
              (or titlesep " ")
              (jao-emms--fmt-song-times track lapsed "[" "] ")
              (jao--put-face artist 'jao-emms-font-lock-artist)
              (jao--put-face (if composer (format " [%s]" composer) "")
                             'jao-emms-font-lock-artist)
              (jao--put-face (if album
                                 (format " (%s%s)" album year)
                               (format "%s *") year)
                             'jao-emms-font-lock-album)))))

;;;###autoload
(defun jao-emms-info-track-description (track &optional lapsed plen tsep)
  (if (memq (emms-track-type track) '(streamlist url))
      (jao-emms-info-track-stream track)
    (jao-emms-info-track-file track lapsed plen tsep)))

;;;###autoload
(defun jao-emms-toggle-osd ()
  (interactive)
  (setq jao-emms-show-osd-p (not jao-emms-show-osd-p))
  (message "Emms OSD %s" (if jao-emms-show-osd-p "enabled" "disabled")))

(defvar jao-emms-show-icon nil)

(defun jao-emms--with-mpd-track (callback)
  (emms-player-mpd-get-status
   nil
   (lambda (_ st)
     (let* ((lapsed (jao-emms--to-number (cdr (assoc "time" st))))
            (plen (cdr (assoc "playlistlength" st)))
            (song (jao-emms--to-number (cdr (assoc "song" st))))
            (track (emms-playlist-current-selected-track)))
       (when (and track song)
         (emms-track-set track 'info-tracknumber (format "%d" (1+ song))))
       (funcall callback track lapsed plen)))))

;;;###autoload
(defun jao-emms-show-osd ()
  (interactive)
  (jao-emms--with-mpd-track
   (lambda (track lapsed play-len)
     (let* ((sep "~~~~~")
            (s (jao-emms-info-track-description track lapsed play-len sep))
            (s (substring-no-properties s 2))
            (cs (split-string s sep)))
       (jao-notify (car cs) (cadr cs) jao-emms-show-icon)))))

(defun jao-emms-show-osd-hook ()
  (interactive)
  (when jao-emms-show-osd-p (jao-emms-show-osd)))

(defun jao-emms-install-id3v2 ()
  (add-to-list 'emms-tag-editor-tagfile-functions
               '("mp3" "id3v2" ((info-artist      . "-a")
                                (info-title       . "-t")
                                (info-album       . "-A")
                                (info-tracknumber . "-T")
                                (info-year        . "-y")
                                (info-genre       . "-g")
                                (info-composer    . "--TCOM")
                                (info-note        . "-c")))))

(defvar jao-emms-echo-string "")

(defun jao-emms--echo-string (v)
  (setq jao-emms-echo-string v)
  (jao-minibuffer-refresh))

(defun jao-emms-update-echo-string (&optional existing-track)
  (if emms-player-playing-p
      (jao-emms--with-mpd-track
       (lambda (track lapsed play-len)
         (jao-emms--echo-string
          (cond ((and emms-player-paused-p existing-track)
                 (format "(%s/%s)"
                         (emms-track-get existing-track 'info-tracknumber)
                         play-len))
                (emms-player-paused-p "")
                (t (jao-emms-info-track-description track nil play-len))))))
    (jao-emms--echo-string "")))

(defun jao-emms-enable-minibuffer (minibuffer-order)
  (jao-minibuffer-add-variable 'jao-emms-echo-string minibuffer-order)
  (dolist (h '(emms-track-updated-functions
               emms-player-finished-hook
               emms-player-stopped-hook
               emms-player-started-hook
               emms-player-paused-hook))
    (add-hook h #'jao-emms-update-echo-string)))

;;;###autoload
(defun jao-emms-info-setup (&optional minibuffer show-osd show-echo-line id3)
  (setq emms-track-description-function 'jao-emms-info-track-description)
  (setq jao-emms-show-osd-p show-osd)
  (add-hook 'emms-player-started-hook 'jao-emms-show-osd-hook)
  (when minibuffer (jao-emms-enable-minibuffer minibuffer))
  (unless show-echo-line
    (eval-after-load 'emms-player-mpd
      '(remove-hook 'emms-player-started-hook 'emms-player-mpd-show)))
  (when id3 (jao-emms-install-id3v2))
  (ignore-errors (emms-player-mpd-connect)))


(provide 'jao-emms-info-track)
;;; jao-emms-info-track.el ends here