X-Git-Url: http://christophe.rhodes.io/gitweb/?p=squeeze-el.git;a=blobdiff_plain;f=squeeze.el;h=25491596d5633e9b41ab235b8b1135376b9011b5;hp=406ffac5adaf74040a1da74c9248bb0ba6183111;hb=0e4ee58cdc46656c8ffaa2e9e0b642c88036b980;hpb=585626987767fee95b4666da3a44128fec0d3105 diff --git a/squeeze.el b/squeeze.el index 406ffac..2549159 100644 --- a/squeeze.el +++ b/squeeze.el @@ -15,10 +15,28 @@ (define-key map (kbd "TAB") 'completion-at-point) map)) +(defun squeeze-unhex-string (string) + (with-temp-buffer + (let ((case-fold-search t) + (start 0)) + (while (string-match "%[0-9a-f][0-9a-f]" string start) + (let* ((s (match-beginning 0)) + (ch1 (url-unhex (elt string (+ s 1)))) + (code (+ (* 16 ch1) + (url-unhex (elt string (+ s 2)))))) + (insert (substring string start s) + (byte-to-string code)) + (setq start (match-end 0)))) + (insert (substring string start))) + (buffer-string))) + +(defun squeeze-unhex-and-decode-utf8-string (string) + (decode-coding-string (squeeze-unhex-string string) 'utf-8)) + (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-unhex-and-decode-utf8-string nil t) (add-hook 'comint-preoutput-filter-functions 'squeeze-update-state nil t)) (defvar squeeze-control-mode-map @@ -36,15 +54,25 @@ (defvar squeeze-control-inhibit-display nil) -(defun squeeze-update-state (string) - (let (done-something) - (dolist (line (split-string string "\n")) - (when (squeeze-update-state-from-line line) - (setq done-something t))) - (when done-something - (unless squeeze-control-inhibit-display - (squeeze-control-display-players)))) - string) +(lexical-let ((buffer (get-buffer-create " *squeeze-update-state*"))) + (defun squeeze-update-state (string) + ;; FIXME: we could make this a lot more elegant by using the + ;; buffer abstraction more + (if (cl-position ?\n string) + (let (done-something) + (with-current-buffer buffer + (insert string) + (setq string (buffer-string)) + (erase-buffer)) + (dolist (line (split-string string "\n")) + (when (squeeze-update-state-from-line line) + (setq done-something t))) + (when done-something + (unless squeeze-control-inhibit-display + (squeeze-control-display-players)))) + (with-current-buffer buffer + (insert string))) + string)) (defconst squeeze-player-line-regexp "^\\(\\(?:[0-9a-f]\\{2\\}%3A\\)\\{5\\}[0-9a-f]\\{2\\}\\) ") @@ -141,16 +169,9 @@ (nblank (floor (- width exact)))) (format "%s%s%s" (make-string nfull ?█) - (cond ((= width (+ nfull nblank)) "") - ((< frac 0.0625) " ") - ((< frac 0.1875) "▏") - ((< frac 0.3125) "▎") - ((< frac 0.4375) "▍") - ((< frac 0.5625) "▌") - ((< frac 0.6875) "▋") - ((< frac 0.8125) "▊") - ((< frac 0.9375) "▉") - (t "█")) + (if (= width (+ nfull nblank)) + "" + (string (aref " ▏▎▍▌▋▊▉█" (floor (+ frac 0.0625) 0.125)))) (make-string nblank ? )))) (defun squeeze-mixer-make-bar (vol width) @@ -333,15 +354,20 @@ playerindex playerid uuid ip name model isplayer displaytype canpoweroff connected power volume) (defun squeeze-string-plistify (string start end) + (unless end + (setq end (length string))) (save-match-data (let (result) (loop - (if (string-match "\\([a-z]+\\)%3A\\([^ \n]+\\)" string start) + (if (string-match "\\([a-z_]+\\)%3A\\([^ \n]+\\)" string start) (let ((mend (match-end 0))) (when (> mend end) (return)) (push (intern (format ":%s" (substring string (match-beginning 1) (match-end 1)))) result) - (push (url-unhex-string (substring string (match-beginning 2) (match-end 2))) result) + (push (decode-coding-string + (url-unhex-string (substring string (match-beginning 2) (match-end 2))) + 'utf-8) + result) (setq start mend)) (return))) (nreverse result)))) @@ -352,20 +378,30 @@ (when startpos (squeeze-string-plistify string startpos (length string))))) +(defun squeeze-parse-count (string) + (save-match-data + (let ((countpos (string-match "count%3A\\([0-9]*\\)\\>" string))) + (if countpos + (string-to-number + (substring string (match-beginning 1) (match-end 1))) + (let ((kind + (progn (string-match "^\\([a-z]*\\) " string) + (substring string (match-beginning 1) (match-end 1))))) + (message "no count found in %s line" kind) + nil))))) + (defun squeeze-parse-players-line (string) - (let ((countpos (string-match " count%3A\\([0-9]\\) " string)) - (startpos (match-end 0))) - (unless countpos - (message "no count found in players line")) - (let ((count (string-to-number (substring string (match-beginning 1) (match-end 1)))) - result endpos) - (dotimes (i (1- count)) - (setq endpos (progn (string-match " connected%3A[0-1] " string startpos) - (match-end 0))) - (push (apply 'squeeze-make-player (squeeze-string-plistify string startpos endpos)) result) - (setq startpos endpos)) - (push (apply 'squeeze-make-player (squeeze-string-plistify string startpos (length string))) result) - result))) + (let ((count (squeeze-parse-count string)) + (startpos (string-match "playerindex" string)) + result endpos) + (dotimes (i (1- count)) + (setq endpos (progn (string-match " connected%3A[0-1] " string startpos) + (match-end 0))) + (push (apply 'squeeze-make-player (squeeze-string-plistify string startpos endpos)) result) + (setq startpos endpos)) + (push (apply 'squeeze-make-player (squeeze-string-plistify string startpos (length string))) result) + result)) + (defun squeeze-complete-command-at-point () (save-excursion @@ -403,7 +439,7 @@ "serverstatus" "status" "displaystatus" "readdirectory" ;; Notifications - + ;; Alarm commands and queries "alarm" "alarms" @@ -411,19 +447,37 @@ "favorites" )))) -(defun squeeze () +(defun squeeze-read-server-parameters (address port) + (let ((host (read-string "Host: " nil nil address)) + (port (read-number "Port: " port))) + (cons host port))) + +(defun squeeze (&optional address port) (interactive) - (let ((buffer (make-comint-in-buffer "squeeze" nil - (cons squeeze-server-address - squeeze-server-port)))) + (unless address (setq address squeeze-server-address)) + (unless port (setq port squeeze-server-port)) + (when current-prefix-arg + (let ((parameters (squeeze-read-server-parameters address port))) + (setq address (car parameters) + port (cdr parameters)))) + (let ((buffer (make-comint-in-buffer "squeeze" nil (cons address port)))) (switch-to-buffer buffer) (squeeze-mode))) -(defun squeeze-control () +(defun squeeze-control (&optional address port) (interactive) - (squeeze) + (unless address (setq address squeeze-server-address)) + (unless port (setq port squeeze-server-port)) + (when current-prefix-arg + (let ((parameters (squeeze-read-server-parameters address port))) + (setq address (car parameters) + port (cdr parameters)))) + (let ((current-prefix-arg nil)) + (squeeze address port)) (let ((buffer (get-buffer-create "*squeeze-control*"))) (switch-to-buffer buffer) (squeeze-control-listen) (squeeze-control-refresh) (squeeze-control-display-players))) + +(provide 'squeeze)