Metadata-Version: 2.4
Name: openbrand
Version: 0.5.0
Summary: Extract brand assets (brand name, logos, colors) from any website. A dependency-light Python alternative to the openbrand npm package.
Project-URL: Homepage, https://github.com/cassidyhhaas/openbrand-py
Project-URL: Repository, https://github.com/cassidyhhaas/openbrand-py
Project-URL: Issues, https://github.com/cassidyhhaas/openbrand-py/issues
Project-URL: Changelog, https://github.com/cassidyhhaas/openbrand-py/releases
Author-email: Cass <cassidyhhaas@gmail.com>
License-Expression: MIT
License-File: LICENSE
Keywords: brand,color-extraction,favicon,logo,metadata,scraping,web
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: WWW/HTTP
Classifier: Topic :: Multimedia :: Graphics
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Classifier: Typing :: Typed
Requires-Python: >=3.12
Requires-Dist: pillow>=10.0.0
Requires-Dist: pydantic>=2.0.0
Requires-Dist: tinycss2>=1.3.0
Provides-Extra: async
Requires-Dist: httpx>=0.27.0; extra == 'async'
Provides-Extra: dev
Requires-Dist: httpx>=0.27.0; extra == 'dev'
Requires-Dist: mypy>=1.13.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
Requires-Dist: pytest>=8.0.0; extra == 'dev'
Requires-Dist: ruff>=0.7.0; extra == 'dev'
Description-Content-Type: text/markdown

# openbrand

Extract brand assets — **brand name, logos, and a color palette** — from any
website URL. A dependency-light Python port of the open-source
[`openbrand`](https://github.com/ethanjyx/OpenBrand) npm package, built to
remove any coupling to the npm registry.

**Three required dependencies:** [Pillow](https://python-pillow.org/) (image
decoding for color quantization), [Pydantic v2](https://docs.pydantic.dev/)
(typed result objects), and [tinycss2](https://doc.courtbouillon.org/tinycss2/)
(CSS parsing for color extraction). Everything else is the Python standard
library. `httpx` is an optional extra for the native-async backend.

All return objects are Pydantic v2 `BaseModel`s — `BrandAssets`, `LogoAsset`,
`ColorAsset`, `Resolution`, `ExtractionError`, `ExtractionResult` — so they
drop cleanly into FastAPI response models, expose
`.model_dump()` / `.model_dump_json()`, and ship `model_json_schema()` for
OpenAPI generation.

## Install

```bash
pip install openbrand
# or, with the native-async backend (httpx):
pip install "openbrand[async]"
```

Requires Python 3.12+.

## Library use

```python
from openbrand import extract_brand_assets

result = extract_brand_assets("https://stripe.com")
if result.ok:
    assets = result.data
    print(assets.brand_name)              # "Stripe"
    for logo in assets.logos:
        print(logo.type, logo.url)
    for color in assets.colors:
        print(color.usage, color.hex)     # primary / secondary / accent
else:
    print(result.error.code, result.error.message)
```

`extract_brand_assets` never raises on network/HTTP failures — they come back
via `result.ok == False` with a classified `result.error.code` (one of
`ACCESS_BLOCKED`, `NOT_FOUND`, `SERVER_ERROR`, `NETWORK_ERROR`,
`EMPTY_CONTENT`).

## Async use (FastAPI, asyncio, …)

```python
from openbrand import aextract_brand_assets

result = await aextract_brand_assets("https://stripe.com")
```

Drops cleanly into any event loop. Two backends, same return value:

- **Default** (no extras): runs the sync pipeline on a worker thread via
  `asyncio.to_thread`. Zero extra deps, never blocks the event loop, no
  in-extraction concurrency.
- **`pip install "openbrand[async]"`**: switches to a native async backend
  powered by `httpx` that fetches the page and pre-warms all candidate-image
  bytes **concurrently**, then runs the heuristics against cache. Measurably
  faster on sites with many logo candidates.

## CLI

```bash
openbrand https://stripe.com              # pretty JSON
openbrand https://stripe.com --indent 0   # compact, single line
python -m openbrand https://stripe.com    # module form
```

Exits non-zero when extraction fails.

## What it extracts

| Asset | Sources |
|-------|---------|
| **brand_name** | `og:site_name` → `application-name` → header/nav logo alt → `<title>` segment → domain |
| **logos** | favicons, apple-touch-icons, `<img>`, inline `<svg>` (serialized to a `data:` URI), ranked by a two-pass header/nav heuristic; dimensions probed per image |
| **colors** | declared (`theme-color`, `msapplication-TileColor`, `manifest.json`), brand-named CSS custom properties + non-neutral landmark `background-color` from `<style>` blocks, and saturation-weighted quantization of the logo imagery; capped at 3 with `primary`/`secondary`/`accent` roles |

## Links

- Source: [github.com/cassidyhhaas/openbrand-py](https://github.com/cassidyhhaas/openbrand-py)
- Issues: [github.com/cassidyhhaas/openbrand-py/issues](https://github.com/cassidyhhaas/openbrand-py/issues)
- Contributing & release process: [CONTRIBUTING.md](https://github.com/cassidyhhaas/openbrand-py/blob/main/CONTRIBUTING.md)

## License

MIT (matching the upstream `openbrand` package).
