Metadata-Version: 2.4
Name: goodscraps
Version: 0.1.3
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)
    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 "Elantris" --limit 5 --no-canonical
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.

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"
```

