From cb26f776337e50e035fb3dff9773fc6f61d66070 Mon Sep 17 00:00:00 2001 From: Christophe Rhodes Date: Thu, 22 May 2014 08:21:47 +0100 Subject: [PATCH] implement process sentinel for iplayer downloads process state, in principle, goes connecting -> downloading -> transcoding -> finished | v | '-----------> failed <--------' thoughat the moment there's a wrong edge from downloading to finished if the get-iplayer process is terminated at an unfortunate time. --- iplayer.el | 94 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 57 insertions(+), 37 deletions(-) diff --git a/iplayer.el b/iplayer.el index 467d656..ce773e5 100644 --- a/iplayer.el +++ b/iplayer.el @@ -219,44 +219,60 @@ The presets are defined in the variable `iplayer-presets'." (iplayer-channel iplayer-current-channel) (iplayer-show-all))) +(defun iplayer-download-display-state (process) + (let ((id (process-get process 'iplayer-id)) + (state (process-get process 'iplayer-state)) + (progress (process-get process 'iplayer-progress))) + (with-current-buffer (get-buffer-create "*iplayer-progress*") + (goto-char (point-min)) + (let ((found (re-search-forward (format "^%s:" id) nil 'end))) + (unless found + (unless (= (point) (progn (forward-line 0) (point))) + (goto-char (point-max)) + (newline))) + (forward-line 0) + (let ((beg (point))) + (end-of-line) + (delete-region beg (point))) + (insert (format "%s: %s %s%%" id state progress)))))) + (defun iplayer-download-process-filter (process string) + (catch 'no-progress + (cond + ((string-match "^Starting download" string) + (process-put process 'iplayer-state 'downloading) + (process-put process 'iplayer-progress 0.0)) + ((and (eql (process-get process 'iplayer-state) 'downloading) + (string-match "(\\([0-9]\\{1,3\\}.[0-9]\\)%)$" string)) + (process-put process 'iplayer-progress (string-to-number (match-string 1 string)))) + ((string-match "Started writing to temp file" string) + (process-put process 'iplayer-state 'transcoding) + (process-put process 'iplayer-progress 0.0)) + ((string-match " Progress: =*>?\\([0-9]\\{1,3\\}\\)%-*|" string) + (let ((idx (match-beginning 0)) (data (match-data))) + (while (string-match " Progress: =*>?\\([0-9]\\{1,3\\}\\)%-*|" string (match-end 0)) + (setq idx (match-beginning 0)) + (setq data (match-data))) + (set-match-data data) + (process-put process 'iplayer-progress (string-to-number (match-string 1 string))))) + (t (with-current-buffer (process-buffer process) + (insert string)) + (throw 'no-progress nil))) + (iplayer-download-display-state process))) + +(defun iplayer-download-process-sentinel (process string) (cond - ((string-match "^Starting download" string) - (process-put process 'iplayer-state 'downloading) - (process-put process 'iplayer-progress 0.0)) - ((and (eql (process-get process 'iplayer-state) 'downloading) - (string-match "(\\([0-9]\\{1,3\\}.[0-9]\\)%)$" string)) - (process-put process 'iplayer-progress (string-to-number (match-string 1 string)))) - ((string-match "Started writing to temp file" string) - (process-put process 'iplayer-state 'transcoding) - (process-put process 'iplayer-progress 0.0)) - ((string-match " Progress: =*>?\\([0-9]\\{1,3\\}\\)%-*|" string) - (let ((idx (match-beginning 0)) (data (match-data))) - (while (string-match " Progress: =*>?\\([0-9]\\{1,3\\}\\)%-*|" string (match-end 0)) - (setq idx (match-beginning 0)) - (setq data (match-data))) - (set-match-data data) - (process-put process 'iplayer-progress (string-to-number (match-string 1 string))))) - (t (with-current-buffer (process-buffer process) - (newline) - (insert string) - (newline)))) - (with-current-buffer (get-buffer-create "*iplayer-progress*") - (goto-char (point-min)) - (let ((found - (re-search-forward (format "^%s:" (process-get process 'iplayer-id)) nil 'end))) - (unless found - (unless (= (point) (progn (forward-line 0) (point))) - (goto-char (point-max)) - (newline))) - (forward-line 0) - (let ((beg (point))) - (end-of-line) - (delete-region beg (point))) - (insert (format "%s: %s %s%%" - (process-get process 'iplayer-id) - (process-get process 'iplayer-state) - (process-get process 'iplayer-progress)))))) + ((string-match "^finished" string) + ;; KLUDGE: get-iplayer installs signal handlers and exit with a 0 + ;; exit code from them. That means we can't use the sentinel to + ;; distinguish between being killed and exiting with success, so + ;; we hack around the problem. + (if (= (process-get process 'iplayer-progress) 100) + (process-put process 'iplayer-state 'finished) + (process-put process 'iplayer-state 'failed))) + ((string-match "^exited abnormally" string) + (process-put process 'iplayer-state 'failed))) + (iplayer-download-display-state process)) (defun iplayer-download () (interactive) @@ -269,8 +285,12 @@ The presets are defined in the variable `iplayer-presets'." (let ((process (start-process "get-iplayer" " *get-iplayer*" "get-iplayer" "--modes=best" "--get" (format "%s" id)))) (process-put process 'iplayer-id id) + (process-put process 'iplayer-state 'connecting) + (process-put process 'iplayer-progress 0.0) (set-process-filter process 'iplayer-download-process-filter) - (display-buffer (get-buffer-create "*iplayer-progress*")))) + (set-process-sentinel process 'iplayer-download-process-sentinel) + (display-buffer (get-buffer-create "*iplayer-progress*")) + (iplayer-download-display-state process))) (message "no id at point")))) (defun iplayer-previous () -- 2.30.2