The problem
Right now xanax is a Wallhaven client. That's a deliberate starting point, but in practice, users building wallpaper tools or desktop apps don't pull from a single source. They browse Wallhaven for high-quality tagged content, Reddit communities for curated feeds, and Unsplash for royalty-free photography. Managing three separate libraries — each with their own auth models, pagination styles, and response shapes — is friction that xanax is already well-positioned to eliminate.
What good looks like
From a user's perspective, the ideal API would let you swap or combine sources with minimal ceremony:
from xanax import Xanax
from xanax.sources import Unsplash, Reddit
wallhaven = Xanax(api_key="...")
unsplash = Unsplash(access_key="...")
reddit = Reddit(client_id="...", client_secret="...")
# Each source has its own search interface, but the same download contract
wallpaper = unsplash.search(UnsplashParams(query="mountains", orientation="landscape"))
data: bytes = unsplash.download(wallpaper)
# Iteration works the same way across all sources
for post in reddit.iter_wallpapers(RedditParams(subreddit="EarthPorn", sort="top")):
reddit.download(post, path=f"{post.id}.jpg")
The key insight: every source should share a common download() contract and iterator protocol, even if their search parameters are source-specific. You shouldn't have to learn a new mental model for each one.
Candidate sources
Reddit
- Subreddits:
r/wallpapers, r/EarthPorn, r/spaceporn, r/WidescreenWallpaper, and dozens of others
- Why: Highly curated, community-voted content. Top posts from
r/EarthPorn are often higher quality than anything a keyword search returns
- Auth: OAuth2 app credentials (client_id + client_secret). Read-only access doesn't require user login
- Complexity: Medium. PRAW exists but adds a heavy dependency; PRAW-free direct API calls are straightforward. Image posts are easy; cross-posts and gallery posts need handling
- Challenges: Direct image links vs. Reddit gallery vs. Imgur/i.redd.it links. Need to filter non-image posts and handle gallery post extraction
Unsplash
- Why: Royalty-free, high-resolution photography with a solid public API. Good for users building tools where licensing matters
- Auth: Access key only for read operations (no user auth needed for search/download)
- Complexity: Low. REST API is clean, well-documented, and has consistent pagination
- Challenges: Download URL is a separate step (the API returns a
download_location that must be triggered for attribution tracking)
Others worth evaluating
- Pexels — Similar to Unsplash, royalty-free, simple API. Low integration cost
- Pixabay — Large free image database, API key only. Includes illustrations and videos (would need filtering)
- Flickr — Massive archive, permissive license filtering available. More complex API, older design
- Artstation — No official public API; scraping-only, fragile, probably not worth it
Design questions
These need answers before any implementation starts:
1. One package or separate extras?
Option A: pip install xanax[reddit] installs PRAW or PRAW-free Reddit deps
Option B: Everything in core, no optional deps — keeps it simple if the Reddit implementation doesn't need PRAW
2. Shared base class or protocol?
A WallpaperSource protocol that each client satisfies would allow duck-typed multi-source code without inheritance. This is probably cleaner than an ABC.
class WallpaperSource(Protocol):
def download(self, wallpaper: Any, path: str | Path | None = None) -> bytes: ...
def iter_wallpapers(self, params: Any) -> Iterator[Any]: ...
3. Unified Wallpaper model or source-specific models?
Each source returns different metadata. A unified Wallpaper type loses information; source-specific models keep fidelity but require users to handle multiple types. A thin common base with source-specific subclasses might split the difference.
4. Async parity
Every new source that ships sync should ship async at the same time. The pattern from Xanax/AsyncXanax should carry over.
What this is not
- A scraper. Sources without official APIs aren't worth the maintenance
- A gallery manager or database. xanax fetches; it doesn't store or deduplicate
- A format converter. Download returns bytes exactly as the source provides them
Suggested order
- Unsplash — lowest complexity, clean API, immediately useful, good test case for the multi-source architecture
- Reddit — high value for wallpaper users specifically, moderate complexity
- Pexels — low cost once Unsplash patterns are established
- Pixabay — similar, evaluate after Pexels
Prior to any of this
The internal architecture of Xanax and AsyncXanax should be reviewed for what's actually shareable: the retry logic, download helper, and pagination machinery are all candidates for extraction into internals that new source clients can reuse without copy-paste.
Not targeting a specific version yet. This is a planning issue — leave it open as a reference while individual source issues are opened separately.
The problem
Right now xanax is a Wallhaven client. That's a deliberate starting point, but in practice, users building wallpaper tools or desktop apps don't pull from a single source. They browse Wallhaven for high-quality tagged content, Reddit communities for curated feeds, and Unsplash for royalty-free photography. Managing three separate libraries — each with their own auth models, pagination styles, and response shapes — is friction that xanax is already well-positioned to eliminate.
What good looks like
From a user's perspective, the ideal API would let you swap or combine sources with minimal ceremony:
The key insight: every source should share a common
download()contract and iterator protocol, even if their search parameters are source-specific. You shouldn't have to learn a new mental model for each one.Candidate sources
Reddit
r/wallpapers,r/EarthPorn,r/spaceporn,r/WidescreenWallpaper, and dozens of othersr/EarthPornare often higher quality than anything a keyword search returnsUnsplash
download_locationthat must be triggered for attribution tracking)Others worth evaluating
Design questions
These need answers before any implementation starts:
1. One package or separate extras?
Option A:
pip install xanax[reddit]installs PRAW or PRAW-free Reddit depsOption B: Everything in core, no optional deps — keeps it simple if the Reddit implementation doesn't need PRAW
2. Shared base class or protocol?
A
WallpaperSourceprotocol that each client satisfies would allow duck-typed multi-source code without inheritance. This is probably cleaner than an ABC.3. Unified
Wallpapermodel or source-specific models?Each source returns different metadata. A unified
Wallpapertype loses information; source-specific models keep fidelity but require users to handle multiple types. A thin common base with source-specific subclasses might split the difference.4. Async parity
Every new source that ships sync should ship async at the same time. The pattern from
Xanax/AsyncXanaxshould carry over.What this is not
Suggested order
Prior to any of this
The internal architecture of
XanaxandAsyncXanaxshould be reviewed for what's actually shareable: the retry logic, download helper, and pagination machinery are all candidates for extraction into internals that new source clients can reuse without copy-paste.Not targeting a specific version yet. This is a planning issue — leave it open as a reference while individual source issues are opened separately.