X-Git-Url: http://christophe.rhodes.io/gitweb/?a=blobdiff_plain;f=squeeze.el;h=c3430946074110addd69f88c5c01a3bb90406a36;hb=abf91c38a4422821c03c56f295e1a865ed13812d;hp=bcdf4e2e055bf1c23490bdf551c3a729ae6c8554;hpb=a386bf58d625eb755df50765f0c50da2d0472f74;p=squeeze-el.git diff --git a/squeeze.el b/squeeze.el index bcdf4e2..c343094 100644 --- a/squeeze.el +++ b/squeeze.el @@ -17,15 +17,18 @@ (define-derived-mode squeeze-mode comint-mode "Squeeze" "Major mode for interacting with the Squeezebox Server CLI.\\" + (add-to-list 'completion-at-point-functions 'squeeze-complete-command-at-point) (add-hook 'comint-preoutput-filter-functions 'url-unhex-string nil t) (add-hook 'comint-preoutput-filter-functions 'squeeze-update-state nil t)) (defvar squeeze-control-mode-map (let ((map (make-sparse-keymap))) (define-key map (kbd "SPC") 'squeeze-control-toggle-power) + (define-key map (kbd "f") 'squeeze-control-play-favorite) (define-key map (kbd "g") 'squeeze-control-refresh) (define-key map (kbd "+") 'squeeze-control-volume-up) (define-key map (kbd "-") 'squeeze-control-volume-down) + (define-key map (kbd "t") 'squeeze-control-toggle-syncgroup-display) map)) (define-derived-mode squeeze-control-mode special-mode "SqueezeControl" @@ -72,6 +75,9 @@ ((string-match "^players 0" string) (setq squeeze-players (squeeze-parse-players-line string)) t) + ((string-match "^syncgroups" string) + (setq squeeze-syncgroups (squeeze-parse-syncgroups-line string)) + t) ((string-match squeeze-player-line-regexp string) (let ((substring (substring string (match-end 0))) (id (url-unhex-string (match-string 1 string)))) @@ -123,6 +129,10 @@ (defface squeeze-mixer-muted-quiet-face '((t :inherit (squeeze-mixer-muted-face squeeze-mixer-quiet-face))) "Face for quiet volume when muted") +(defface squeeze-syncgroup-face + '((t :slant italic)) + "Face for syncgroups" + :group 'squeeze) (defun squeeze-mixer-compute-bar (vol width) (let* ((exact (* width (/ vol 100.0))) @@ -143,18 +153,22 @@ (t "█")) (make-string nblank ? )))) -(defun squeeze-mixer-insert-bar (vol width) +(defun squeeze-mixer-make-bar (vol width) (let ((bar (squeeze-mixer-compute-bar vol width)) (lo (floor (* 0.65 width))) (hi (floor (* 0.9 width)))) - (insert ?▕ + (concat "▕" (propertize (substring bar 0 lo) 'face 'squeeze-mixer-quiet-face) (propertize (substring bar lo hi) 'face 'squeeze-mixer-medium-face) (propertize (substring bar hi) 'face 'squeeze-mixer-loud-face) - ?▏ - ))) + (propertize "▏" 'intangible t)))) (defvar squeeze-players ()) +(defvar squeeze-syncgroups ()) + +(defun squeeze-control-query-syncgroups () + (interactive) + (comint-send-string (get-buffer-process "*squeeze*") (format "syncgroups ?\n"))) (defun squeeze-control-query-players () (interactive) @@ -166,6 +180,13 @@ (setq id (get-text-property (point) 'squeeze-playerid))) (comint-send-string (get-buffer-process "*squeeze*") (format "%s power\n" id))) +(defun squeeze-control-play-favorite (&optional favorite id) + (interactive "nFavourite: ") + (unless id + (setq id (get-text-property (point) 'squeeze-playerid))) + (comint-send-string (get-buffer-process "*squeeze*") + (format "%s favorites playlist play item_id:%d\n" id favorite))) + (defun squeeze-control-query-power (&optional id) (interactive) (unless id @@ -189,6 +210,10 @@ (when id (comint-send-string (get-buffer-process "*squeeze*") (format "%s mixer volume %+d\n" id (- inc))))) +(defun squeeze-control-volume-set (id val) + (interactive) + (comint-send-string (get-buffer-process "*squeeze*") (format "%s mixer volume %d\n" id val))) + (defun squeeze-control-query-mixer-volume (&optional id) (interactive) (unless id @@ -210,6 +235,8 @@ (let ((squeeze-control-inhibit-display t)) (squeeze-control-query-players) (accept-process-output (get-buffer-process "*squeeze*")) + (squeeze-control-query-syncgroups) + (accept-process-output (get-buffer-process "*squeeze*")) (dolist (player squeeze-players) (squeeze-control-query-power (squeeze-player-playerid player)) (accept-process-output (get-buffer-process "*squeeze*")) @@ -217,21 +244,82 @@ (accept-process-output (get-buffer-process "*squeeze*")))) (squeeze-control-display-players)) +(defvar squeeze-control-mixer-map + (let ((map (make-sparse-keymap))) + (define-key map (kbd "RET") 'squeeze-control-mixer-set-volume) + (define-key map [mouse-1] 'squeeze-control-mixer-mouse-1) + map)) + +(defun squeeze-control-compute-volume (pos) + (let* ((end (next-single-property-change pos 'keymap)) + (start (previous-single-property-change end 'keymap))) + (/ (* 100 (- (point) start)) (- end start 1)))) + +(defun squeeze-control-mixer-mouse-1 (event) + (interactive "e") + (let* ((pos (cadadr event)) + (val (squeeze-control-compute-volume pos)) + (id (get-text-property pos 'squeeze-playerid))) + (squeeze-control-volume-set id val))) + +(defun squeeze-control-mixer-set-volume () + (interactive) + (let* ((val (squeeze-control-compute-volume (point))) + (id (get-text-property (point) 'squeeze-playerid))) + (squeeze-control-volume-set id val))) + +(defvar squeeze-control-display-syncgroups nil) + +(defun squeeze-control-toggle-syncgroup-display () + (interactive) + (setf squeeze-control-display-syncgroups + (not squeeze-control-display-syncgroups)) + (squeeze-control-display-players)) + +(defun squeeze-control-insert-player (player) + (insert (propertize (format "%20s" (squeeze-player-name player)) + 'face (squeeze-control-player-face player) + 'squeeze-playerid (squeeze-player-playerid player))) + (when (squeeze-player-volume player) + (insert (propertize + (squeeze-mixer-make-bar (squeeze-player-volume player) 28) + 'squeeze-playerid (squeeze-player-playerid player) + 'keymap squeeze-control-mixer-map + 'pointer 'hdrag + 'rear-nonsticky '(keymap)))) + (insert (propertize "\n" 'intangible t))) + (defun squeeze-control-display-players () (interactive) - (let ((players squeeze-players)) + (cond + (squeeze-control-display-syncgroups (with-current-buffer (get-buffer-create "*squeeze-control*") (squeeze-control-mode) (read-only-mode -1) (erase-buffer) - (dolist (player players) - (insert (propertize (format "%20s" (squeeze-player-name player)) - 'face (squeeze-control-player-face player) - 'squeeze-playerid (squeeze-player-playerid player))) - (when (squeeze-player-volume player) - (squeeze-mixer-insert-bar (squeeze-player-volume player) 28)) - (insert "\n")) - (read-only-mode 1)))) + (let ((syncgroups squeeze-syncgroups) + (seen)) + (while syncgroups + (let ((names (getf syncgroups :names)) + (members (split-string (getf syncgroups :members) ","))) + (insert (propertize names 'face 'squeeze-syncgroup-face) "\n") + (dolist (member members) + (let ((player (squeeze-find-player member))) + (squeeze-control-insert-player player) + (push player seen)))) + (setq syncgroups (cddddr syncgroups))) + (insert (propertize "No syncgroup" 'face 'squeeze-syncgroup-face) "\n") + (dolist (player squeeze-players) + (unless (member player seen) + (squeeze-control-insert-player player)))))) + (t + (with-current-buffer (get-buffer-create "*squeeze-control*") + (squeeze-control-mode) + (read-only-mode -1) + (erase-buffer) + (dolist (player squeeze-players) + (squeeze-control-insert-player player)) + (read-only-mode 1))))) (cl-defstruct (squeeze-player (:constructor squeeze-make-player)) playerindex playerid uuid ip name model isplayer displaytype canpoweroff connected power volume) @@ -250,6 +338,12 @@ (return))) (nreverse result)))) +(defun squeeze-parse-syncgroups-line (string) + (let ((syncgroupspos (string-match "^syncgroups " string)) + (startpos (match-end 0))) + (when startpos + (squeeze-string-plistify string startpos (length string))))) + (defun squeeze-parse-players-line (string) (let ((countpos (string-match " count%3A\\([0-9]\\) " string)) (startpos (match-end 0)))