#!/usr/bin/env python3 """Open Library search — the "English RSL" for author works lists. Usage: tools/ol.py "Neumann, Erich" [title_words] [limit] Output: one line per title: title | years | languages | sample publishers | sample ISBN. Open Library aggregates all editions of a work into one doc (author_name, publish_year[], language[], publisher[], isbn[]) — i.e. it answers "what did this EN author write" and "which languages/years exist" — the missing half of our RSL (RU-only) pipeline. NO RU editions are indexed (checked: language=rus → 0 for known RU books) — RU hunting still goes through RSL/libgen/flibusta. """ import json, sys, time, urllib.parse, urllib.request UA = "research-tools/1.0 (jung booklist research; contact: dmitry@kokorin.org)" def ol_search(q, fields="title,author_name,publish_year,language,publisher,isbn,original_title", limit=40): url = "https://openlibrary.org/search.json?" + urllib.parse.urlencode({ "q": q, "fields": fields, "limit": min(limit, 100)}) req = urllib.request.Request(url, headers={"User-Agent": UA}) with urllib.request.urlopen(req, timeout=40) as r: return json.load(r) def main(): if len(sys.argv) < 2: sys.exit(__doc__) first = sys.argv[1] # raw query passthrough (e.g. 'title:"..."'); else treat as author name if first.startswith(("title:", "subject:", "isbn:", "publisher:")): q = " ".join(sys.argv[1:-1]) if sys.argv[-1].isdigit() else " ".join(sys.argv[1:]) else: rest = " ".join(sys.argv[2:-1]) if sys.argv[-1].isdigit() else " ".join(sys.argv[2:]) q = f"author:{first}" + (f" title:{rest}" if rest else "") limit = int(sys.argv[-1]) if sys.argv[-1].isdigit() else 40 d = ol_search(q, limit=limit) print(f"numFound: {d.get('numFound')}") for doc in d.get("docs", []): years = sorted(set(doc.get("publish_year") or [])) ys = f"{years[0]}-{years[-1]}" if len(years) > 1 else (str(years[0]) if years else "?") langs = ",".join(doc.get("language") or []) pubs = sorted(set(p[:30] for p in (doc.get("publisher") or [])))[:3] isbns = (doc.get("isbn") or [])[:2] ot = doc.get("original_title") or "" an = ", ".join(doc.get("author_name") or []) print(f"- {doc.get('title')} | {an} | {ys} | {langs} | {'; '.join(pubs)} | {isbns} | {doc.get('key','')} | {ot}") time.sleep(1) if __name__ == "__main__": main()