Added mpg123 command-line arguments
[emus.git] / emus.el
diff --git a/emus.el b/emus.el
index e529697..e5f2ea3 100644 (file)
--- a/emus.el
+++ b/emus.el
   "Name of (and, optionally, path to) mpg123 binary."
   :type '(string))
 
   "Name of (and, optionally, path to) mpg123 binary."
   :type '(string))
 
+(defcustom emus-mpg123-args nil
+  "Arguments to pass to mpg123."
+  :type '(repeat string))
+
 (defface emus-artist
 (defface emus-artist
-  '((t :inherit font-lock-string-face :background "#333"))
+  '((((background dark)) :inherit font-lock-string-face :background "#222" :extend t)
+    (t :inherit font-lock-string-face :background "#ddd" :extend t))
   "Face used for artist names in browser.")
 
 (defface emus-album
   "Face used for artist names in browser.")
 
 (defface emus-album
-  '((t :inherit font-lock-constant-face :background "#222"))
+  '((((background dark)) :inherit font-lock-constant-face :background "#111" :extend t)
+    (t :inherit font-lock-constant-face :background "#eee" :extend t))
   "Face used for album names in browser.")
 
 (defface emus-track
   "Face used for album names in browser.")
 
 (defface emus-track
@@ -69,7 +75,7 @@
   "Face used for track titles in browser.")
 
 (defface emus-track-current
   "Face used for track titles in browser.")
 
 (defface emus-track-current
-  '((t :inherit font-lock-keyword-face :inverse-video t))
+  '((t :inherit font-lock-keyword-face :inverse-video t :extend t))
   "Face used for track titles in browser.")
 
 (defface emus-cursor
   "Face used for track titles in browser.")
 
 (defface emus-cursor
@@ -98,6 +104,14 @@ Used to prevent commands from interfering with library construction.")
 (defvar emus-current-volume 100
   "The current playback volume.")
 
 (defvar emus-current-volume 100
   "The current playback volume.")
 
+(defvar emus-current-progress ""
+  "String describing the progress through the current track.")
+
+(defvar emus-progress-enabled t
+  "Current state of progress tracking.
+
+To enable or disable progress tracking, using `emus-toggle-progress-tracking'.
+(Changing the value of this variable will not affect anything.)")
 
 ;;; mpg123 process
 ;;
 
 ;;; mpg123 process
 ;;
@@ -115,10 +129,12 @@ Used to prevent commands from interfering with library construction.")
         emus-process
       (let ((proc
              (make-process :name "emus-process"
         emus-process
       (let ((proc
              (make-process :name "emus-process"
-                           ;; :buffer (get-buffer-create "*emus-process*")
-                           :command `(,emus-mpg123-program "-R"))))
+                           :command `(,emus-mpg123-program
+                                      ,@emus-mpg123-args
+                                      "-R"))))
         (set-process-query-on-exit-flag proc nil)
         (set-process-query-on-exit-flag proc nil)
-        (process-send-string proc "silence\n")
+        (unless emus-progress-enabled
+          (process-send-string proc "silence\n"))
         proc))))
 
 (defun emus--send-cmd-raw (cmd &rest args)
         proc))))
 
 (defun emus--send-cmd-raw (cmd &rest args)
@@ -135,13 +151,29 @@ be used by `emus--load-library'."
   (unless emus--proc-in-use
     (apply #'emus--send-cmd-raw cmd args)))
 
   (unless emus--proc-in-use
     (apply #'emus--send-cmd-raw cmd args)))
 
+(defun emus-kill-process ()
+  "Kill any existing mpg123 process."
+  (let ((emus-process (get-process "emus-process")))
+    (if emus-process
+        (kill-process emus-process))
+    (setq emus-state 'stopped
+          emus--proc-in-use nil
+          emus-tracks nil)))
 
 ;;; Library
 ;;
 
 (defun emus-get-audio-files ()
   "Get all mp3 files in main emus directory."
 
 ;;; Library
 ;;
 
 (defun emus-get-audio-files ()
   "Get all mp3 files in main emus directory."
-  (directory-files-recursively emus-directory ".*\\.mp3"))
+  (mapcar
+   #'expand-file-name
+   (directory-files-recursively emus-directory ".*\\.mp3")))
+
+(defun emus-get-playlist-files ()
+  "Get all m3u files in the main emus music directory."
+  (mapcar
+   #'expand-file-name
+   (directory-files-recursively emus-directory ".*\\.m3u")))
 
 (defun emus-make-track (artist album title filename &optional pos)
   "Create an object representing an emus track.
 
 (defun emus-make-track (artist album title filename &optional pos)
   "Create an object representing an emus track.
@@ -149,7 +181,7 @@ ARTIST, ALBUM and TITLE are used to describe the track, FILENAME
 refers to the mp3 file containing the track.  If non-nil, POS
 specifies the position of the record representing this track in the
 emus browser buffer."
 refers to the mp3 file containing the track.  If non-nil, POS
 specifies the position of the record representing this track in the
 emus browser buffer."
-  (vector artist album title filename pos))
+  (list artist album title filename pos))
 
 (defun emus-track-artist (track)
   "The artist corresponding to TRACK."
 
 (defun emus-track-artist (track)
   "The artist corresponding to TRACK."
@@ -173,7 +205,7 @@ emus browser buffer."
 
 (defun emus-set-track-browser-pos (track pos)
   "Set the location of the browser buffer record corresponding to TRACK to POS."
 
 (defun emus-set-track-browser-pos (track pos)
   "Set the location of the browser buffer record corresponding to TRACK to POS."
-  (aset track 4 pos))
+  (setf (seq-elt track 4) pos))
 
 (defun emus--load-library (then)
   "Initialize the emus track library.
 
 (defun emus--load-library (then)
   "Initialize the emus track library.
@@ -182,10 +214,10 @@ Once the library is initialized, the function THEN is called."
     (setq emus--proc-in-use t)
     (emus--suspend-cp)
     (setq emus-state 'stopped)
     (setq emus--proc-in-use t)
     (emus--suspend-cp)
     (setq emus-state 'stopped)
+    (setq emus-tracks nil)
     (let ((proc (emus-get-process))
           (tagstr "")
           (filenames (emus-get-audio-files)))
     (let ((proc (emus-get-process))
           (tagstr "")
           (filenames (emus-get-audio-files)))
-      (setq emus-tracks nil)
       (set-process-filter proc (lambda (proc string)
                                  (setq tagstr (concat tagstr string))
                                  (when (string-suffix-p "@P 1\n" string)
       (set-process-filter proc (lambda (proc string)
                                  (setq tagstr (concat tagstr string))
                                  (when (string-suffix-p "@P 1\n" string)
@@ -199,6 +231,7 @@ Once the library is initialized, the function THEN is called."
                                      (set-process-filter proc nil)
                                      (setq emus-tracks (reverse emus-tracks))
                                      (emus--sort-tracks)
                                      (set-process-filter proc nil)
                                      (setq emus-tracks (reverse emus-tracks))
                                      (emus--sort-tracks)
+                                     (emus--add-tracks-from-playlist-files)
                                      (unless emus-current-track
                                        (setq emus-current-track (car emus-tracks)))
                                      (funcall then)
                                      (unless emus-current-track
                                        (setq emus-current-track (car emus-tracks)))
                                      (funcall then)
@@ -206,11 +239,14 @@ Once the library is initialized, the function THEN is called."
                                      (setq emus--proc-in-use nil)))))
       (emus--send-cmd-raw "lp" (car filenames)))))
 
                                      (setq emus--proc-in-use nil)))))
       (emus--send-cmd-raw "lp" (car filenames)))))
 
+(defun emus--dump-tracks ()
+    emus-tracks)
+
 (defun emus--make-track-from-tagstr (filename tagstr)
   "Parse TAGSTR to populate the fields of a track corresponding to FILENAME."
 (defun emus--make-track-from-tagstr (filename tagstr)
   "Parse TAGSTR to populate the fields of a track corresponding to FILENAME."
-  (let ((artist "")
-        (album "")
-        (title ""))
+  (let ((artist "Unknown Artist")
+        (album "Unknown Album")
+        (title filename))
     (dolist (line (split-string tagstr "\n"))
       (let ((found-artist (elt (split-string line "@I ID3v2.artist:") 1))
             (found-album (elt (split-string line "@I ID3v2.album:") 1))
     (dolist (line (split-string tagstr "\n"))
       (let ((found-artist (elt (split-string line "@I ID3v2.artist:") 1))
             (found-album (elt (split-string line "@I ID3v2.album:") 1))
@@ -219,26 +255,53 @@ Once the library is initialized, the function THEN is called."
          (found-artist (setq artist found-artist))
          (found-album (setq album found-album))
          (found-title (setq title found-title)))))
          (found-artist (setq artist found-artist))
          (found-album (setq album found-album))
          (found-title (setq title found-title)))))
-    (emus-make-track artist album title filename nil)))
+    (emus-make-track artist album title filename)))
+
+(defun emus--add-tracks-from-playlist-files ()
+  (let ((tracks nil))
+    (dolist (filename (emus-get-playlist-files))
+      (let ((artist "Playlists")
+            (album (file-name-base filename))
+            (title nil)
+            (lines (split-string (with-temp-buffer
+                                   (insert-file-contents filename)
+                                   (buffer-string))
+                                 "\n")))
+        (dolist (line lines)
+          (pcase (string-trim line)
+            ((rx (: string-start
+                    (* space)
+                    "#extinf:"
+                    (* (not ",")) ","
+                    (let display-title (* any))
+                    string-end))
+             (setq title display-title))
+            ((rx (: string-start (* space) "#"))) ;skip other comments
+            ((rx (let filename (+ any)))
+             (setq tracks (cons (emus-make-track artist album (or title filename) filename)
+                                tracks))
+             (setq title nil))))))
+    (setq emus-tracks (append emus-tracks (reverse tracks)))))
 
 (defun emus--sort-tracks ()
   "Sort the library tracks according to artist and album.
 Leaves the track titles unsorted, so they will appear in the order specified
 by the filesystem."
 
 (defun emus--sort-tracks ()
   "Sort the library tracks according to artist and album.
 Leaves the track titles unsorted, so they will appear in the order specified
 by the filesystem."
-  (sort emus-tracks
-        (lambda (r1 r2)
-          (let ((artist1 (emus-track-artist r1))
-                (artist2 (emus-track-artist r2)))
-            (if (string= artist1 artist2)
-                (let ((album1 (emus-track-album r1))
-                      (album2 (emus-track-album r2)))
-                  (string< album1 album2))
-              (string< artist1 artist2))))))
+  (setq emus-tracks
+        (sort emus-tracks
+              (lambda (r1 r2)
+                (let ((artist1 (emus-track-artist r1))
+                      (artist2 (emus-track-artist r2)))
+                  (if (string= artist1 artist2)
+                      (let ((album1 (emus-track-album r1))
+                            (album2 (emus-track-album r2)))
+                        (string< album1 album2))
+                    (string< artist1 artist2)))))))
 
 (defmacro emus--with-library (&rest body)
   "Evaluate BODY with the library initialized."
   `(if emus-tracks
 
 (defmacro emus--with-library (&rest body)
   "Evaluate BODY with the library initialized."
   `(if emus-tracks
-       (progn ,@body)
+       (unless emus--proc-in-use ,@body)
      (emus--load-library
       (lambda () ,@body))))
 
      (emus--load-library
       (lambda () ,@body))))
 
@@ -252,13 +315,13 @@ by the filesystem."
 
 (defun emus--resume-cp ()
   "Resume continuous playback."
 
 (defun emus--resume-cp ()
   "Resume continuous playback."
-  (setq emus-continuous-playback t)
-  (set-process-filter (emus-get-process)
-                      (lambda (_proc string)
-                        (and emus-continuous-playback
-                             (eq emus-state 'playing)
-                             (string-suffix-p "@P 0\n" string)
-                             (emus-play-next)))))
+  (setq emus-continuous-playback t))
+
+(defun emus--timestamp (seconds-total)
+  "Produce a timestamp string representation of SECONDS-TOTAL."
+  (let* ((seconds (truncate (mod seconds-total 60)))
+         (minutes (truncate (/ seconds-total 60))))
+    (format "%02d:%02d" minutes seconds)))
 
 (defun emus-play-track (track)
   "Set TRACK as current and start playing."
 
 (defun emus-play-track (track)
   "Set TRACK as current and start playing."
@@ -267,9 +330,44 @@ by the filesystem."
      (emus-send-cmd "l" (emus-track-file track))
      (setq emus-state 'playing)
      (setq emus-current-track track)
      (emus-send-cmd "l" (emus-track-file track))
      (setq emus-state 'playing)
      (setq emus-current-track track)
+     (setq emus-current-progress (if emus-progress-enabled "" " (progress disabled)"))
+     (set-process-filter
+      (emus-get-process)
+      (lambda (_proc string)
+        (dolist (line (string-split string "\n"))
+          (pcase line
+            ((and "@P 0"
+                  (guard emus-continuous-playback)
+                  (guard (eq emus-state 'playing)))
+             (emus-play-next))
+            ((and (guard emus-progress-enabled)
+                  (rx (: string-start
+                         "@I ICY-META: StreamTitle="
+                         (let str (+ (not ";")))
+                         ";")))
+             (message (concat "Emus: Playing stream " str)))
+            ((and (guard emus-progress-enabled)
+                  (rx (: string-start
+                         "@F "
+                         (+ digit)
+                         " "
+                         (+ digit)
+                         " "
+                         (let left-str (+ (not " ")))
+                         " "
+                         (let right-str (+ any)))))
+             (let* ((left (string-to-number left-str))
+                    (right (string-to-number right-str))
+                    (total (+ left right)))
+               (setq emus-current-progress
+                     (format " %s/%s"
+                             (emus--timestamp left)
+                             (emus--timestamp total)))))
+            ))))
      (emus--update-track old-track)
      (emus--update-track track)
      (emus--update-track old-track)
      (emus--update-track track)
-     (emus--resume-cp))))
+     (emus--resume-cp)
+     (emus-goto-current))))
 
 (defun emus-select-track (track)
   "Set TRACK as current, but do not start playing."
 
 (defun emus-select-track (track)
   "Set TRACK as current, but do not start playing."
@@ -280,7 +378,8 @@ by the filesystem."
      (emus--update-track old-track)
      (emus--update-track track)
      (emus-send-cmd "o")
      (emus--update-track old-track)
      (emus--update-track track)
      (emus-send-cmd "o")
-     (emus--resume-cp))))
+     (emus--resume-cp)
+     (emus-goto-current))))
 
 (defun emus-stop ()
   "Stop playback of the current track."
 
 (defun emus-stop ()
   "Stop playback of the current track."
@@ -398,6 +497,16 @@ If PREV is non-nil, plays the last track of the previous album."
   (interactive)
   (emus-jump -10))
 
   (interactive)
   (emus-jump -10))
 
