Metadata-Version: 2.5
Name: openbb-news
Version: 2.0.0
Summary: RSS news feeds extension for OpenBB
Project-URL: Homepage, https://openbb.co
Project-URL: Repository, https://github.com/OpenBB-finance/OpenBB
Author-email: OpenBB Team <hello@openbb.co>
License: Apache-2.0
Requires-Python: <4,>=3.10
Requires-Dist: feedparser>=6.0
Requires-Dist: lxml>=5.0
Requires-Dist: openbb-core[pandas]>=2.0.0
Description-Content-Type: text/markdown

# openbb-news

RSS news feeds for the OpenBB Platform — one Workspace Newsfeed widget backed by
a registry of 500+ vetted feeds (Benzinga, GlobeNewswire by full ICB industry
breakdown + subject/event-type breakdown — earnings, M&A, dividends, IPOs, etc.,
PR Newswire regional + category, Axios, Yahoo Finance, Fortune, BBC, Fox News,
Drudge Report, Drugs.com, Google News regional + topic, plus the full set of
publishers aggregated by brutalist.report grouped under its eight topics —
Tech, News, Business, Science, Gaming, Culture, Politics, Sports). The widget
defaults to **Benzinga → Markets** so it loads finance-relevant articles
immediately on first open.

## Install

```bash
uv pip install -e .
```

## Endpoints

| GET path | Returns |
| --- | --- |
| `/api/v1/news/rss?outlet=<id>&source=<key>&limit=<n>&fetch_body=<bool>` | `OBBject[list[NewsItemData]]` — `{title, date, author, url, excerpt, body}` per article. Empty when `source` is unset and no default can be resolved. |
| `/api/v1/news/rss_providers` | `list[{label, value}]` — drives the widget's **Provider** dropdown. |
| `/api/v1/news/rss_feeds?outlet=<id>` | `list[{label, value}]` — drives the widget's **Feed** dropdown, filtered by the selected provider. |

`fetch_body=true` extracts the full article body from each entry's URL via
JSON-LD `articleBody` first, then the largest `<article>` element after
stripping site chrome (`nav`/`header`/`footer`/`aside`/`script`/`style`/`form`/
`iframe`/`button`/`svg`). Requires at least two real `<p>` paragraphs and
rejects pages whose body contains unrendered template markers (`[[`, `{{`);
falls back to the RSS summary on any miss. Bounded `lru_cache(maxsize=256)`
keeps repeat fetches in-process; no disk persistence.

## Pluggable feeds — `openbb.toml`

Three levers in `~/.openbb_platform/openbb.toml`, all under `[news]`:

### 1. Add or replace feeds — `[news.rss_feeds]`

**Simple form** — `key = "url-string"`. The feed appears under a single
"Custom" provider; the label is a humanized form of the key.

```toml
[news.rss_feeds]
my_internal = "https://internal.example.com/news.rss"
acme_blog   = "https://acme.example.com/feed"
```

**Rich form** — `key = { url, provider, label }` (or the equivalent table
syntax). Lets you bucket feeds into your own provider and give them a
display label, so the widget's Provider → Feed cascade groups them.

```toml
[news.rss_feeds.alpha_research]
url      = "https://alpha.example.com/rss"
provider = "acme_research"
label    = "Alpha Research"

[news.rss_feeds.beta_research]
url      = "https://acme.example.com/beta/rss"
provider = "acme_research"
label    = "Beta Research"
```

### 2. Pretty provider names — `[news.rss_providers]`

By default a provider id is humanized (`acme_research` → "Acme Research"). To
control the display label exactly, map provider id → label:

```toml
[news.rss_providers]
acme_research = "Acme Research"
internal      = "Internal Sources"
```

### 3. Keep the bundled defaults — `[news] merge_defaults`

Without this flag, the presence of any `[news.rss_feeds]` entries replaces
the 562 bundled feeds entirely. Set `merge_defaults = true` to keep
everything and add your feeds on top. User keys that collide with bundled
keys override the bundled URL.

```toml
[news]
merge_defaults = true

[news.rss_feeds]
my_internal = "https://internal.example.com/news.rss"
```

### Full example

```toml
[news]
merge_defaults = true

[news.rss_providers]
acme_research = "Acme Research"

[news.rss_feeds.alpha]
url      = "https://alpha.example.com/rss"
provider = "acme_research"
label    = "Alpha Research"

[news.rss_feeds.beta]
url      = "https://beta.example.com/rss"
provider = "acme_research"
label    = "Beta Research"
```

The Workspace Newsfeed widget rebuilds its **Provider** + **Feed** dropdowns
from this config on each request — restart the server only if the file was
empty at boot.

## Tests

```bash
pytest tests --cov=openbb_news --cov-fail-under=100
pytest integration -m integration   # hits the live feeds
```
