Skip to content

Roadmap: multi-source wallpaper support (Reddit, Unsplash, and beyond) #5

@violhex

Description

@violhex

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

  1. Unsplash — lowest complexity, clean API, immediately useful, good test case for the multi-source architecture
  2. Reddit — high value for wallpaper users specifically, moderate complexity
  3. Pexels — low cost once Unsplash patterns are established
  4. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requestroadmapLong-term direction and planning

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions