161 lines
5.2 KiB
Python
161 lines
5.2 KiB
Python
import logging
|
|
|
|
import requests
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
OPENLIBRARY_BASE_URL = "https://openlibrary.org"
|
|
|
|
|
|
def lookup_book_from_openlibrary(title: str, author: str | None = None) -> dict:
|
|
try:
|
|
response = requests.get(
|
|
f"{OPENLIBRARY_BASE_URL}/search.json",
|
|
params={"title": title, "limit": 5},
|
|
timeout=10,
|
|
)
|
|
response.raise_for_status()
|
|
search_results = response.json()
|
|
except Exception as e:
|
|
logger.warning(f"Could not search for {title}: {e}")
|
|
return {}
|
|
|
|
docs = search_results.get("docs", [])
|
|
|
|
title_lower = title.lower()
|
|
for work_doc in docs:
|
|
found_title = work_doc.get("title", "")
|
|
if found_title.lower() == title_lower:
|
|
olid = work_doc.get("key", "").replace("/works/", "")
|
|
if not olid:
|
|
continue
|
|
break
|
|
else:
|
|
logger.info(f"OpenLibrary: no close match for '{title}', skipping")
|
|
return {}
|
|
|
|
try:
|
|
work_response = requests.get(
|
|
f"{OPENLIBRARY_BASE_URL}/works/{olid}.json", timeout=10
|
|
)
|
|
work_response.raise_for_status()
|
|
work_json = work_response.json()
|
|
except Exception as e:
|
|
logger.warning(f"Could not get work JSON for {olid}: {e}")
|
|
return {}
|
|
|
|
book_dict: dict = {"title": work_json.get("title"), "openlibrary_id": olid}
|
|
|
|
description = work_json.get("description")
|
|
if description:
|
|
if isinstance(description, dict):
|
|
book_dict["summary"] = description.get("value", "")
|
|
else:
|
|
book_dict["summary"] = str(description)
|
|
|
|
subjects = work_json.get("subjects", [])
|
|
if subjects:
|
|
book_dict["genres"] = subjects[:10]
|
|
|
|
covers = work_json.get("covers", [])
|
|
if covers:
|
|
book_dict["cover_url"] = (
|
|
f"https://covers.openlibrary.org/b/id/{covers[0]}-L.jpg"
|
|
)
|
|
|
|
try:
|
|
editions_response = requests.get(
|
|
f"{OPENLIBRARY_BASE_URL}/works/{olid}/editions.json", timeout=10
|
|
)
|
|
if editions_response.status_code == 200:
|
|
editions_data = editions_response.json()
|
|
entries = editions_data.get("entries", [])
|
|
if entries:
|
|
edition = entries[0]
|
|
isbn_list = edition.get("isbn_10", [])
|
|
if isbn_list:
|
|
book_dict["isbn_10"] = isbn_list[0]
|
|
isbn_list = edition.get("isbn_13", [])
|
|
if isbn_list:
|
|
book_dict["isbn_13"] = isbn_list[0]
|
|
publishers = edition.get("publishers", [])
|
|
if publishers:
|
|
book_dict["publisher"] = publishers[0]
|
|
pub_date = edition.get("publish_date")
|
|
if pub_date:
|
|
if len(pub_date) >= 4:
|
|
try:
|
|
book_dict["first_publish_year"] = int(pub_date[:4])
|
|
except ValueError:
|
|
pass
|
|
pages = edition.get("number_of_pages_median")
|
|
if pages:
|
|
book_dict["pages"] = pages
|
|
edition_covers = edition.get("covers", [])
|
|
if edition_covers and not book_dict.get("cover_url"):
|
|
book_dict["cover_url"] = (
|
|
f"https://covers.openlibrary.org/b/id/{edition_covers[0]}-L.jpg"
|
|
)
|
|
except Exception as e:
|
|
logger.warning(f"Could not get editions for {olid}: {e}")
|
|
|
|
if author:
|
|
book_dict["authors"] = [author]
|
|
elif work_doc.get("author_name"):
|
|
book_dict["authors"] = work_doc.get("author_name", [])
|
|
|
|
return book_dict
|
|
|
|
|
|
def lookup_author_from_openlibrary(name: str) -> dict:
|
|
try:
|
|
response = requests.get(
|
|
f"{OPENLIBRARY_BASE_URL}/search.json",
|
|
params={"author": name, "limit": 1},
|
|
timeout=10,
|
|
)
|
|
response.raise_for_status()
|
|
search_results = response.json()
|
|
except Exception as e:
|
|
logger.warning(f"Could not search for author {name}: {e}")
|
|
return {}
|
|
|
|
docs = search_results.get("docs", [])
|
|
if not docs:
|
|
return {}
|
|
|
|
author_doc = docs[0]
|
|
author_olid = author_doc.get("key", "").replace("/authors/", "")
|
|
if not author_olid:
|
|
return {}
|
|
|
|
author_dict: dict = {
|
|
"name": author_doc.get("name", name),
|
|
"openlibrary_id": author_olid,
|
|
}
|
|
|
|
try:
|
|
author_response = requests.get(
|
|
f"{OPENLIBRARY_BASE_URL}/authors/{author_olid}.json", timeout=10
|
|
)
|
|
if author_response.status_code == 200:
|
|
author_json = author_response.json()
|
|
bio = author_json.get("bio")
|
|
if bio:
|
|
if isinstance(bio, dict):
|
|
author_dict["bio"] = bio.get("value", "")
|
|
else:
|
|
author_dict["bio"] = str(bio)
|
|
|
|
wikipedia = author_json.get("wikipedia")
|
|
if wikipedia:
|
|
author_dict["wikipedia_url"] = wikipedia
|
|
except Exception as e:
|
|
logger.warning(f"Could not get author JSON for {author_olid}: {e}")
|
|
|
|
author_dict["author_headshot_url"] = (
|
|
f"https://covers.openlibrary.org/a/olid/{author_olid}-L.jpg"
|
|
)
|
|
|
|
return author_dict
|