+(defun emus-jump-1m-forward ()
+  "Jump 1 minute forward in current track."
+  (interactive)
+  (emus-jump 60))
+
+(defun emus-jump-1m-backward ()
+  "Jump 1 minute backward in current track."
+  (interactive)
+  (emus-jump -60))
+
 (defun emus-display-status ()
   "Display the current playback status in the minibuffer."
   (interactive)
 (defun emus-display-status ()
   "Display the current playback status in the minibuffer."
   (interactive)
@@ -406,15 +515,29 @@ If PREV is non-nil, plays the last track of the previous album."
     (concat "Emus: Volume %d%%"
             (pcase emus-state
               ('stopped " [Stopped]")
     (concat "Emus: Volume %d%%"
             (pcase emus-state
               ('stopped " [Stopped]")
-              ('paused " [Paused]")
-              ('playing " [Playing]")
+              ('paused (format " [Paused%s]" emus-current-progress))
+              ('playing (format " [Playing%s]" emus-current-progress))
               (_ ""))
               (_ ""))
-            (if emus-current-track
-                (format " - %.30s (%.20s)"
-                        (emus-track-title emus-current-track)
-                        (emus-track-artist emus-current-track))
-              ""))
-    emus-current-volume)))
+            " %s")
+    emus-current-volume
+    (if emus-current-track
+        (format "- %.30s (%.20s, %.20s)"
+                (emus-track-title emus-current-track)
+                (emus-track-album emus-current-track)
+                (emus-track-artist emus-current-track))
+      ""))))
+
+(defun emus-toggle-progress-tracking ()
+  "Enable/disable progress tracking."
+  (interactive)
+  (setq emus-progress-enabled (not emus-progress-enabled))
+  (if emus-progress-enabled
+      (progn
+        (emus-send-cmd "progress")
+        (setq emus-current-progress ""))
+    (progn
+      (emus-send-cmd "silence")
+      (setq emus-current-progress " (progress diabled)"))))
 
 
 ;;; Browser
 
 
 ;;; Browser
@@ -431,7 +554,9 @@ and thus requires both artist and album headers."
   (let* ((artist (emus-track-artist track))
          (album (emus-track-album track))
          (title (emus-track-title track))
   (let* ((artist (emus-track-artist track))
          (album (emus-track-album track))
          (title (emus-track-title track))
-         (help-str (format "mouse-1, RET: Play '%.30s' (%.20s)" title artist)))
+         (album-symb (intern (concat artist album)))
+         (help-str (format "mouse-1, RET: Play '%.30s' (%.20s)" title artist))
+         (field (intern album))) ;Allows easy jumping between albums with cursor.
     (when (or prev-track first)
       (unless (equal (emus-track-artist prev-track) artist)
         (insert-text-button
     (when (or prev-track first)
       (unless (equal (emus-track-artist prev-track) artist)
         (insert-text-button
@@ -439,16 +564,22 @@ and thus requires both artist and album headers."
          'action #'emus--click-track
          'follow-link t
          'help-echo help-str
          'action #'emus--click-track
          'follow-link t
          'help-echo help-str
-         'emus-track track)
-        (insert (propertize "\n" 'face 'emus-artist)))
+         'emus-track track
+         'field field)
+        (insert (propertize "\n"
+                            'face 'emus-artist
+                            'field field)))
       (unless (equal (emus-track-album prev-track) album)
         (insert-text-button
          (propertize (concat "  " album) 'face 'emus-album)
          'action #'emus--click-track
          'follow-link t
          'help-echo help-str
       (unless (equal (emus-track-album prev-track) album)
         (insert-text-button
          (propertize (concat "  " album) 'face 'emus-album)
          'action #'emus--click-track
          'follow-link t
          'help-echo help-str
-         'emus-track track)
-        (insert (propertize "\n" 'face 'emus-album))))
+         'emus-track track
+         'field field)
+        (insert (propertize "\n"
+                            'face 'emus-album
+                            'field field))))
     (emus-set-track-browser-pos track (point))
     (let ((is-current (equal track emus-current-track)))
       (insert-text-button
     (emus-set-track-browser-pos track (point))
     (let ((is-current (equal track emus-current-track)))
       (insert-text-button
@@ -468,11 +599,15 @@ and thus requires both artist and album headers."
        'action #'emus--click-track
        'follow-link t
        'help-echo help-str
        'action #'emus--click-track
        'follow-link t
        'help-echo help-str
-       'emus-track track)
+       'emus-track track
+       'invisible album-symb
+       'field field)
       (insert (propertize "\n"
                           'face (if is-current
                                     'emus-track-current
       (insert (propertize "\n"
                           'face (if is-current
                                     'emus-track-current
-                                  'emus-track))))))
+                                  'emus-track)
+                          'field field
+                          'invisible album-symb)))))
 
 (defun emus--update-track (track)
   "Rerender entry for TRACK in emus browser buffer.
 
 (defun emus--update-track (track)
   "Rerender entry for TRACK in emus browser buffer.
@@ -508,22 +643,22 @@ Used to update browser display when `emus-current-track' and/or `emus-state' cha
   (emus-play-track (button-get button 'emus-track))
   (emus-display-status))
 
   (emus-play-track (button-get button 'emus-track))
   (emus-display-status))
 
-(defun emus-centre-current ()
-  "Centre the current track in the browser buffer, if available."
+(defun emus-goto-current ()
+  "Move point to the current track in the browser buffer, if available."
   (interactive)
   (interactive)
-  (when (and (eq (current-buffer) (get-buffer "*emus*"))
+  (when (and (get-buffer "*emus*")
              emus-current-track)
              emus-current-track)
-        (goto-char (emus-track-browser-pos emus-current-track))
-        (recenter)))
+    (with-current-buffer "*emus*"
+        (goto-char (emus-track-browser-pos emus-current-track)))))
 
 (defun emus-browse ()
   "Switch to *emus* audio library browser."
   (interactive)
   (emus--with-library
 
 (defun emus-browse ()
   "Switch to *emus* audio library browser."
   (interactive)
   (emus--with-library
-   (pop-to-buffer "*emus*")
+   (pop-to-buffer-same-window "*emus*")
    (emus-browser-mode)
    (emus--render-tracks)
    (emus-browser-mode)
    (emus--render-tracks)
-   (emus-centre-current)))
+   (emus-goto-current)))
 
 (defun emus-refresh ()
   "Refresh the emus library."
 
 (defun emus-refresh ()
   "Refresh the emus library."
@@ -596,10 +731,28 @@ Used to update browser display when `emus-current-track' and/or `emus-state' cha
   (emus-jump-10s-backward)
   (emus-display-status))
 
   (emus-jump-10s-backward)
   (emus-display-status))
 
-(defun emus-centre-current-status ()
+(defun emus-jump-1m-forward-status ()
+  "Jump 10s forward in current track, then display the emus status in the minibuffer."
+  (interactive)
+  (emus-jump-1m-forward)
+  (emus-display-status))
+
+(defun emus-jump-1m-backward-status ()
   "Jump 10s backward in current track, then display the emus status in the minibuffer."
   (interactive)
   "Jump 10s backward in current track, then display the emus status in the minibuffer."
   (interactive)
-  (emus-centre-current)
+  (emus-jump-1m-backward)
+  (emus-display-status))
+
+(defun emus-toggle-progress-status ()
+  "Toggle progress tracking, then display the emus status in the minibuffer."
+  (interactive)
+  (emus-toggle-progress-tracking)
+  (emus-display-status))
+
+(defun emus-goto-current-status ()
+  "Move point to the current track, then display the emus status in the minibuffer."
+  (interactive)
+  (emus-goto-current)
   (emus-display-status))
 
 (defun emus-refresh-status ()
   (emus-display-status))
 
 (defun emus-refresh-status ()
@@ -607,9 +760,23 @@ Used to update browser display when `emus-current-track' and/or `emus-state' cha
   (interactive)
   (emus-stop)
   (setq emus-tracks nil)
   (interactive)
   (emus-stop)
   (setq emus-tracks nil)
-  (emus--with-library
-   (emus-browse)
-   (emus-display-status)))
+  (emus-browse)
+  (emus-display-status))
+
+(defun emus-restart-browse ()
+  "Restart the emus process, then refresh the browse window."
+  (interactive)
+  (message "Restarting mpg123.")
+  (emus-kill-process)
+  (run-at-time 0.1 nil #'emus-browse)) ;Slight delay to wait for kill signal to take effect
+
+(defun emus-restart-status ()
+  "Restart the emus process, then display the status."
+  (interactive)
+  (message "Restarting mpg123.")
+  (emus-kill-process)
+  (run-at-time 0.1 nil #'emus-display-status)) ;Slight delay to wait for kill signal to take effect
+
 
 (defvar emus-browser-mode-map
   (let ((map (make-sparse-keymap)))
 
 (defvar emus-browser-mode-map
   (let ((map (make-sparse-keymap)))
@@ -625,27 +792,36 @@ Used to update browser display when `emus-current-track' and/or `emus-state' cha
     (define-key map (kbd "P") 'emus-play-prev-album-status)
     (define-key map (kbd ",") 'emus-jump-10s-backward-status)
     (define-key map (kbd ".") 'emus-jump-10s-forward-status)
     (define-key map (kbd "P") 'emus-play-prev-album-status)
     (define-key map (kbd ",") 'emus-jump-10s-backward-status)
     (define-key map (kbd ".") 'emus-jump-10s-forward-status)
-    (define-key map (kbd "c") 'emus-centre-current-status)
+    (define-key map (kbd "<") 'emus-jump-1m-backward-status)
+    (define-key map (kbd ">") 'emus-jump-1m-forward-status)
+    (define-key map (kbd "c") 'emus-goto-current-status)
+    (define-key map (kbd "#") 'emus-toggle-progress-status)
+    (define-key map (kbd "!") 'emus-restart-browse)
     (when (fboundp 'evil-define-key*)
       (evil-define-key* 'motion map
     (when (fboundp 'evil-define-key*)
       (evil-define-key* 'motion map
-                        (kbd "SPC") 'emus-playpause-status
-                        (kbd "o") 'emus-stop-status
-                        (kbd "+") 'emus-volume-up-status
-                        (kbd "=") 'emus-volume-up-status
-                        (kbd "-") 'emus-volume-down-status
-                        (kbd "R") 'emus-refresh-status
-                        (kbd "n") 'emus-play-next-status
-                        (kbd "p") 'emus-play-prev-status
-                        (kbd "N") 'emus-play-next-album-status
-                        (kbd "P") 'emus-play-prev-album-status
-                        (kbd ",") 'emus-jump-10s-backward-status
-                        (kbd ".") 'emus-jump-10s-forward-status
-                        (kbd "c") 'emus-centre-current-status))
+        (kbd "SPC") 'emus-playpause-status
+        (kbd "o") 'emus-stop-status
+        (kbd "+") 'emus-volume-up-status
+        (kbd "=") 'emus-volume-up-status
+        (kbd "-") 'emus-volume-down-status
+        (kbd "R") 'emus-refresh-status
+        (kbd "n") 'emus-play-next-status
+        (kbd "p") 'emus-play-prev-status
+        (kbd "N") 'emus-play-next-album-status
+        (kbd "P") 'emus-play-prev-album-status
+        (kbd ",") 'emus-jump-10s-backward-status
+        (kbd ".") 'emus-jump-10s-forward-status
+        (kbd "<") 'emus-jump-1m-backward-status
+        (kbd ">") 'emus-jump-1m-forward-status
+        (kbd "c") 'emus-goto-current-status
+        (kbd "#") 'emus-toggle-progress-status
+        (kbd "!") #'emus-restart-browse))
     map)
   "Keymap for emus browser.")
 
 (define-derived-mode emus-browser-mode special-mode "emus-browser"
     map)
   "Keymap for emus browser.")
 
 (define-derived-mode emus-browser-mode special-mode "emus-browser"
-  "Major mode for EMUS music player file browser.")
+  "Major mode for EMUS music player file browser."
+  (setq-local buffer-invisibility-spec nil))
 
 (when (fboundp 'evil-set-initial-state)
   (evil-set-initial-state 'emus-browser-mode 'motion))
 
 (when (fboundp 'evil-set-initial-state)
   (evil-set-initial-state 'emus-browser-mode 'motion))