Use request.el to make http requests
This commit is contained in:
parent
3cf37e7c80
commit
8a1cfd3bfe
1 changed files with 24 additions and 35 deletions
|
@ -6,7 +6,7 @@
|
||||||
;; Description: Make Anki Cards in Org-mode
|
;; Description: Make Anki Cards in Org-mode
|
||||||
;; Author: Louie Tan
|
;; Author: Louie Tan
|
||||||
;; Version: 0.2.1
|
;; Version: 0.2.1
|
||||||
;; Package-Requires: ((emacs "25"))
|
;; Package-Requires: ((emacs "25") (request "0.3.0"))
|
||||||
;; URL: https://github.com/louietan/anki-editor
|
;; URL: https://github.com/louietan/anki-editor
|
||||||
;;
|
;;
|
||||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
@ -63,6 +63,7 @@
|
||||||
(require 'json)
|
(require 'json)
|
||||||
(require 'org-element)
|
(require 'org-element)
|
||||||
(require 'ox)
|
(require 'ox)
|
||||||
|
(require 'request)
|
||||||
(require 'seq)
|
(require 'seq)
|
||||||
|
|
||||||
(defconst anki-editor-prop-note-type "ANKI_NOTE_TYPE")
|
(defconst anki-editor-prop-note-type "ANKI_NOTE_TYPE")
|
||||||
|
@ -104,29 +105,23 @@ See https://apps.ankiweb.net/docs/manual.html#latex-conflicts.")
|
||||||
(if params
|
(if params
|
||||||
(push `("params" . ,params) data)
|
(push `("params" . ,params) data)
|
||||||
data)))
|
data)))
|
||||||
(request-tempfile (make-temp-file "emacs-anki-editor")))
|
(request-backend 'curl)
|
||||||
|
(json-array-type 'list)
|
||||||
|
reply err)
|
||||||
|
|
||||||
(with-temp-file request-tempfile
|
(request (format "http://%s:%s"
|
||||||
(setq buffer-file-coding-system 'utf-8)
|
anki-editor-anki-connect-listening-address
|
||||||
(set-buffer-multibyte t)
|
anki-editor-anki-connect-listening-port)
|
||||||
(insert request-body))
|
:type "POST"
|
||||||
|
:parser 'json-read
|
||||||
(let* ((raw-resp (shell-command-to-string
|
:data (encode-coding-string request-body 'utf-8)
|
||||||
(format "curl %s:%s --silent -X POST --data-binary @%s"
|
:success (cl-function (lambda (&key data &allow-other-keys)
|
||||||
(shell-quote-argument anki-editor-anki-connect-listening-address)
|
(setq reply data)))
|
||||||
(shell-quote-argument anki-editor-anki-connect-listening-port)
|
:error (cl-function (lambda (&key _ &key error-thrown &allow-other-keys)
|
||||||
(shell-quote-argument request-tempfile))))
|
(setq err (string-trim (cdr error-thrown)))))
|
||||||
resp error)
|
:sync t)
|
||||||
(condition-case err
|
(when err (error "Error communicating with AnkiConnect using cURL: %s" err))
|
||||||
(let ((json-array-type 'list))
|
(or reply (error "Got empty reply from AnkiConnect"))))
|
||||||
(setq resp (json-read-from-string raw-resp)
|
|
||||||
error (alist-get 'error resp)))
|
|
||||||
(error (setq error
|
|
||||||
(format "Unexpected error communicating with AnkiConnect: %s, the response was %s"
|
|
||||||
(error-message-string err)
|
|
||||||
(prin1-to-string raw-resp)))))
|
|
||||||
`((result . ,(alist-get 'result resp))
|
|
||||||
(error . ,error)))))
|
|
||||||
|
|
||||||
(defmacro anki-editor--anki-connect-invoke-result (&rest args)
|
(defmacro anki-editor--anki-connect-invoke-result (&rest args)
|
||||||
"Invoke AnkiConnect with ARGS, return the result from response or raise an error."
|
"Invoke AnkiConnect with ARGS, return the result from response or raise an error."
|
||||||
|
@ -148,16 +143,10 @@ See https://apps.ankiweb.net/docs/manual.html#latex-conflicts.")
|
||||||
;; to be type of list.
|
;; to be type of list.
|
||||||
(cons "tags" (vconcat .tags)))))
|
(cons "tags" (vconcat .tags)))))
|
||||||
|
|
||||||
(defun anki-editor--anki-connect-heading-to-note (heading)
|
|
||||||
"Convert HEADING to a note in the form that AnkiConnect accepts."
|
|
||||||
(anki-editor--anki-connect-map-note
|
|
||||||
(anki-editor--heading-to-note heading)))
|
|
||||||
|
|
||||||
(defun anki-editor--anki-connect-store-media-file (path)
|
(defun anki-editor--anki-connect-store-media-file (path)
|
||||||
"Store media file for PATH, which is an absolute file name.
|
"Store media file for PATH, which is an absolute file name.
|
||||||
The result is the path to the newly stored media file."
|
The result is the path to the newly stored media file."
|
||||||
(unless (and (executable-find "base64")
|
(unless (every #'executable-find '("base64" "sha1sum"))
|
||||||
(executable-find "sha1sum"))
|
|
||||||
(error "Please make sure `base64' and `sha1sum' are available from your shell, which are required for storing media files"))
|
(error "Please make sure `base64' and `sha1sum' are available from your shell, which are required for storing media files"))
|
||||||
|
|
||||||
(let* ((content (string-trim
|
(let* ((content (string-trim
|
||||||
|
@ -238,14 +227,14 @@ of that heading."
|
||||||
(acc 0)
|
(acc 0)
|
||||||
(failed 0))
|
(failed 0))
|
||||||
(message "Counting notes...")
|
(message "Counting notes...")
|
||||||
(org-map-entries (lambda () (incf total)) match scope)
|
(org-map-entries (lambda () (cl-incf total)) match scope)
|
||||||
(org-map-entries (lambda ()
|
(org-map-entries (lambda ()
|
||||||
(message "[%d/%d] Processing notes in buffer \"%s\", wait a moment..."
|
(message "[%d/%d] Processing notes in buffer \"%s\", wait a moment..."
|
||||||
(incf acc) total (buffer-name))
|
(cl-incf acc) total (buffer-name))
|
||||||
(anki-editor--clear-failure-reason)
|
(anki-editor--clear-failure-reason)
|
||||||
(condition-case err
|
(condition-case err
|
||||||
(anki-editor--process-note-heading)
|
(anki-editor--process-note-heading)
|
||||||
(error (incf failed)
|
(error (cl-incf failed)
|
||||||
(anki-editor--set-failure-reason (error-message-string err)))))
|
(anki-editor--set-failure-reason (error-message-string err)))))
|
||||||
match
|
match
|
||||||
scope)
|
scope)
|
||||||
|
@ -468,11 +457,11 @@ Do nothing when JUST-ALIGN is non-nil."
|
||||||
|
|
||||||
(defun anki-editor--heading-to-note (heading)
|
(defun anki-editor--heading-to-note (heading)
|
||||||
"Construct an alist representing a note for HEADING."
|
"Construct an alist representing a note for HEADING."
|
||||||
(let (deck note-id note-type tags fields)
|
(let ((org-trust-scanner-tags t)
|
||||||
|
deck note-id note-type tags fields)
|
||||||
(setq deck (org-entry-get-with-inheritance anki-editor-prop-deck)
|
(setq deck (org-entry-get-with-inheritance anki-editor-prop-deck)
|
||||||
note-id (org-entry-get nil anki-editor-prop-note-id)
|
note-id (org-entry-get nil anki-editor-prop-note-id)
|
||||||
note-type (org-entry-get nil anki-editor-prop-note-type)
|
note-type (org-entry-get nil anki-editor-prop-note-type)
|
||||||
;; TODO: use `org-scanner-tags' instead, which is said to be faster
|
|
||||||
tags (org-get-tags-at)
|
tags (org-get-tags-at)
|
||||||
fields (mapcar #'anki-editor--heading-to-note-field (anki-editor--get-subheadings heading)))
|
fields (mapcar #'anki-editor--heading-to-note-field (anki-editor--get-subheadings heading)))
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue