;;; my-openlibrary.el -- openlibrary client -*- lexical-binding: t -*- ;; Copyright (C) 2023 Free Software Foundation. ;; Author: Yuchen Pei ;; Package-Requires: ((emacs "28.2")) ;; This file is part of dotfiles. ;; dotfiles is free software: you can redistribute it and/or modify it under ;; the terms of the GNU Affero General Public License as published by ;; the Free Software Foundation, either version 3 of the License, or ;; (at your option) any later version. ;; dotfiles 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 Affero General ;; Public License for more details. ;; You should have received a copy of the GNU Affero General Public ;; License along with dotfiles. If not, see . ;;; Commentary: ;; openlibrary client. ;;; Code: ;;; an openlibrary client (require 'generic-search) (require 'my-net) (defvar my-openlibrary-host "https://openlibrary.org") (defun my-openlibrary-api-book-by-olid (olid) (my-url-fetch-json (format "%s/api/books?bibkeys=OLID:%s&format=json&jscmd=data" my-openlibrary-host olid))) (defun my-openlibrary-html-book-by-url (url) (list (cons 'description (string-trim (dom-texts (dom-by-class (my-url-fetch-dom url) "book-description-content restricted-view")))))) (defun my-grok-openlibrary (url) "grok openlibrary. title, subtitle, description, subjects, authors (by_statement?), classification, publisher, publish_places, publish_date, subjects, cover" (when (string-match (concat my-openlibrary-host "/books/\\([^/]+\\)") url) (my-grok-openlibrary-make-info (append (my-openlibrary-api-book-by-olid (match-string 1 url)) (my-openlibrary-html-book-by-url url))))) (defun my-grok-openlibrary-make-info (info) (list (cons "Title" (alist-get 'title info)) (cons "Subtitle" (alist-get 'subtitle info)) (cons "Authors" (string-join (mapcar (lambda (author) (alist-get 'name author)) (alist-get 'authors info)) ", ")) (cons "Pages" (when (alist-get 'number_of_pages info) (number-to-string (alist-get 'number_of_pages info)))) (cons "OpenLibrary-link" (alist-get 'url info)) (cons "OpenLibrary-ID" (string-join (alist-get 'openlibrary info) ",")) (cons "ISBN" (string-join (vconcat (alist-get 'isbn_13 (alist-get 'identifiers info)) (alist-get 'isbn_10 (alist-get 'identifiers info))) ", ")) (cons "Dewey-Decimal" (alist-get 'dewey_decimal_class info)) (cons "Subject" (string-join (seq-take (remove-duplicates (mapcar (lambda (subject) (alist-get 'name subject)) (alist-get 'subjects info)) :test 'string=) 20) ", ")) (cons "Cover" (alist-get 'large (alist-get 'cover info))) (cons "Published" (alist-get 'publish_date info)) (cons "Description" (alist-get 'description info)))) (defun my-openlibrary-api-book-by-isbn (isbn) (my-url-fetch-json (format "%s/api/books?bibkeys=ISBN:%s&format=json&jscmd=data" my-openlibrary-host isbn))) (defun my-grok-openlibrary-isbn (isbn) (unless isbn (error "isbn not supplied")) (let* ((info-json (alist-get (intern (format "ISBN:%s" isbn)) (my-openlibrary-api-book-by-isbn isbn))) (url (alist-get 'url info-json)) (info-html (my-openlibrary-html-book-by-url url))) (my-grok-openlibrary-make-info (append info-json info-html)))) (defun my-openlibrary-api-search (query) (my-url-fetch-json (format "%s/search.json?q=%s" my-openlibrary-host query))) (defun my-openlibrary-format-result (info) (format "%s - %s [%s] (%s)" (string-join (alist-get 'author_name info) ", ") (alist-get 'title info) (string-join (alist-get 'isbn info) ",") (alist-get 'publish_date info))) (defun my-openlibrary-action (info) (interactive) (my-org-create-node (my-grok-openlibrary-isbn (elt (alist-get 'isbn info) 0)) t)) (defun my-openlibrary-show-more-info () (interactive) (pp (my-grok-openlibrary-isbn (elt (alist-get 'isbn (get-text-property (point) 'button-data)) 0)))) (defvar my-openlibrary-button-keymap (let ((kmap (make-sparse-keymap))) (set-keymap-parent kmap button-map) (define-key kmap "p" 'my-openlibrary-show-more-info) kmap)) (defun my-openlibrary-search (query) (interactive "sQuery: ") (generic-search-open (alist-get 'docs (my-openlibrary-api-search query)) (format "openlibrary-query:%s" query) `((formatter . my-openlibrary-format-result) (default-action . my-openlibrary-action) (keymap . ,my-openlibrary-button-keymap)))) (provide 'my-openlibrary) ;;; my-openlibrary.el ends here