Metadata-Version: 2.4
Name: goodscraps
Version: 0.1.8
Summary: A read-only, unofficial Goodreads metadata client.
License: MIT
Author: Brandon Shelley
Author-email: brandon@pacificaviator.co
Requires-Python: >=3.12,<4.0
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Requires-Dist: beautifulsoup4 (>=4.13.4,<5.0.0)
Requires-Dist: httpx (>=0.28.1,<0.29.0)
Requires-Dist: pydantic (>=2.11.5,<3.0.0)
Requires-Dist: tinta (>=1.1.0,<2.0.0)
Description-Content-Type: text/markdown

# goodscraps

`goodscraps` is a standalone, read-only Python client for public Goodreads
metadata, including books, authors, works, series, editions, and cover images.

Goodreads has no supported public developer API. These endpoints are
unofficial and may change or become unavailable. The package does not log in,
read cookies, mutate shelves, submit ratings, or fetch review text.

## Development

```bash
poetry install
poetry run pytest
poetry run ruff check .
poetry run mypy src/
```

The test suite runs the live Goodreads smoke test by default. Set
`GOODSCRAPS_LIVE=0` to run completely offline:

```bash
GOODSCRAPS_LIVE=0 poetry run pytest
```

## CI and PyPI releases

GitHub Actions runs offline tests, Ruff, and mypy on pushes to `main` and on
pull requests. Live Goodreads requests are intentionally disabled in CI.
After those checks pass, a change to the package version on `main`
automatically creates the matching GitHub release, which triggers PyPI
publishing.

To release a new version:

```bash
# Bump the package version in pyproject.toml and the CLI source, then commit
# and push it. CI handles the tag,
# GitHub release, and PyPI publication.
poetry run python scripts/set_version.py 0.1.2
git add pyproject.toml
git add src/goodscraps/__init__.py
git commit -m "Bump package version"
git push origin main
```

## Usage

Install the package and create a `~/.local/bin/goodscraps` command:

```bash
./install.sh
```

If needed, add `~/.local/bin` to your `PATH`.

Help and usage output uses Tinta ANSI colors when displayed in a terminal.
Set `NO_COLOR=1` to disable them.

```python
from goodscraps import Goodscraps

with Goodscraps() as client:
    matches = client.search("Elantris", limit=5, resolve_canonical=True)
    authors = client.search_author("John Scalzi", limit=5)
    book_id = matches[0].canonical_book_id or matches[0].book_id
    book = client.book(book_id)
    work = client.work(book.book_id)
    requested_book = work.requested_book
    canonical_book = work.canonical_book
    editions = client.editions(book.book_id, limit=5)
    series = client.series(book.series[0].series_id) if book.series else None
    client.download_cover(book.book_id, "/tmp/elantris.jpg")
```

The optional smoke CLI is available as:

```bash
poetry run goodscraps search "Elantris" --limit 5
poetry run goodscraps search --title "Speaker for the Dead" --author "Orson Scott Card"
poetry run goodscraps search --title "Speaker for the Dead"
poetry run goodscraps search --author "Orson Scott Card"
poetry run goodscraps search "Elantris" --limit 5 --no-canonical
poetry run goodscraps search-author "John Scalzi" --limit 5
poetry run goodscraps config show
poetry run goodscraps config new
poetry run goodscraps book 68427
```

Searches resolve each result to the first edition Goodreads returns for its
work by default and include that ID as `canonical_book_id`. Use
`--no-canonical` when the original search-result edition IDs are required.
`search_author` and `search-author` use Goodreads' explicit author-filtered
book search, aggregate authors by exact normalized name, and rank them by the
number of matching works returned as `works_score`. Book searches return `author` and
`additional_authors` using the same `AuthorRef` schema as book metadata. Search
titles remove trailing Goodreads series markers from `title` while preserving
the original in `title_complete`. Supplying `--title` and/or `--author` runs
targeted title variants in parallel and ranks the merged results by title and
author agreement.

Configuration is loaded from `~/.config/goodscraps/config.toml` (or the
`XDG_CONFIG_HOME` equivalent). Use `config new` to create a documented
default configuration and `config show` to inspect the effective values.

Lookup failures return readable JSON by default:

```json
{
  "error": {
    "type": "NotFound",
    "message": "No author matched 'Unknown'"
  }
}
```

Use `--raise-errors` when debugging or when a shell traceback is preferred:

```bash
goodscraps --raise-errors author "Unknown"
```

