branch: externals/ement
commit f07623e3b2c8fa0b1525ab82c7e527cbe477fb34
Author: Adam Porter <a...@alphapapa.net>
Commit: Adam Porter <a...@alphapapa.net>

    Add/Change: (room--event-at, room-download-file) Refactor, expand
---
 ement-room.el | 72 ++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 57 insertions(+), 15 deletions(-)

diff --git a/ement-room.el b/ement-room.el
index 941f9aa766..6e697acbb9 100644
--- a/ement-room.el
+++ b/ement-room.el
@@ -2502,6 +2502,17 @@ To be used in `ement-room-view-hook', which see."
       (goto-char (ewoc-location node))
     (error "Event not found in buffer: %S" (ement-event-id event))))
 
+(defun ement-room--event-at (pos)
+  "Return event at POS or signal an error."
+  ;; TODO: Use this where appropriate.
+  (save-excursion
+    (goto-char pos)
+    (cl-assert ement-ewoc)
+    (let ((data (ewoc-data (ewoc-locate ement-ewoc))))
+      (cl-typecase data
+        (ement-event data)
+        (otherwise (user-error "No event at point"))))))
+
 (cl-defun ement-room-retro-callback (room session data
                                           &key (set-prev-batch t))
   "Push new DATA to ROOM on SESSION and add events to room buffer.
@@ -5546,7 +5557,7 @@ Then invalidate EVENT's node to show the image."
                              (file-size-human-readable size)))
                (string (format "[file: %s (%s) (%s)]" filename mimetype 
human-size)))
     (concat (propertize string
-                        'action #'ement-room-download-event-file
+                        'action #'ement-room-download-file
                         'button t
                         'button-data event
                         'category t
@@ -5569,7 +5580,7 @@ Then invalidate EVENT's node to show the image."
                (human-size (file-size-human-readable size))
                (string (format "[video: %s (%s) (%sx%s) (%s)]" body mimetype w 
h human-size)))
     (concat (propertize string
-                        'action #'ement-room-download-event-file
+                        'action #'ement-room-download-file
                         'button t
                         'button-data event
                         'category t
@@ -5592,7 +5603,7 @@ Then invalidate EVENT's node to show the image."
                (human-duration (format-seconds "%m:%s" (/ duration 1000)))
                (string (format "[audio: %s (%s) (%s) (%s)]" body mimetype 
human-duration human-size)))
     (concat (propertize string
-                        'action #'ement-room-download-event-file
+                        'action #'ement-room-download-file
                         'button t
                         'button-data event
                         'category t
@@ -5937,18 +5948,49 @@ For use in `completion-at-point-functions'."
 
 ;;;; Downloading media/files
 
-(defun ement-room-download-event-file (event)
-  (pcase-let* (((cl-struct ement-event
-                           (content (map ('filename event-filename)
-                                         ('url mxc-url))))
-                event))
-               (let* ((session ement-session)
-                     (dir (if (stringp eww-download-directory)
-                              eww-download-directory
-                            (funcall eww-download-directory)))
-                     (filename (expand-file-name(read-file-name "Download to: 
" (file-name-concat dir (file-name-nondirectory event-filename))))))
-                 (access-file dir "Download failed")
-                 (ement--media-request mxc-url session :as (list 'file 
filename)))))
+(defvar eww-download-directory)
+
+(defun ement-room-download-file (event destination)
+  "Download EVENT's file to DESTINATION.
+If DESTINATION is a directory, use the file's default name;
+otherwise, download to the filename.  Interactively, download to
+`eww-download-directory'; with prefix, prompt for destination."
+  (interactive (list (ement-room--event-at (point))
+                     (if current-prefix-arg
+                         (expand-file-name
+                          (read-file-name
+                           "Download to: "
+                           (cl-typecase eww-download-directory
+                             (string eww-download-directory)
+                             (function (funcall eww-download-directory)))))
+                       (expand-file-name
+                        (cl-typecase eww-download-directory
+                          (string eww-download-directory)
+                          (function (funcall eww-download-directory)))))))
+  (pcase-let (((cl-struct ement-event
+                          (content (map ('filename event-filename)
+                                        ('url mxc-url))))
+               event)
+              (started-at (current-time)))
+    (when (directory-name-p destination)
+      (unless (file-exists-p destination)
+        (make-directory destination 'parents))
+      (setf destination (file-name-concat destination event-filename)))
+    (unless (file-writable-p destination)
+      (user-error "Destination path not writable: %S" destination))
+    (when (file-exists-p destination)
+      (user-error "File already exists: %S" destination))
+    (ement--media-request mxc-url ement-session :authenticatedp t
+      :as `(file ,destination)
+      :then (lambda (&rest _)
+              (let* ((file-size (file-attribute-size
+                                 (file-attributes destination)))
+                     (duration (float-time (time-subtract (current-time) 
started-at)))
+                     (speed (file-size-human-readable (/ file-size duration))))
+                (message "File downloaded: %S (%s in %s at %s/sec) "
+                         destination (file-size-human-readable file-size)
+                         (format-seconds "%h:%m:%s%z seconds" duration)
+                         speed))))))
 
 ;;;; Footer
 

Reply via email to