Created
September 7, 2020 14:48
-
-
Save TuringMachinegun/dde781e5f6667e373db5423f2517ae93 to your computer and use it in GitHub Desktop.
Post markdown with images to micro.blog in emacs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(require 'request) | |
(setq mb-emacs-app-token "123456789") ;; create this in account -> app tokens -> edit apps | |
(setq mb-micropub-endpoint "https://micro.blog/micropub") | |
(setq mb-destination-address "https://your.micro.blog") | |
(setq mb-image-upload-timeout 20) ;; seconds | |
(defun mb-get-media-endpoint () | |
(cdr (assoc "media-endpoint" | |
(let (result) | |
(request | |
mb-micropub-endpoint | |
:params '(("q" . "config")) | |
:type "GET" | |
:sync t | |
:timeout: 10 | |
:parser 'json-read | |
:headers `(("Content-Type" . "application/json") | |
("Authorization".,(format "Bearer %s" mb-emacs-app-token))) | |
:complete (cl-function | |
(lambda (&key data &allow-other-keys) | |
(setq result data)))) | |
(if result | |
result | |
(error "Can't get media endpoint"))) | |
#'string=))) | |
(defun mb-upload-image (img-path media-endpoint) | |
"Post inline images." | |
(cdr (assoc "url" | |
(let ((result)) | |
(request | |
(concat media-endpoint | |
(if (boundp 'mb-destination-address) (concat "?mp-destination=" mb-destination-address))) | |
:type "POST" | |
:files `(("file" . ,img-path)) | |
:headers `(("Content-Type" . "multipart/form-data") | |
("Authorization".,(format "Bearer %s" mb-emacs-app-token))) | |
:sync t | |
:timeout mb-image-upload-timeout | |
:parser 'json-read | |
:success (cl-function | |
(lambda (&key data &allow-other-keys) | |
(setq result data)))) | |
(if result | |
result | |
(error "Error in uploading."))) | |
#'string=))) | |
(defun mb-markdown-upload-images-substitute-links () | |
"Upload images to micro.blog and substitute their local links with the upload locations." | |
(interactive) | |
(save-excursion | |
(save-restriction | |
(let ((media-endpoint (mb-get-media-endpoint))) | |
(widen) | |
(goto-char (point-min)) | |
(while (re-search-forward markdown-regex-link-inline nil t) | |
(let ((start (match-beginning 0)) | |
(imagep (match-beginning 1)) | |
(end (match-end 0)) | |
(file (match-string-no-properties 6))) | |
(when (and imagep | |
(not (zerop (length file)))) | |
(when (file-exists-p file) | |
(let* ((abspath (if (file-name-absolute-p file) | |
file | |
(concat default-directory file))) | |
(img-upload-url (save-match-data (mb-upload-image abspath media-endpoint)))) | |
(replace-match img-upload-url t t nil 6)))))))))) | |
(defun mb-post-buffer () | |
"Post current buffer to micro.blog (possibly as draft)." | |
(interactive) | |
(if (yes-or-no-p "Are you sure you want to post this?") | |
(save-restriction | |
(widen) | |
(let ((buffer-contents (buffer-substring-no-properties (point-min) (point-max))) | |
(mb-post-name (read-string "Enter post name (leave empty if none):")) | |
(mb-post-status `(post-status . [,(if (yes-or-no-p "Post as draft?") "draft" "published")]))) | |
;; copy content of current buffer to new buffer, | |
;; then upload eventual linked images, substitute links with the upload locations, send buffer to microblog | |
(with-current-buffer (generate-new-buffer "post2mb") | |
(goto-char (point-min)) | |
(insert buffer-contents) | |
(goto-char (point-min)) | |
(mb-markdown-upload-images-substitute-links) | |
(request | |
(concat mb-micropub-endpoint | |
(if (boundp 'mb-destination-address) (concat "?mp-destination=" mb-destination-address))) | |
:type "POST" | |
:data (json-encode `((type . ["h-entry"]) | |
(properties | |
(content . [,(buffer-substring-no-properties (point-min) (point-max))]) | |
(name . [,mb-post-name]) ,mb-post-status))) | |
:headers `(("Content-Type" . "application/json") | |
("Authorization".,(format "Bearer %s" mb-emacs-app-token))) | |
:success (cl-function | |
(lambda (&key data &allow-other-keys) | |
(message "Success."))))))))) |
Hi Thadeej, I'm also no Lisp programmer, so let's see if I'm of any help!
What about if instead of setting the token as a variable, you create a function which, when called, returns the token?
Something like this (didn't test it):
(defun get-mb-emacs-app-token ()
"Return mb token from .authinfo.gpg"
(plist-get (car (auth-source-search :host "micro.blog")) :secret)
)
Then the headers section in the requests just becomes
:headers `(("Content-Type" . "application/json")
("Authorization".,(format "Bearer %s" (get-mb-emacs-app-token))))
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I am absolutely loving this function.
I've used Emacs off-and-on for awhile, but I'm no Lisp programmer. And this posting to micro.blog is something that's keeping me active in Emacs.
I was hoping I might be able to get your help in making this function a little more "secure" by not setting our app-token in plain text.
By using .authinfo.gpg I am able to set my token in an encrypted file.
This function will allow me to set my token as a variable (as you define it: mb-emacs-app-token):
However, that sets my token as a plain text variable that can be seen in a buffer throughout all of Emacs.
I'm thinking that using this inside of your function should work:
If so, this would allow me (and anyone else) to more safely call the token. I've just not been able to figure out how or where this could fit into your code.
What are you thoughts on this?