81 lines
3.2 KiB
EmacsLisp
81 lines
3.2 KiB
EmacsLisp
(defun my/get-url-title (url)
|
|
"Attempt to retrieve the title string from the given URL.
|
|
|
|
Assuming the URL points to an HTML source.
|
|
|
|
Returns nil if there is a non-200 return status or no title could
|
|
be found."
|
|
(let* ((command (format "curl --fail --silent %s" url))
|
|
(html (shell-command-to-string command))
|
|
(regexp (rx (seq "<title>"
|
|
(group (+ (not (any "<" ">"))))
|
|
"</title>")))
|
|
(matches (string-match regexp html)))
|
|
(match-string 1 html)))
|
|
|
|
(defun my/denote/url-clipboard ()
|
|
"Return the URL from the system clipboard, if any."
|
|
(let ((clipboard (my/clipboard-get)))
|
|
(when (org-url-p clipboard)
|
|
clipboard)))
|
|
|
|
(defvar my/denote/url-functions
|
|
'(thing-at-point-url-at-point my/denote/url-clipboard)
|
|
"List of function symbols to call to get an URL candidate.
|
|
|
|
Each function should return a string with the URL or a cons
|
|
cell (URL . TITLE), where title is either a string or a function
|
|
returning a string.")
|
|
|
|
(defun my/denote/url (url &optional title)
|
|
"Create a new Org-based note based on a URL.
|
|
|
|
URL can be a string or a cons cell (URL . TITLE). The TITLE, in
|
|
turn, can be a string or a function (without arguments) to
|
|
retrieve the title.
|
|
|
|
When called interactively, the candidate URLs are obtained from
|
|
the variable `my/denote/url-functions' (e.g. takes the URL from
|
|
the clipboard).
|
|
|
|
In case no TTTLE is passed to this function, or the URL wasn't
|
|
paired with a title value, the title is obtained by curl(1) by
|
|
looking at the <title> tags."
|
|
(interactive (list
|
|
(let* ((prompt (format-prompt "URL" ""))
|
|
(candidate-urls (-non-nil (mapcar #'funcall my/denote/url-functions)))
|
|
(url (if (eql 1 (length candidate-urls))
|
|
(read-string prompt (car candidate-urls))
|
|
(completing-read prompt candidate-urls))))
|
|
|
|
;; `candidate-urls' is a mix of strings and cons
|
|
;; cells. If the selected URL comes from a cons
|
|
;; cell, (assoc) will return it. If it comes from a
|
|
;; string valuo, (assoc) will return nil. In that
|
|
;; case return the URL as is.
|
|
(or (assoc url candidate-urls #'string=) url))
|
|
nil))
|
|
(denote
|
|
(read-string (format-prompt "Title" "")
|
|
|
|
;; initial input. If no title was passed, see if it
|
|
;; can be obtained from the URL value (the cdr if the
|
|
;; url was a cons cell.
|
|
(or
|
|
title
|
|
(cond ((and (consp url) (stringp (cdr url))) (cdr url))
|
|
((and (consp url) (functionp (cdr url))) (funcall (cdr url)))
|
|
((stringp url) (my/get-url-title url)))))
|
|
(denote-keywords-prompt)
|
|
'org
|
|
(denote-subdirectory-prompt))
|
|
(org-set-property "URL" url))
|
|
|
|
(defun my/elfeed/entry-url ()
|
|
"Return the URL of the current elfeed entry."
|
|
(when-let ((entry (or elfeed-show-entry
|
|
(elfeed-search-selected :ignore-region))))
|
|
(cons (elfeed-entry-link entry)
|
|
(elfeed-entry-title entry))))
|
|
|
|
(add-to-list 'my/denote/url-functions #'my/elfeed/entry-url)
|