1 ;;; cmus.el --- A very simple interface to cmus, useable locally and remotely via ssh.
    2 ;------------------------------------------------------------------------------
    3 ;; Remote control of cmus audio player
    4 ;; Copyright (C) 2015-2017, Winfried S. Dietmayer ---==WDI==---
    5 
    6 ;; Author: Winfried S. Dietmayer ---==WDI==--- <winfried@sunkiddance.de>
    7 ;; Version: 0.2
    8 ;; Keywords: multimedia, audio player remote control, cmus, ssh, elisp
    9 
   10 ;; cmus.el is free software: you can redistribute it and/or modify
   11 ;; it under the terms of the GNU General Public License as published by
   12 ;; the Free Software Foundation, either version 3 of the License, or
   13 ;; (at your option) any later version.
   14 
   15 ;; cmus.el is distributed in the hope that it will be useful,
   16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
   17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   18 ;; GNU General Public License for more details.
   19 
   20 ;; You should have received a copy of the GNU General Public License
   21 ;; along with cmus.el.  If not, see <https://www.gnu.org/licenses/>.
   22 ;;
   23 ;; To summarize: This is *free* but copyrighted software,
   24 ;; *free* as in *free*dom or *free* will.
   25 
   26 ;;; Commentary:
   27 ;; Overview
   28 ;; --------
   29 ;; cmus.el provides a simple interface for cmus, the C* music player.
   30 ;; It allows to control the basics, i.e. start, stop, pause, previous track,
   31 ;; next track, status of cmus player, lyrics for the currently playing track
   32 ;; and a possibility to look up the lyrics of a song, given artist and title
   33 ;; of the song.
   34 ;; It provides this basic functionality either on the local machine with cmus
   35 ;; and Emacs running, or on a remote machine issuing the cmus commands via ssh.
   36 ;; The main scenario is to remote control cmus from within a virtual machine
   37 ;; running on the local machine.  You don't have to leave the virtual machine
   38 ;; in order to control cmus.  No distractions only to mute the sound or to go
   39 ;; on to the next track.
   40 ;;
   41 ;; Prerequisites
   42 ;;--------------
   43 ;; * Local machine
   44 ;; ** cmus installed, any version will do
   45 ;; ** sshd installed if you plan to use it remotely, i.e. from a virtual machine
   46 ;; ** Script to retrieve the lyrics from the internet, say ~/bin/lyrics-cmus.sh
   47 ;; * Remote machine
   48 ;; ** ssh public-key authentication to localhost configured
   49 ;; 
   50 ;; Configuration of cmus
   51 ;; ---------------------
   52 ;; On cmus command line:
   53 ;; :set status_display_program=/path/to/program/cmus-artist-title.sh
   54 ;; To make this permanent, add the line above to your ~/.cmus/rc
   55 ;; cmus-artist-title.sh writes the current cmus status
   56 ;; (artist, track title, etc.) to a defined file, say ~/cmus-status.txt.
   57 ;;
   58 ;; Configuration of cmus.el
   59 ;; ------------------------
   60 ;; cmus.el support the Emacs Custom interface invoked with 'M-x customize'.
   61 ;; cmus is located in the subgroups 'Application/cmus' and 'Multimedia/cmus', respectively.
   62 ;; The entries there are self-explanatory, really, believe me 8-) .
   63 ;; The parameter 'Cmus Lyrics Command' is the full path to a script/program which retrieves
   64 ;; the lyrics of the currently playing track.  It reads this information from cmus-status.txt.
   65 ;; Alternatively, the script shall accept two parameters, 'artist' and 'title',
   66 ;; for example 'Beatles yesterday'.
   67 ;;
   68 ;; cmus.el buffer
   69 ;; --------------
   70 ;; Messages returned to Emacs are logged into buffer *CMUS-Shell-Output*.
   71 ;; If things go awry, look there for a clue what went wrong.
   72 ;;
   73 ;; Configuration of ~/.emacs
   74 ;; -------------------------
   75 ;; In order to load cmus.el at startup, add the following line to ~/.emacs:
   76 ;; (load-file "~/bin/emacs/cmus.el")
   77 
   78 ;------------------------------------------------------------------------------
   79 ;;; Code:
   80 (defgroup cmus ()
   81   "Very simple remote and local client for the C* music player (cmus)."
   82   :prefix "cmus-"
   83   :group 'multimedia
   84   :group 'applications)
   85 (defcustom
   86   cmus-remote-ssh-port ""
   87   "The port number sshd on remote *cmus* host is listening to. Leave blank if invoked locally."
   88   :type 'string)
   89 (defcustom
   90   cmus-remote-ssh-login ""
   91   "The ssh user and remote *cmus* host name to login, f.e. <user@192.168.1.1>. Leave blank if invoked locally."
   92   :type 'string)
   93 (defcustom
   94   cmus-local-ssh-command ""
   95   "The *local* ssh command to connect to remote *cmus* host. Leave blank if invoked locally."
   96   :type 'string)
   97 (defcustom
   98   cmus-local-ssh-parameter ""
   99   "The *local* ssh command parameters to connect to remote *cmus* host. Note that the last parameter has to be -p.
  100 Leave blank if invoked locally."
  101   :type 'string)
  102 (defcustom
  103   cmus-command "/opt/local/bin/cmus-remote"
  104   "The command to control *cmus* locally or remotely."
  105   :type 'string)
  106 (defcustom
  107   cmus-lyrics-command "/Users/winfried/bin/lyrics-cmus.sh"
  108   "The *cmus* command to retrieve the lyrics."
  109   :type 'string)
  110 ;; ------------------------------------------------------------------------------
  111 ; cmus helper functions
  112 (defun ssh-command-string ()
  113 "The complete shell command string to control *cmus*."
  114   (mapconcat 'identity
  115 	     (list cmus-local-ssh-command
  116 		   cmus-local-ssh-parameter
  117 		   cmus-remote-ssh-port
  118 		   cmus-remote-ssh-login
  119 		   cmus-command)
  120 	     " "))
  121 
  122 (defun ssh-command-lyrics-string ()
  123 "The complete shell command string to retrieve lyrics."
  124   (mapconcat 'identity
  125 	     (list cmus-local-ssh-command
  126 		   cmus-local-ssh-parameter
  127 		   cmus-remote-ssh-port
  128 		   cmus-remote-ssh-login
  129 		   cmus-lyrics-command)
  130 	     " "))
  131 ;; ------------------------------------------------------------------------------
  132 (defun cmus-play ()
  133 "Start playing the current song in cmus."
  134   (interactive)
  135   (start-process-shell-command "*CMUS-Shell-Play*" "*CMUS-Shell-Output*" (ssh-command-string) "-p"))
  136 (global-set-key "\C-c\C-xp" 'cmus-play)
  137 
  138 (defun cmus-pause ()
  139 "Pause playing the current song in cmus."
  140   (interactive)
  141   (start-process-shell-command "*CMUS-Shell-Pause*" "*CMUS-Shell-Output*" (ssh-command-string) "-u"))
  142 (global-set-key "\C-c\C-xu" 'cmus-pause)
  143 
  144 (defun cmus-stop ()
  145 "Stop playing the current song in cmus."
  146   (interactive)
  147   (start-process-shell-command "*CMUS-Shell-Stop*" "*CMUS-Shell-Output*" (ssh-command-string) "-s"))
  148 (global-set-key "\C-c\C-xs" 'cmus-stop)
  149 
  150 (defun cmus-vol (volume)
  151 "Set the VOLUME in cmus.
  152 The complete possible command is as follows: [+-]NUM[%].
  153 NUM is a number in (0..100)."
  154   (interactive "MVolume:(0..100):")
  155   (start-process-shell-command "*CMUS-Shell-Vol*" "*CMUS-Shell-Output*" (ssh-command-string) "-v" volume))
  156 (global-set-key "\C-c\C-xv" 'cmus-vol)
  157 
  158 (defun cmus-next ()
  159 "Play the next song in cmus."
  160   (interactive)
  161   (start-process-shell-command "*CMUS-Shell-Next*" "*CMUS-Shell-Output*" (ssh-command-string) "-n"))
  162 (global-set-key "\C-c\C-xn" 'cmus-next)
  163 
  164 (defun cmus-previous ()
  165 "Play the previous song in cmus."
  166   (interactive)
  167   (start-process-shell-command "*CMUS-Shell-Previous*" "*CMUS-Shell-Output*" (ssh-command-string) "-r"))
  168 (global-set-key "\C-c\C-xr" 'cmus-previous)
  169 
  170 (defun cmus-show-lyrics ()
  171 "Retrieve the lyrics of the song currently played and display it in the buffer *CMUS Lyrics*."
  172    (interactive)
  173    (switch-to-buffer (create-file-buffer "*CMUS Lyrics*"))
  174    (text-mode)
  175    (insert (shell-command-to-string (ssh-command-lyrics-string)))
  176    (goto-char (point-min))
  177    (view-mode))
  178 (global-set-key "\C-c\C-xl" 'cmus-show-lyrics)
  179 
  180 (defun cmus-show-lyrics-user (&optional artist title)
  181 "Retrieve the lyrics of the ARTIST and TITLE provided by the user and displays it in the buffer *CMUS Lyrics*."
  182   (interactive
  183    "Martist: \nMtitle: ")
  184   (switch-to-buffer (create-file-buffer "*CMUS Lyrics*"))
  185   (text-mode)
  186   (insert
  187    (shell-command-to-string
  188     (concat (ssh-command-lyrics-string)
  189 	    (shell-quote-argument
  190 	     (concat " \""artist"\"" " " "\""title"\"")))))
  191   (goto-char (point-min))
  192   (view-mode))
  193 (global-set-key "\C-c\C-xt" 'cmus-show-lyrics-user)
  194 
  195 (defun cmus-status ()
  196 "Show the current state of cmus."
  197   (interactive)
  198   (switch-to-buffer (create-file-buffer "*CMUS Status*"))
  199   (text-mode)
  200   (insert (shell-command-to-string (concat (ssh-command-string) " -Q")))
  201   (goto-char (point-min))
  202   (view-mode))
  203 (global-set-key "\C-c\C-xQ" 'cmus-status)
  204 ;------------------------------------------------------------------------------
  205 
  206 (provide 'cmus)
  207 
  208 ;;; cmus.el ends here