X-Git-Url: http://christophe.rhodes.io/gitweb/?p=iplayer-el.git;a=blobdiff_plain;f=iplayer.el;h=d61b6d1d6168aaf7817f1e904dcaf0dc9aa297b3;hp=1b02d16b6beed2e6a17f63a95977b1c55a7a9ac7;hb=06c057214ea2f9c4220ecd7d0b49018a9b65e470;hpb=fdc7d7e30e72d78e91285f0a1b0cfe3d2032daf8 diff --git a/iplayer.el b/iplayer.el index 1b02d16..d61b6d1 100644 --- a/iplayer.el +++ b/iplayer.el @@ -25,6 +25,17 @@ ;; convenient interface to BBC iPlayer. ;;; Code: + +(defgroup iplayer nil + "Browse and download BBC TV/radio shows." + :prefix "iplayer-" + :group 'applications) + +(defcustom iplayer-download-directory "~/iPlayer/" + "Directory into which shows will be downloaded." + :group 'iplayer + :type 'directory) + (defvar iplayer-updating-cache-process nil) (defvar iplayer-updating-cache-sentinel-info nil) (defvar iplayer-updating-cache-sentinel-executing nil) @@ -36,51 +47,56 @@ (setq iplayer-updating-cache-process nil iplayer-updating-cache-sentinel-info nil) (dolist (info info) - (let ((iplayer-command-frame (car info)) - (iplayer-command-window (cadr info)) - (iplayer-command-buffer (caddr info)) - (keys (car (cdddr info))) - (function (cadr (cdddr info)))) + (let ((iplayer-command-frame (nth 0 info)) + (iplayer-command-window (nth 1 info)) + (iplayer-command-buffer (nth 2 info)) + (keys (nth 3 info)) + (function (nth 4 info))) (when (and (frame-live-p iplayer-command-frame) (window-live-p iplayer-command-window) (buffer-live-p iplayer-command-buffer)) (let ((old-frame (selected-frame)) (old-window (selected-window)) (old-buffer (current-buffer))) - (let ((pre-command-hook - (lambda () - (select-frame iplayer-command-frame) - (select-window iplayer-command-window) - (set-buffer iplayer-command-buffer) - (setq pre-command-hook nil)))) - ;; KLUDGE: execute-kbd-macro executes a normal - ;; command-loop, whose first action is to select the - ;; current frame and window, which is why we contort - ;; things to select the frame/window/buffer we actually - ;; want in pre-command-hook. I'm actually surprised - ;; that it works, but mine is not too much to reason - ;; why; lots of other ways to try to achieve this didn't - ;; in fact work. - (if (version< emacs-version "24") - (execute-kbd-macro keys) - ;; KLUDGE: we store the function name, which is fine, - ;; but some of our functions need to know which - ;; keystrokes were used to invoke them, so we need to - ;; pass those along, so we need to make sure that all - ;; iplayer-functions accept an optional argument, argh - ;; argh argh. - (funcall function keys)) - ;; KLUDGE: and then we restore old state - (select-window old-window) - (select-frame old-frame) - (set-buffer old-buffer)))))) - (message "Done updating iPlayer cache"))) + (cond + ((version< emacs-version "24") + (let ((pre-command-hook + (lambda () + (select-frame iplayer-command-frame) + (select-window iplayer-command-window) + (set-buffer iplayer-command-buffer) + (setq pre-command-hook nil)))) + ;; KLUDGE: execute-kbd-macro executes a normal + ;; command-loop, whose first action is to select the + ;; current frame and window, which is why we contort + ;; things to select the frame/window/buffer we actually + ;; want in pre-command-hook. I'm actually surprised + ;; that it works, but mine is not too much to reason + ;; why; lots of other ways to try to achieve this didn't + ;; in fact work. + (execute-kbd-macro keys) + ;; KLUDGE: and then we restore old state + (select-window old-window) + (select-frame old-frame) + (set-buffer old-buffer))) + (t + ;; KLUDGE: we store the function name, which is fine, + ;; but some of our functions need to know which + ;; keystrokes were used to invoke them, so we need to + ;; pass those along, so we need to make sure that all + ;; iplayer-functions accept an optional argument, argh + ;; argh argh. + (with-selected-frame iplayer-command-frame + (with-current-buffer iplayer-command-buffer + (with-selected-window iplayer-command-window + (funcall function keys))))))))) + (message "Done updating iPlayer cache")))) (defmacro define-iplayer-command (name arglist &rest body) (let (docstring interactive) (when (stringp (car body)) (setq docstring (car body) body (cdr body))) - (when (and (consp (car body)) (eql (caar body) 'interactive)) + (when (and (consp (car body)) (eql (car (car body)) 'interactive)) (setq interactive (car body) body (cdr body))) `(defun ,name ,arglist ,@(when docstring (list docstring)) @@ -126,16 +142,18 @@ (defun display-iplayer-tree (tree) (with-current-buffer (get-buffer-create "*iplayer*") - (delete-region (point-min) (point-max)) + (let ((buffer-read-only nil)) + (fundamental-mode) + (delete-region (point-min) (point-max)) + (dolist (entry tree) + (let ((program (car entry)) + (episodes (cdr entry))) + (insert (propertize (format "* %s\n" program) 'face 'outline-1)) + (dolist (episode episodes) + (insert (propertize (format "** %s\n" (cdr episode)) + 'face 'outline-2 'iplayer-id (car episode))))))) (iplayer-mode) (orgstruct-mode 1) - (dolist (entry tree) - (let ((program (car entry)) - (episodes (cdr entry))) - (insert (propertize (format "* %s\n" program) 'face 'outline-1)) - (dolist (episode episodes) - (insert (propertize (format "** %s\n" (cdr episode)) - 'face 'outline-2 'iplayer-id (car episode)))))) (org-overview) (goto-char (point-min))) (switch-to-buffer (get-buffer-create "*iplayer*"))) @@ -158,13 +176,19 @@ Used in the `iplayer-preset' command.") +(defun iplayer-frob-presets (presets) + (cond + ((version< emacs-version "24") + (mapcar (lambda (x) (cons (read-kbd-macro (car x)) (cdr x))) presets)) + (t presets))) + (define-iplayer-command iplayer-preset (&optional keys) "Switch display to a preset channel. The presets are defined in the variable `iplayer-presets'." (interactive) (let ((keys (or (and keys (concat keys)) (this-command-keys))) - (presets (mapcar (lambda (x) (cons (read-kbd-macro (car x)) (cdr x))) iplayer-presets))) + (presets (iplayer-frob-presets iplayer-presets))) (cond ((= (length keys) 1) (let ((channel (cdr (assoc keys presets)))) @@ -181,11 +205,11 @@ The presets are defined in the variable `iplayer-presets'." (interactive) (let ((id (get-text-property (point) 'iplayer-id))) (if id - (let ((default-directory "~/iPlayer/")) + (let ((default-directory iplayer-download-directory)) ;; should probably use a process filter instead to give us a ;; progress bar (message "downloading id %s" id) - (start-process "get-iplayer" " *get-iplayer*" "get-iplayer" "--get" (format "%s" id))) + (start-process "get-iplayer" " *get-iplayer*" "get-iplayer" "--modes=best" "--get" (format "%s" id))) (message "no id at point")))) (defun iplayer-previous () @@ -224,12 +248,9 @@ The presets are defined in the variable `iplayer-presets'." map )) -(defun iplayer-mode () +(define-derived-mode iplayer-mode special-mode "iPlayer" "A major mode for the BBC's iPlayer. -\\{iplayer-mode-map}" - (interactive) - (use-local-map iplayer-mode-map) - (setq major-mode 'iplayer-mode mode-name "iPlayer")) +\\{iplayer-mode-map}") (define-iplayer-command iplayer (&optional keys) "Start the emacs iPlayer interface."