emacs/lisp/uguu.el 4.3 K raw
1
;;; uguu.el --- Upload files to uguu.se -*- lexical-binding: t; -*-
2
;;
3
;;; Commentary:
4
;; `uguu-upload-file' and `uguu-upload-clipboard' upload to uguu.se and put
5
;; the resulting link in the kill ring.  In an ERC buffer the link is also
6
;; inserted at the prompt.  A prefix argument flips that behavior.
7
;;
8
;;; Code:
9
10
(require 'subr-x)
11
12
(defgroup uguu nil
13
  "Upload files to uguu.se."
14
  :group 'tools)
15
16
(defcustom uguu-endpoint "https://uguu.se/upload?output=text"
17
  "Upload URL.  `output=text' makes the response just the file link."
18
  :type 'string)
19
20
(defcustom uguu-insert-modes '(erc-mode)
21
  "Major modes where the link is inserted at point by default."
22
  :type '(repeat symbol))
23
24
(defun uguu--finish (url insert)
25
  "Copy URL to the kill ring, and insert it when INSERT is non-nil."
26
  (kill-new url)
27
  (when insert
28
    (when (derived-mode-p 'erc-mode)
29
      (goto-char (point-max)))
30
    (insert url))
31
  (message "Uploaded: %s%s" url (if insert "" " (copied)")))
32
33
(defun uguu--upload (file insert &optional cleanup)
34
  "Upload FILE asynchronously, then call `uguu--finish' with INSERT.
35
When CLEANUP is non-nil, delete FILE afterwards."
36
  (let ((buf (current-buffer))
37
        (out (generate-new-buffer " *uguu*")))
38
    (message "Uploading %s..." (file-name-nondirectory file))
39
    (make-process
40
     :name "uguu" :buffer out :noquery t
41
     :command (list "curl" "-sS" "--fail-with-body"
42
                    "-F" (concat "files[]=@" (expand-file-name file))
43
                    uguu-endpoint)
44
     :sentinel
45
     (lambda (proc _event)
46
       (when (memq (process-status proc) '(exit signal))
47
         (let ((resp (with-current-buffer out (string-trim (buffer-string)))))
48
           (kill-buffer out)
49
           (when cleanup (ignore-errors (delete-file file)))
50
           (if (and (zerop (process-exit-status proc))
51
                    (string-prefix-p "http" resp))
52
               (if (buffer-live-p buf)
53
                   (with-current-buffer buf (uguu--finish resp insert))
54
                 (uguu--finish resp nil))
55
             (message "Uguu upload failed: %s" resp))))))))
56
57
(defun uguu--insert-p (arg)
58
  "Whether to insert the link, given prefix ARG."
59
  (let ((default (apply #'derived-mode-p uguu-insert-modes)))
60
    (if arg (not default) default)))
61
62
;;;###autoload
63
(defun uguu-upload-file (file &optional arg)
64
  "Upload FILE to uguu.se.  Copy the link; insert it too in ERC.
65
With prefix ARG, flip whether the link is inserted."
66
  (interactive (list (read-file-name "Upload file: " nil nil t) current-prefix-arg))
67
  (uguu--upload file (uguu--insert-p arg)))
68
69
(defun uguu--clipboard-file ()
70
  "Return the path of a file copied in Finder/CleanShot, or nil.
71
Checked before the image data, which for a copied file is just its icon."
72
  (with-temp-buffer
73
    (when (zerop (call-process
74
                  "osascript" nil '(t nil) nil
75
                  "-e" "POSIX path of (the clipboard as «class furl»)"))
76
      (let ((path (string-trim (buffer-string))))
77
        (and (file-regular-p path) path)))))
78
79
(defun uguu--clipboard-image ()
80
  "Write the clipboard image to a temp PNG and return its path, or nil."
81
  (let ((tmp (make-temp-file "uguu-" nil ".png")))
82
    (if (zerop (call-process
83
                "osascript" nil nil nil
84
                "-e" (format "set f to open for access POSIX file %S with write permission"
85
                             tmp)
86
                "-e" "set eof f to 0"
87
                "-e" "write (the clipboard as «class PNGf») to f"
88
                "-e" "close access f"))
89
        tmp
90
      (delete-file tmp)
91
      nil)))
92
93
;;;###autoload
94
(defun uguu-upload-clipboard (&optional arg)
95
  "Upload the clipboard (an image, else text) to uguu.se.
96
With prefix ARG, flip whether the link is inserted."
97
  (interactive "P")
98
  (let* ((insert (uguu--insert-p arg))
99
         (file (uguu--clipboard-file))
100
         (img (and (not file) (uguu--clipboard-image))))
101
    (cond
102
     (file (uguu--upload file insert))
103
     (img (uguu--upload img insert t))
104
     (t
105
      (let ((text (or (ignore-errors (gui-get-selection 'CLIPBOARD 'STRING))
106
                      (car kill-ring)))
107
            (tmp (make-temp-file "uguu-" nil ".txt")))
108
        (unless (and text (not (string-empty-p text)))
109
          (user-error "Clipboard is empty"))
110
        (write-region text nil tmp nil 'silent)
111
        (uguu--upload tmp insert t))))))
112
113
(provide 'uguu)
114
;;; uguu.el ends here