150 lines
4.4 KiB
Python
150 lines
4.4 KiB
Python
import json
|
|
import logging
|
|
from typing import Optional
|
|
import urllib
|
|
|
|
import requests
|
|
|
|
from thefuzz import fuzz
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
ISBN_URL = "https://openlibrary.org/isbn/{isbn}.json"
|
|
SEARCH_URL = "https://openlibrary.org/search.json?q={query}&sort=editions&mode=everything"
|
|
AUTHOR_SEARCH_URL = "https://openlibrary.org/search/authors.json?q={query}"
|
|
COVER_URL = "https://covers.openlibrary.org/b/olid/{id}-L.jpg"
|
|
AUTHOR_URL = "https://openlibrary.org/authors/{id}.json"
|
|
AUTHOR_IMAGE_URL = "https://covers.openlibrary.org/a/olid/{id}-L.jpg"
|
|
|
|
|
|
def get_first(key: str, result: dict) -> str:
|
|
obj = ""
|
|
if obj_list := result.get(key):
|
|
obj = obj_list[0]
|
|
return obj
|
|
|
|
|
|
def get_author_openlibrary_id(name: str) -> str:
|
|
search_url = AUTHOR_SEARCH_URL.format(query=name)
|
|
response = requests.get(search_url)
|
|
|
|
if response.status_code != 200:
|
|
logger.warn(f"Bad response from OL: {response.status_code}")
|
|
return ""
|
|
|
|
results = json.loads(response.content)
|
|
|
|
if not results:
|
|
logger.warn(f"No author results found from search for {name}")
|
|
return ""
|
|
|
|
try:
|
|
result = results.get("docs", [])[0]
|
|
except IndexError:
|
|
result = {"key": ""}
|
|
return result.get("key")
|
|
|
|
|
|
def lookup_author_from_openlibrary(olid: str) -> dict:
|
|
author_url = AUTHOR_URL.format(id=olid)
|
|
response = requests.get(author_url)
|
|
|
|
if response.status_code != 200:
|
|
logger.warn(f"Bad response from OL: {response.status_code}")
|
|
return {}
|
|
|
|
results = json.loads(response.content)
|
|
|
|
if not results:
|
|
logger.warn(f"No author results found from OL for {olid}")
|
|
return {}
|
|
|
|
remote_ids = results.get("remote_ids", {})
|
|
bio = ""
|
|
if results.get("bio"):
|
|
try:
|
|
bio = results.get("bio").get("value")
|
|
except AttributeError:
|
|
bio = results.get("bio")
|
|
return {
|
|
"name": results.get("name"),
|
|
"openlibrary_id": olid,
|
|
"wikipedia_url": results.get("wikipedia"),
|
|
"wikidata_id": remote_ids.get("wikidata"),
|
|
"isni": remote_ids.get("isni"),
|
|
"goodreads_id": remote_ids.get("goodreads"),
|
|
"librarything_id": remote_ids.get("librarything"),
|
|
"amazon_id": remote_ids.get("amazon"),
|
|
"bio": bio,
|
|
"author_headshot_url": AUTHOR_IMAGE_URL.format(id=olid),
|
|
}
|
|
|
|
|
|
def lookup_book_from_openlibrary(
|
|
title: str, author: Optional[str] = None
|
|
) -> dict:
|
|
title_quoted = urllib.parse.quote(title)
|
|
author_quoted = ""
|
|
if author:
|
|
author_quoted = urllib.parse.quote(author)
|
|
query = f"{title_quoted} {author_quoted}"
|
|
|
|
search_url = SEARCH_URL.format(query=query)
|
|
response = requests.get(search_url)
|
|
|
|
if response.status_code != 200:
|
|
logger.warn(f"Bad response from OL: {response.status_code}")
|
|
return {}
|
|
|
|
results = json.loads(response.content)
|
|
|
|
if len(results.get("docs")) == 0:
|
|
logger.warn(f"No results found from OL for {title}")
|
|
return {}
|
|
|
|
top = None
|
|
for result in results.get("docs"):
|
|
if fuzz.ratio(title.lower(), result.get("title", "").lower()) > 90:
|
|
top = result
|
|
break
|
|
|
|
if not top:
|
|
for result in results.get("docs"):
|
|
# These Summary things suck and ruin our one-shot search
|
|
if "Summary of" in result.get("title"):
|
|
continue
|
|
|
|
if title.lower() in result.get("title", "").lower():
|
|
top = result
|
|
|
|
if not top and len(results.get("docs")) > 0:
|
|
top = results.get("docs")[0]
|
|
|
|
if not top:
|
|
logger.warn(f"No book found for query {query}")
|
|
return {}
|
|
|
|
ol_id = top.get("cover_edition_key")
|
|
ol_author_id = get_first("author_key", top)
|
|
first_sentence = ""
|
|
if top.get("first_sentence"):
|
|
try:
|
|
first_sentence = top.get("first_sentence")[0].get("value")
|
|
except AttributeError:
|
|
first_sentence = top.get("first_sentence")[0]
|
|
isbn = None
|
|
if top.get("isbn"):
|
|
isbn = top.get("isbn")[0]
|
|
return {
|
|
"title": top.get("title"),
|
|
"isbn": isbn,
|
|
"openlibrary_id": ol_id,
|
|
"goodreads_id": get_first("id_goodreads", top),
|
|
"first_publish_year": top.get("first_publish_year"),
|
|
"first_sentence": first_sentence,
|
|
"pages": top.get("number_of_pages_median", None),
|
|
"cover_url": COVER_URL.format(id=ol_id),
|
|
"ol_author_id": ol_author_id,
|
|
"subject_key_list": top.get("subject_key", []),
|
|
}
|