Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ A visual theming application for [Omarchy](https://omarchy.org). Extract colors

### Wallpaper Tools
- Animated wallpaper support: `.gif`, `.mp4`, and `.webm` via the built-in `aether-wp` service
- Search and download wallpapers from wallhaven.cc directly in the app
- Search and download wallpapers from [wallhaven.cc](docs/wallhaven.md) directly in the app
- Browse and use wallpapers from any public [GitHub repo](docs/github-source.md)
- Full wallpaper editor with blur, exposure, sharpen, vignette, grain, and color toning
- 12 one-click image presets: Cinematic, Vintage, Film, Dramatic, and more

Expand Down
23 changes: 22 additions & 1 deletion app.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"aether/internal/color"
"aether/internal/extraction"
"aether/internal/favorites"
"aether/internal/githubsource"
"aether/internal/omarchy"
"aether/internal/platform"
"aether/internal/template"
Expand All @@ -37,6 +38,7 @@ type App struct {
blueprints *blueprint.Service
favorites *favorites.Service
wallhaven *wallhaven.Client
github *githubsource.Client
batch *batch.Processor
themeWatcher *theme.ThemeWatcher
media *MediaServer
Expand Down Expand Up @@ -72,6 +74,7 @@ func NewApp() *App {
blueprints: blueprint.NewService(),
favorites: favorites.NewService(),
wallhaven: wallhaven.NewClient(),
github: githubsource.NewClient(),
batch: batch.NewProcessor(),
themeWatcher: theme.NewThemeWatcher(),
}
Expand Down Expand Up @@ -660,7 +663,25 @@ func (a *App) SearchWallhaven(params wallhaven.SearchParams) (*wallhaven.SearchR

// DownloadWallpaper downloads a wallpaper from a URL. Returns local path.
func (a *App) DownloadWallpaper(imageURL string) (string, error) {
return a.wallhaven.Download(imageURL)
return a.wallhaven.DownloadImage(imageURL)
}

// ---------------------------------------------------------------------------
// GitHub Source
// ---------------------------------------------------------------------------

// ListGitHubImages fetches all image files and subdirectories from a GitHub
// repository URL. Accepts github.com, <owner>.github.io, and
// raw.githubusercontent.com URLs.
func (a *App) ListGitHubImages(rawURL string) (*githubsource.ListContentsResult, error) {
return a.github.ListImages(rawURL)
}

// GetGitHubThumbnail downloads an image from a GitHub raw URL, generates a
// thumbnail, caches it to disk, and returns a ThumbnailResult with the data
// URL and original image dimensions.
func (a *App) GetGitHubThumbnail(rawURL string) (*githubsource.ThumbnailResult, error) {
return githubsource.DownloadThumbnail(rawURL)
}

// ---------------------------------------------------------------------------
Expand Down
42 changes: 42 additions & 0 deletions docs/github-source.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# GitHub Source

Aether can browse image repositories on **GitHub** and use wallpapers directly from them — no cloning or manual download needed. Works with any public repo containing `.jpg`, `.jpeg`, `.png`, or `.webp` images.

## Features

- **Browse any public GitHub repo** by URL — supports `github.com`, `*.github.io` (GitHub Pages), and `raw.githubusercontent.com` links
- **Directory navigation** — click folders to navigate deeper, arrow button to go up
- **Thumbnails** — server-side generated 300px previews, cached to disk for instant repeat views
- **Name filter** — client-side text filter to narrow down results
- **Saved repos** — bookmark repos for quick access (stored in browser localStorage)
- **Favorites** — star individual wallpapers to add to the global Favorites tab
- **Additional images** — add wallpapers to the blend set for multi-image extraction
- **Wallpaper only** — apply a wallpaper without re-extracting the palette
- **Full-size preview** — overlay preview with next/previous navigation

## Usage

1. Open the **Sources** dropdown in the header bar and select **GitHub**
2. Paste a GitHub URL in the input field and click **Fetch**
- Examples: `https://github.com/dharmx/walls`, `https://github.com/bjarneo/wallpapers/tree/gh-pages`
3. Browse images and directories
4. Click **Use** on any wallpaper to download it, set it as the current wallpaper, and switch to the Editor

## Supported URL Formats

| Format | Example |
|--------|---------|
| Repository root | `https://github.com/owner/repo` |
| With branch | `https://github.com/owner/repo/tree/main` |
| Subdirectory | `https://github.com/owner/repo/tree/main/wallpapers/nature` |
| Single file | `https://github.com/owner/repo/blob/main/image.jpg` |
| Without branch | `https://github.com/owner/repo/subdir` |
| GitHub Pages | `https://owner.github.io/wallpapers` |
| Raw URL | `https://raw.githubusercontent.com/owner/repo/branch/path` |

## Performance

- The **GitHub API** response is cached in memory for 5 minutes (100 entries max, LRU eviction)
- Thumbnails are generated server-side and cached to `~/.cache/aether/github/` as PNG files with a `.dims` sidecar for original dimensions
- The first 12 images in each fetch are **pre-warmed** in the thumbnail cache so they load instantly on scroll
- Images load lazily — only cards that scroll into view trigger thumbnail generation
4 changes: 4 additions & 0 deletions frontend/src/App.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import TargetAppsStrip from '$lib/components/layout/TargetAppsStrip.svelte';
import ThemeEditor from '$lib/components/editor/ThemeEditor.svelte';
import WallhavenBrowser from '$lib/components/wallhaven/WallhavenBrowser.svelte';
import GitHubBrowser from '$lib/components/github/GitHubBrowser.svelte';
import LocalBrowser from '$lib/components/local/LocalBrowser.svelte';
import FavoritesView from '$lib/components/favorites/FavoritesView.svelte';
import BlueprintsView from '$lib/components/blueprints/BlueprintsView.svelte';
Expand Down Expand Up @@ -39,6 +40,7 @@
const VALID_TABS: readonly Tab[] = [
'editor',
'wallhaven',
'github',
'local',
'favorites',
'blueprints',
Expand Down Expand Up @@ -439,6 +441,8 @@
<ThemeEditor />
{:else if activeTab === 'wallhaven'}
<WallhavenBrowser />
{:else if activeTab === 'github'}
<GitHubBrowser />
{:else if activeTab === 'local'}
<LocalBrowser />
{:else if activeTab === 'favorites'}
Expand Down
18 changes: 18 additions & 0 deletions frontend/src/lib/components/favorites/FavoritesView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,16 @@
}
}

async function loadRemoteThumb(path: string) {
try {
const {GetGitHubThumbnail} = await import(
'../../../../wailsjs/go/main/App'
);
const result = await GetGitHubThumbnail(path);
if (result?.dataURL) setCachedImage('thumb:' + path, result.dataURL);
} catch {}
}

async function loadThumbnails() {
for (const fav of favorites) {
if (isThumbnailCached(fav.path)) continue;
Expand All @@ -71,6 +81,14 @@
continue;
}

// Remote GitHub URLs — use Go thumbnail generator (download +
// resize to 300px, cached on disk for subsequent loads). Fire and
// forget so the loop doesn't block on HTTP downloads.
if (fav.path.startsWith('http://') || fav.path.startsWith('https://')) {
loadRemoteThumb(fav.path);
continue;
}

// Local files — load thumbnail
loadThumbnail(fav.path);
}
Expand Down
Loading