|
;;; org-ref-isbn.el --- utilities for generating bibtex entries from an ISBN -*- lexical-binding: t; -*-
|
|
|
|
;; Copyright (C) 2015 John Kitchin
|
|
|
|
;; Author: John Kitchin <jkitchin@andrew.cmu.edu>
|
|
;; Keywords: convenience
|
|
|
|
;; This program is free software; you can redistribute it and/or modify
|
|
;; it under the terms of the GNU General Public License as published by
|
|
;; the Free Software Foundation, either version 3 of the License, or
|
|
;; (at your option) any later version.
|
|
|
|
;; This program is distributed in the hope that it will be useful,
|
|
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
;; GNU General Public License for more details.
|
|
|
|
;; You should have received a copy of the GNU General Public License
|
|
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
;;; Commentary:
|
|
|
|
;; Provides functions to download bibtex entries from isbn numbers.
|
|
|
|
;;; Code:
|
|
(require 'f)
|
|
(require 'org)
|
|
(require 'org-ref-core)
|
|
|
|
(defvar url-http-end-of-headers)
|
|
|
|
;;* ISBN utility
|
|
|
|
(defcustom org-ref-isbn-clean-bibtex-entry-hook
|
|
'(oricb-remove-enclosing-brackets
|
|
oricb-clean-author-field
|
|
oricb-remove-period
|
|
oricb-kill-fields
|
|
oricb-replace-field-names)
|
|
"Hook that is run in `org-ref-isbn-clean-bibtex-entry'.
|
|
The functions should have no arguments, and operate on the bibtex
|
|
entry at point. You can assume point starts at the beginning of the
|
|
entry. These functions are wrapped in `save-restriction' and
|
|
`save-excursion' so you do not need to save the point position."
|
|
:group 'org-ref-isbn
|
|
:type 'hook)
|
|
|
|
|
|
(defcustom org-ref-isbn-exclude-fields nil
|
|
"List of bibtex fields to kill when new entry is inserted."
|
|
:group 'org-ref-isbn
|
|
:type '(repeat :tag "List of bibtex fields to kill" string))
|
|
|
|
|
|
(defcustom org-ref-isbn-field-name-replacements nil
|
|
"List of bitex field name/replacement pairs.
|
|
The entries in this list are cons cells where the car is the field name
|
|
and cdr is the replacement name."
|
|
:group 'org-ref-isbn
|
|
:type '(repeat (cons (string :tag "Field name")
|
|
(string :tag "Field name replacement"))))
|
|
|
|
|
|
(defun oricb-replace-field-names ()
|
|
"Replace bibtex field names defined in
|
|
`org-ref-isbn-field-name-replacements'."
|
|
(when org-ref-isbn-field-name-replacements
|
|
(mapcar (lambda (field)
|
|
(bibtex-beginning-of-entry)
|
|
(let ((f (bibtex-autokey-get-field (car field))))
|
|
(unless (string= "" f)
|
|
(goto-char (cadr (bibtex-search-forward-field (car field) t)))
|
|
(bibtex-kill-field)
|
|
(bibtex-make-field (cdr field))
|
|
(backward-char)
|
|
(insert f))))
|
|
org-ref-isbn-field-name-replacements)))
|
|
|
|
|
|
(defun oricb-kill-fields ()
|
|
"Kill all bibtex fields defined in `org-ref-isbn-exclude-fields'."
|
|
(when org-ref-isbn-exclude-fields
|
|
(mapcar (lambda (field)
|
|
(bibtex-beginning-of-entry)
|
|
(let ((f (bibtex-autokey-get-field field)))
|
|
(unless (string= "" f)
|
|
(goto-char (cadr (bibtex-search-forward-field field t)))
|
|
(bibtex-kill-field))))
|
|
org-ref-isbn-exclude-fields)))
|
|
|
|
|
|
(defun oricb-remove-enclosing-brackets ()
|
|
"Remove enclosing brackets from fields."
|
|
(save-restriction
|
|
(bibtex-narrow-to-entry)
|
|
(while (re-search-forward "\\({\\)\\(\\[\\)\\(.+\\)\\(]\\)\\(}\\)" nil t)
|
|
(replace-match "\\1\\3\\5"))))
|
|
|
|
|
|
(defun oricb-clean-author-field ()
|
|
"Remove extra information from author's field."
|
|
(goto-char (cadr (bibtex-search-forward-field "author" t)))
|
|
(let ((case-fold-search nil))
|
|
(when (re-search-forward "\\({\\)\\(by \\|ed. by \\|edited by \\)" nil t)
|
|
(replace-match "\\1"))))
|
|
|
|
|
|
(defun oricb-remove-period ()
|
|
"Remove period from author's field."
|
|
(goto-char (cadr (bibtex-search-forward-field "author" t)))
|
|
(when (re-search-forward "\\(\\.\\)\\(}\\)" nil t)
|
|
(replace-match "\\2")))
|
|
|
|
|
|
;;;###autoload
|
|
(defun org-ref-isbn-clean-bibtex-entry ()
|
|
"Clean a bibtex entry inserted via `isbn-to-bibtex'.
|
|
See functions in `org-ref-isbn-clean-bibtex-entry-hook'."
|
|
(interactive)
|
|
(bibtex-beginning-of-entry)
|
|
(mapc (lambda (x)
|
|
(save-restriction
|
|
(save-excursion
|
|
(funcall x))))
|
|
org-ref-isbn-clean-bibtex-entry-hook))
|
|
|
|
|
|
;; I found this on the web. It can be handy, but the bibtex entry has a lot of stuff in it.
|
|
|
|
;;;###autoload
|
|
(defun isbn-to-bibtex-lead (isbn)
|
|
"Search lead.to for ISBN bibtex entry.
|
|
You have to copy the entry if it is on the page to your bibtex
|
|
file."
|
|
(interactive "sISBN: ")
|
|
(browse-url
|
|
(format
|
|
"http://lead.to/amazon/en/?key=%s+&si=all&op=bt&bn=&so=sa&ht=us"
|
|
isbn)))
|
|
|
|
|
|
;; Here we get isbn metadata and build a bibtex entry.
|
|
;; http://xisbn.worldcat.org/xisbnadmin/doc/api.htm#getmetadata
|
|
|
|
;;;###autoload
|
|
(defun isbn-to-bibtex (isbn bibfile)
|
|
"Get bibtex entry for ISBN and insert it into BIBFILE.
|
|
Nothing happens if an entry with the generated key already exists
|
|
in the file. Data comes from worldcat."
|
|
(interactive
|
|
(list
|
|
(read-string
|
|
"ISBN: "
|
|
;; now set initial input
|
|
(cond
|
|
;; If region is active and it starts with a number, we use it
|
|
((and (region-active-p)
|
|
(s-match "^[0-9]" (buffer-substring (region-beginning) (region-end))))
|
|
(buffer-substring (region-beginning) (region-end)))
|
|
;; if first entry in kill ring starts with a number assume it is an isbn
|
|
;; and use it as the guess
|
|
((stringp (car kill-ring))
|
|
(when (s-match "^[0-9]" (car kill-ring))
|
|
(car kill-ring)))
|
|
;; type or paste it in
|
|
(t
|
|
nil)))
|
|
(completing-read "Bibfile: " (org-ref-possible-bibfiles))))
|
|
|
|
(let* ((url (format "https://www.ottobib.com/isbn/%s/bibtex" isbn))
|
|
(entry))
|
|
(with-current-buffer (url-retrieve-synchronously url t t)
|
|
(goto-char (point-min))
|
|
(when (re-search-forward "@[a-zA-Z]+{.+\\(\n\s+[a-z\s={\.,?:;'0-9\n}-]+\\)+}$" nil t)
|
|
(setq entry (match-string 0))))
|
|
|
|
(if (not entry)
|
|
(message "Nothing found.")
|
|
(find-file bibfile)
|
|
(goto-char (point-max))
|
|
(insert (with-temp-buffer
|
|
(insert (concat entry "\n}"))
|
|
(goto-char (point-min))
|
|
(org-ref-isbn-clean-bibtex-entry)
|
|
(org-ref-clean-bibtex-entry)
|
|
(bibtex-fill-entry)
|
|
(s-trim (buffer-string))
|
|
(buffer-string)))
|
|
(save-buffer))))
|
|
|
|
(provide 'org-ref-isbn)
|
|
;;; org-ref-isbn.el ends here
|