aboutsummaryrefslogtreecommitdiff
path: root/lisp/mastodon-media.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/mastodon-media.el')
-rw-r--r--lisp/mastodon-media.el232
1 files changed, 40 insertions, 192 deletions
diff --git a/lisp/mastodon-media.el b/lisp/mastodon-media.el
index d1ec871..23fbc79 100644
--- a/lisp/mastodon-media.el
+++ b/lisp/mastodon-media.el
@@ -38,212 +38,60 @@
:prefix "mastodon-media-"
:group 'mastodon)
-(defvar mastodon-media-show-avatars-p
- (image-type-available-p 'imagemagick)
- "A boolean value stating whether to show avatars in timelines.")
-
-(defvar mastodon-media--generic-avatar-data
- (base64-decode-string
- "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")
- "The PNG data for a generic 100x100 avatar")
-
-(defvar mastodon-media--generic-broken-image-data
- (base64-decode-string
- "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")
- "The PNG data for a generic 200x200 'broken image' view")
-
-(defun mastodon-media--process-image-response (status-plist marker image-options region-length image-url)
- "Callback function processing the url retrieve response for URL.
-
-STATUS-PLIST is the usual plist of status events as per `url-retrieve'.
-IMAGE-OPTIONS are the precomputed options to apply to the image.
-MARKER is the marker to where the response should be visible.
-REGION-LENGTH is the length of the region that should be replaced with the image.
-IMAGE-URL is the URL that was retrieved.
-"
- (let ((url-buffer (current-buffer))
- (is-error-response-p (eq :error (car status-plist))))
+(defun mastodon-media--image-from-url (url)
+ "Takes a URL and return an image."
+ (let ((buffer (url-retrieve-synchronously url)))
(unwind-protect
- (let* ((data (unless is-error-response-p
- (goto-char (point-min))
- (search-forward "\n\n")
- (buffer-substring (point) (point-max))))
- (image (when data
- (apply #'create-image data (when image-options 'imagemagick)
- t image-options))))
- (switch-to-buffer (marker-buffer marker))
- ;; Save narrowing in our buffer
- (let ((inhibit-read-only t))
- (save-restriction
- (widen)
- (put-text-property marker (+ marker region-length) 'media-state 'loaded)
- (when image
- ;; We only set the image to display if we could load
- ;; it; we already have set a default image when we
- ;; added the tag.
- (put-text-property marker (+ marker region-length)
- 'display image))
- ;; We are done with the marker; release it:
- (set-marker marker nil)))
- (kill-buffer url-buffer)))))
-
-(defun mastodon-media--load-image-from-url (url media-type start region-length)
- "Takes a URL and MEDIA-TYPE and load the image asynchronously.
-
-MEDIA-TYPE is a symbol and either 'avatar or 'media-link."
- ;; TODO: Cache the avatars
- (let ((image-options (when (image-type-available-p 'imagemagick)
- (cond
- ((eq media-type 'avatar)
- `(:height ,mastodon-avatar-height))
- ((eq media-type 'media-link)
- `(:max-height ,mastodon-preview-max-height))))))
- (url-retrieve url
- #'mastodon-media--process-image-response
- (list (copy-marker start) image-options region-length url))))
+ (let ((data (with-current-buffer buffer
+ (goto-char (point-min))
+ (search-forward "\n\n")
+ (buffer-substring (point) (point-max)))))
+ (insert "\n")
+ (insert-image (create-image data nil t)))
+ (kill-buffer buffer))))
(defun mastodon-media--select-next-media-line ()
- "Find coordinates of the next media to load.
-
-Returns the list of (`start' . `end', `media-symbol') points of
-that line and string found or nil no more media links were
-found."
- (let ((next-pos (point)))
- (while (and (setq next-pos (next-single-property-change next-pos 'media-state))
- (or (not (eq 'needs-loading (get-text-property next-pos 'media-state)))
- (null (get-text-property next-pos 'media-url))
- (null (get-text-property next-pos 'media-type))))
- ;; do nothing - the loop will proceed
- )
- (when next-pos
- (let ((media-type (get-text-property next-pos 'media-type)))
- (cond
- ;; Avatars are just one character in the buffer
- ((eq media-type 'avatar)
- (list next-pos (+ next-pos 1) 'avatar))
- ;; Media links are 5 character ("[img]")
- ((eq media-type 'media-link)
- (list next-pos (+ next-pos 5) 'media-link)))))))
+ "Find coordinates of a line that contains `Media_Links::'
+
+Returns the cons of (`start' . `end') points of that line or nil no
+more media links were found."
+ (let ((foundp (search-forward-regexp "Media_Link::" nil t)))
+ (when foundp
+ (let ((start (progn (move-beginning-of-line nil) (point)))
+ (end (progn (move-end-of-line nil) (point))))
+ (cons start end)))))
(defun mastodon-media--valid-link-p (link)
"Checks to make sure that the missing string has
not been returned."
(let ((missing "/files/small/missing.png"))
- (and link
- (not (equal link missing)))))
+ (not (equal link missing))))
+
+(defun mastodon-media--line-to-link (line-points)
+ "Returns the url of the media link given at the given point.
+
+`LINE-POINTS' is a cons of (`start' . `end') positions of the line with
+the `Media_Link:: <url>' text."
+ (replace-regexp-in-string "Media_Link:: " ""
+ (buffer-substring
+ (car line-points)
+ (cdr line-points))))
+
+(defun mastodon-media--delete-line (line)
+ "Deletes the current media line"
+ (delete-region (car line) (cdr line)))
(defun mastodon-media--inline-images ()
"Find all `Media_Links:' in the buffer replacing them with the referenced image."
(interactive)
(goto-char (point-min))
- (let (line-details)
- (while (setq line-details (mastodon-media--select-next-media-line))
- (let* ((start (car line-details))
- (end (cadr line-details))
- (media-type (cadr (cdr line-details)))
- (image-url (get-text-property start 'media-url)))
- (if (not (mastodon-media--valid-link-p image-url))
- ;; mark it at least as not needing loading any more
- (put-text-property start end 'media-state 'invalid-url)
- ;; proceed to load this image asynchronously
- (put-text-property start end 'media-state 'loading)
- (mastodon-media--load-image-from-url image-url media-type start (- end start)))))))
-
-(defun mastodon-media--get-avatar-rendering (avatar-url)
- "Returns the string to be written that renders the avatar at AVATAR-URL."
- ;; We use just an empty space as the textual representation.
- ;; This is what a user will see on a non-graphical display
- ;; where not showing an avatar at all is preferable.
- (let ((image-options (when (image-type-available-p 'imagemagick)
- `(:height ,mastodon-avatar-height))))
- (concat
- (propertize " "
- 'media-url avatar-url
- 'media-state 'needs-loading
- 'media-type 'avatar
- 'display (apply #'create-image mastodon-media--generic-avatar-data
- (when image-options 'imagemagick)
- t image-options))
- " ")))
-
-(defun mastodon-media--get-media-link-rendering (media-url)
- "Returns the string to be written that renders the image at MEDIA-URL."
- (concat
- (propertize "[img]"
- 'media-url media-url
- 'media-state 'needs-loading
- 'media-type 'media-link
- 'display (create-image mastodon-media--generic-broken-image-data nil t))
- " "))
+ (let (line-coordinates)
+ (while (setq line-coordinates (mastodon-media--select-next-media-line))
+ (let ((link (mastodon-media--line-to-link line-coordinates)))
+ (when (mastodon-media--valid-link-p link)
+ (mastodon-media--image-from-url link)
+ (mastodon-media--delete-line line-coordinates))))))
(provide 'mastodon-media)
;;; mastodon-media.el ends here