#!/usr/bin/env python3 """archive.org — EN full-text search + metadata + file lists ("English libgen"). Usage: tools/ia.py search "creator:(Carl Gustav Jung)" [rows] # advancedsearch, mediatype filtered tools/ia.py meta # /metadata/ — files, size, format tools/ia.py title "Aion" # convenience: title:("...") AND mediatype:texts Output (search): numFound + rows: identifier | title | year | downloads | restricted | mediatype. Output (meta): item fields + list of files (name, format, size) — pick _pdf/_epub/_fb2/_djvu. Notes: - query syntax: Solr — creator:(...), title:(...), subject:(...), AND/OR/NOT; + = space. - access-restricted-item=true → controlled digital lending (borrow, no direct download). - creator: is loose (images/misattributions included) — add AND mediatype:texts in query (the tool appends it for search/title unless the query already has 'mediatype'). - Politeness: 2s between calls. No key needed. """ import json, sys, time, urllib.parse, urllib.request UA = "Mozilla/5.0 (research; contact: dmitry@kokorin.org)" def fetch(url, tries=3): last = None for i in range(tries): try: req = urllib.request.Request(url, headers={"User-Agent": UA}) return urllib.request.urlopen(req, timeout=60).read().decode("utf-8", "replace") except Exception as e: last = e time.sleep(3 + 3 * i) raise SystemExit(f"fetch failed: {last}") FL = "identifier,title,year,downloads,access-restricted-item,mediatype" def main(): if len(sys.argv) < 3: sys.exit(__doc__) cmd, q = sys.argv[1], sys.argv[2] if cmd == "search": rows = int(sys.argv[3]) if len(sys.argv) > 3 else 20 if "mediatype" not in q: q = q + " AND mediatype:texts" url = "https://archive.org/advancedsearch.php?" + urllib.parse.urlencode( {"q": q, "output": "json", "rows": rows, "fl[]": FL}) d = json.loads(fetch(url)) print("numFound:", d.get("response", {}).get("numFound")) for x in d.get("response", {}).get("docs", []): r = x.get("access-restricted-item", "") print(f" {x.get('identifier')[:60]:60s} {x.get('year') or '?':>5} " f"dl={x.get('downloads', 0):>7} {'RESTRICTED' if r == 'true' else 'open':10s} {x.get('title', '')[:60]}") elif cmd == "title": q = f'title:("{q}")' rows = 20 if "mediatype" not in q: q = q + " AND mediatype:texts" url = "https://archive.org/advancedsearch.php?" + urllib.parse.urlencode( {"q": q, "output": "json", "rows": rows, "fl[]": FL}) d = json.loads(fetch(url)) print("numFound:", d.get("response", {}).get("numFound")) for x in d.get("response", {}).get("docs", []): r = x.get("access-restricted-item", "") print(f" {x.get('identifier')[:60]:60s} {x.get('year') or '?':>5} " f"dl={x.get('downloads', 0):>7} {'RESTRICTED' if r == 'true' else 'open':10s} {x.get('title', '')[:60]}") elif cmd == "meta": d = json.loads(fetch(f"https://archive.org/metadata/{q}")) meta = d.get("metadata", {}) print("title:", meta.get("title"), "| creator:", meta.get("creator"), "| year:", meta.get("year")) print("restricted:", d.get("is_access_restricted")) for f in d.get("files", []): n, fmt, size = f.get("name"), f.get("format"), f.get("size", "?") if fmt in ("Text PDF", "EPUB", "FB3", "DJVU", "Full Text OCR", "Mobi", "DAISY") or "pdf" in str(fmt): print(f" {n[:70]:70s} {fmt:15s} {size}") else: sys.exit("cmd: search|title|meta") if __name__ == "__main__": main()