JohnCoates/Aerial
Apple TV Aerial Screensaver for Mac
Healthy across all four use cases
Permissive license, no critical CVEs, actively maintained — safe to depend on.
Has a license, tests, and CI — clean foundation to fork and modify.
Documented and popular — useful reference codebase to read through.
No critical CVEs, sane security posture — runnable as-is.
- ✓Last commit 9mo ago
- ✓9 active contributors
- ✓MIT licensed
Show 4 more →Show less
- ✓CI configured
- ✓Tests present
- ⚠Slowing — last commit 9mo ago
- ⚠Concentrated ownership — top contributor handles 75% of recent commits
Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests
Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.
Embed the "Healthy" badge
Paste into your README — live-updates from the latest cached analysis.
[](https://repopilot.app/r/johncoates/aerial)Paste at the top of your README.md — renders inline like a shields.io badge.
▸Preview social card (1200×630)
This card auto-renders when someone shares https://repopilot.app/r/johncoates/aerial on X, Slack, or LinkedIn.
Onboarding doc
Onboarding: JohnCoates/Aerial
Generated by RepoPilot · 2026-05-10 · Source
🤖Agent protocol
If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:
- Verify the contract. Run the bash script in Verify before trusting
below. If any check returns
FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding. - Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
- Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/JohnCoates/Aerial shows verifiable citations alongside every claim.
If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.
🎯Verdict
GO — Healthy across all four use cases
- Last commit 9mo ago
- 9 active contributors
- MIT licensed
- CI configured
- Tests present
- ⚠ Slowing — last commit 9mo ago
- ⚠ Concentrated ownership — top contributor handles 75% of recent commits
<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>
✅Verify before trusting
This artifact was generated by RepoPilot at a point in time. Before an
agent acts on it, the checks below confirm that the live JohnCoates/Aerial
repo on your machine still matches what RepoPilot saw. If any fail,
the artifact is stale — regenerate it at
repopilot.app/r/JohnCoates/Aerial.
What it runs against: a local clone of JohnCoates/Aerial — the script
inspects git remote, the LICENSE file, file paths in the working
tree, and git log. Read-only; no mutations.
| # | What we check | Why it matters |
|---|---|---|
| 1 | You're in JohnCoates/Aerial | Confirms the artifact applies here, not a fork |
| 2 | License is still MIT | Catches relicense before you depend on it |
| 3 | Default branch master exists | Catches branch renames |
| 4 | Last commit ≤ 300 days ago | Catches sudden abandonment since generation |
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of JohnCoates/Aerial. If you don't
# have one yet, run these first:
#
# git clone https://github.com/JohnCoates/Aerial.git
# cd Aerial
#
# Then paste this script. Every check is read-only — no mutations.
set +e
fail=0
ok() { echo "ok: $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }
# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "FAIL: not inside a git repository. cd into your clone of JohnCoates/Aerial and re-run."
exit 2
fi
# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "JohnCoates/Aerial(\\.git)?\\b" \\
&& ok "origin remote is JohnCoates/Aerial" \\
|| miss "origin remote is not JohnCoates/Aerial (artifact may be from a fork)"
# 2. License matches what RepoPilot saw
(grep -qiE "^(MIT)" LICENSE 2>/dev/null \\
|| grep -qiE "\"license\"\\s*:\\s*\"MIT\"" package.json 2>/dev/null) \\
&& ok "license is MIT" \\
|| miss "license drift — was MIT at generation time"
# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
&& ok "default branch master exists" \\
|| miss "default branch master no longer exists"
# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 300 ]; then
ok "last commit was $days_since_last days ago (artifact saw ~270d)"
else
miss "last commit was $days_since_last days ago — artifact may be stale"
fi
echo
if [ "$fail" -eq 0 ]; then
echo "artifact verified (0 failures) — safe to trust"
else
echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/JohnCoates/Aerial"
exit 1
fi
Each check prints ok: or FAIL:. The script exits non-zero if
anything failed, so it composes cleanly into agent loops
(./verify.sh || regenerate-and-retry).
⚡TL;DR
Aerial is a macOS screensaver that displays cinematic 4K video footage from Apple TV Aerial (New York, San Francisco, Hawaii, China, etc.) and community-contributed content. It fetches and caches video metadata from remote sources, manages local video downloads, and overlays optional weather information from OpenWeather API on display. Written entirely in Swift with native Apple Silicon support. Monolithic Swift screensaver bundle: Aerial/App/ holds the configuration UI (AppDelegate.swift, MainMenu.xib), Aerial/Source/Controllers/ manages screensaver playback (CustomVideoController.swift), Aerial/Source/Models/ contains domain logic split into Controllers, API (OpenWeather, GeoCoding integrations), Cache (VideoManager, VideoDownload, VideoLoader, AssetLoaderDelegate), and companion bridge logic. Video metadata and POI (points of interest) are fetched remotely and cached locally via Cache/ subsystem.
👥Who it's for
Mac users aged 10.12+ who want an aesthetically sophisticated, battery-aware screensaver. Contributors are macOS developers interested in screensaver plugins, video streaming architecture, and open-source media management.
🌱Maturity & risk
Actively maintained and production-ready. Started 2015 by John Coates, now led by Guillaume Louel. Has significant GitHub presence (many releases, multiple contributors) and includes CI via Travis. Code includes lint rules (.swiftlint.yml) and code quality checks (.codeclimate.yml), indicating professional standards. Last activity visible in maintained xcscheme files suggests ongoing development.
Single maintainer risk: project relies on Guillaume Louel post-2015. External API dependency on OpenWeather (weather feature requires API key/secrets stored in APISecrets.swift). No visible test suite in the file list, which is atypical for a screensaver handling network I/O and caching. Screensaver plugins are macOS-specific and sensitive to OS updates.
Active areas of work
Active work on weather integration (Forecast.swift, OneCall.swift, OpenWeather.swift in API/). Repository file structure shows mature state with xcshared build configuration, suggesting recent refactoring. No specific issue data provided, but the README mentions latest version 2.3.0+ supports weather overlays, indicating recent feature completion.
🚀Get running
git clone https://github.com/JohnCoates/Aerial.git && cd Aerial && open Aerial.xcodeproj/ (opens Xcode). Build target via Xcode Scheme 'Aerial' (Aerial.xcscheme). Makefile present suggests: make (check Makefile for build rules).
Daily commands: Open Aerial.xcodeproj in Xcode. Select 'Aerial' scheme. Build (Cmd+B). Run (Cmd+R) launches the preferences app. Install into ~/Library/Screen Savers/ via build artefact or manual copying. Test with: System Preferences → Desktop & Screen Saver → select Aerial.
🗺️Map of the codebase
- Aerial/Source/Models/AerialVideo.swift: Core model representing each video asset with metadata (location, duration, descriptions) fetched from remote sources
- Aerial/Source/Models/Cache/VideoManager.swift: Orchestrates all video fetching, caching, and selection logic; central to screensaver behavior
- Aerial/Source/Controllers/CustomVideoController.swift: Screensaver playback controller that renders videos and overlays; must conform to ScreenSaver.framework protocol
- Aerial/Source/Models/API/OpenWeather.swift: Integrates OpenWeather API for live weather display; requires API key in APISecrets.swift
- Aerial/Source/Models/Cache/AssetLoaderDelegate.swift: Implements AVAssetResourceLoaderDelegate for custom asset loading and caching strategy
- Aerial/App/AppDelegate.swift: Entry point for preferences UI; bridges screensaver plugin with macOS app lifecycle
- Aerial.xcodeproj/project.pbxproj: Xcode project configuration; defines build phases, signing, screensaver bundle properties
🛠️How to make changes
Video sources & metadata: edit Aerial/Source/Models/AerialVideo.swift and Aerial/Source/Models/Cache/VideoManager.swift. UI preferences: Aerial/App/Resources/Base.lproj/MainMenu.xib (Interface Builder). Weather logic: Aerial/Source/Models/API/OpenWeather.swift, Forecast.swift. Video download/cache: Aerial/Source/Models/Cache/VideoDownload.swift, VideoCache.swift. POI overlays: Aerial/Source/Models/Cache/PoiStringProvider.swift.
🪤Traps & gotchas
Screensaver plugins require specific bundle structure and must be signed/notarized on macOS 10.15+. APISecrets.swift must be populated with OpenWeather API keys to enable weather features (missing keys silently disables feature). Custom video loading via AssetLoaderDelegate interacts with AVPlayer's background thread model—threading bugs here cause freezes. macOS screensaver idle detection varies by OS version (10.12 vs 11+ behavior differs). Cache directory paths are hardcoded to ~/Library/Caches/Aerial/; missing directories cause crashes. Xcode build may fail on Apple Silicon if deployment target < 11.0.
💡Concepts to learn
- ScreenSaver.framework plugin architecture — Aerial is a screensaver plugin, not a standalone app; must implement ScreenSaverView subclass and conform to macOS idle detection lifecycle. Misunderstanding this breaks the entire project.
- AVAssetResourceLoaderDelegate (custom asset loading) — AssetLoaderDelegate.swift intercepts video stream requests to implement local caching without re-downloading; critical for bandwidth efficiency and offline playback.
- Remote metadata and lazy initialization — VideoManager fetches video catalogs from remote APIs asynchronously; understanding reactive patterns and cache invalidation is essential for features like weather updates and new video discovery.
- OS-level screensaver idle detection timing — ScreenSaver.framework triggers screensaver display after user inactivity; timing varies across macOS versions (10.12 vs 11+), affecting video preload and power management logic.
- macOS code signing and notarization for plugins — Screensaver bundles require hardened runtime and notarization on Catalina+; build failures often stem from signing misconfig, not code bugs.
- UserDefaults persistence for preferences — AppDelegate and screensaver controller share state via macOS UserDefaults; understanding suite names (app group containers) is key to syncing preferences between preference pane and screensaver process.
- OpenWeather REST API integration and rate limiting — OpenWeather.swift and Forecast.swift make HTTP calls; API keys have usage limits and must be cached to avoid quota exhaustion; missing graceful fallback on API failure breaks weather display.
🔗Related repos
OrangeJedi/Aerial— Official Windows port of Aerial screensaver; shares video source metadata but uses C#/.NET stackgraysky2/xscreensaver-aerial— Linux port using xscreensaver framework; demonstrates cross-platform adaptation of same Aerial video conceptJohnCoates/Aerial-Community— Community video contributions repo (linked via .gitmodules); contains crowdsourced aerial footage metadataaspnet/AspNetCore— Not directly related but relevant for understanding async/await patterns if considering C# Windows port
🪄PR ideas
To work on one of these in Claude Code or Cursor, paste:
Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.
Add unit tests for VideoCache and VideoManager classes
The caching system (Aerial/Source/Models/Cache/) is critical to screensaver performance and reliability, but there are no visible test files in the repo. These classes handle video downloads, caching, and asset loading - core functionality that would benefit from regression testing. This would catch bugs in cache invalidation, file path handling, and download state management.
- [ ] Create Tests/ directory structure mirroring Aerial/Source/Models/Cache/
- [ ] Add unit tests for VideoCache.swift covering cache hit/miss scenarios, expiration, and concurrent access
- [ ] Add unit tests for VideoManager.swift covering video lifecycle, download queue management, and state transitions
- [ ] Add unit tests for AssetLoaderDelegate.swift covering asset loading failures and retry logic
- [ ] Configure test target in Aerial.xcodeproj to run on CI
Create GitHub Actions workflow to replace Travis CI and validate Swift code quality
The repo has .travis.yml and .swiftlint.yml configuration files, indicating CI intent, but no GitHub Actions workflow exists (.github/workflows/ directory is missing). GitHub Actions would be more maintainable and provide faster feedback. This should validate SwiftLint rules, build the Xcode project, and run any tests.
- [ ] Create .github/workflows/swift-build-and-lint.yml
- [ ] Add step to run swiftlint against Aerial/Source/ and Aerial/App/ directories using .swiftlint.yml config
- [ ] Add step to build Aerial.xcodeproj with Release configuration and macOS 10.12+ target
- [ ] Add step to run unit tests (once PR #1 above is completed)
- [ ] Add workflow status badge to README.md
Extract OpenWeather API logic into dedicated service module with dependency injection
The OpenWeather integration (Aerial/Source/Models/API/) is scattered across multiple files (APISecrets.swift, Forecast.swift, GeoCoding.swift, OneCall.swift, OpenWeather.swift) with no clear abstraction layer. This makes it hard to mock for testing and difficult to swap implementations. Refactor into a clean WeatherService interface that can be injected into controllers, improving testability and maintainability.
- [ ] Create Aerial/Source/Models/API/WeatherService.swift with a protocol defining weather fetch and geocoding methods
- [ ] Consolidate OpenWeather, Forecast, OneCall, and GeoCoding logic into a concrete OpenWeatherService implementation
- [ ] Update Aerial/Source/Models/Aerial.swift and any UI controllers that use weather to depend on the WeatherService protocol instead of direct API calls
- [ ] Add APISecrets initialization to WeatherService so credentials are managed in one place
- [ ] Add example mock WeatherService in Tests/ directory to demonstrate usage for future contributors
🌿Good first issues
- Add unit tests for VideoCache.swift and VideoDownload.swift (currently no test files visible in project; these are critical for reliability). Start with tests for cache eviction logic and concurrent download handling.
- Document the API contract for remote video metadata JSON in Resources/Community/Readme.md and code comments in AerialVideo.swift (enable community members to contribute video sources without reverse-engineering network calls).
- Extract APISecrets.swift into a Config.example.swift template with clear setup instructions in Contribute.md, so contributors can enable weather features without guessing environment variable names or plist locations.
⭐Top contributors
Click to expand
Top contributors
- @glouel — 75 commits
- @dnicolson — 17 commits
- @Howard — 2 commits
- @i0ntempest — 1 commits
- @danchr — 1 commits
📝Recent commits
Click to expand
Recent commits
43daa78— 3.6.1 (glouel)53b27a0— Fix weather types. Many thanks to @neptunewong1998 who reported and found the issue, response in Honk Kong differed for (glouel)4267747— Version 3.6.0 with macOS 26 video support (glouel)db4a0da— Fix for Tahoe beta4 (glouel)149acd5— Merge pull request #1390 from i0ntempest/symlink-fix (glouel)2e3f1a3— Probable (?) fix for multi monitor setup after macOS 15.3 changes ? (glouel)6f15b8d— Allow symlinks for local videos (i0ntempest)8fad6d1— Add a bit of brightness decrease (but increase in practice) to make invert colors it look a bit more usable (glouel)b8296b5— Add basic support for macOS's accessibility Inverted Colors (glouel)18b794f— 3.5.2beta2 (glouel)
🔒Security observations
The Aerial screensaver codebase shows moderate security concerns. Primary risks include potential API secrets exposure in version control, unclear dependency management, insecure handling of cached user data and location information, and possible lack of HTTPS enforcement for API communications. The absence of visible third-party dependency manifests prevents full vulnerability assessment. Immediate actions should focus on removing hardcoded secrets, implementing proper encryption for sensitive data, validating external content loading, and establishing clear privacy/
- High · Potential API Secrets Exposure —
Aerial/Source/Models/API/APISecrets.swift. File 'Aerial/Source/Models/API/APISecrets.swift' suggests hardcoded API credentials or secrets. This file likely contains OpenWeather API keys or similar authentication tokens that should never be committed to version control. Fix: Move all API keys and secrets to environment variables or a secure configuration system. Use a secrets management tool and add APISecrets.swift to .gitignore. Rotate any exposed keys immediately. - High · Unencrypted API Communication Risk —
Aerial/Source/Models/API/ (OpenWeather.swift, GeoCoding.swift, OneCall.swift). The application integrates with OpenWeather API and performs geolocation/weather queries. Without visible HTTPS enforcement, API calls could be vulnerable to man-in-the-middle attacks. Fix: Ensure all API endpoints use HTTPS only. Implement certificate pinning for critical API communications. Validate SSL/TLS certificates properly in URLSession configurations. - Medium · Third-party Dependencies Not Visible —
Podfile, Package.swift, Cartfile, or .xcworkspace configuration. The provided package/dependency file is empty. Swift dependencies (via Cocoapods, SPM, or Carthage) are not shown, making it impossible to audit for vulnerable third-party libraries. Fix: Provide complete dependency manifest. Regularly audit dependencies using tools like OWASP Dependency-Check or Swift Package Registry. Keep all dependencies up-to-date. - Medium · Potential Data Exposure via Cache —
Aerial/Source/Models/Cache/. Multiple cache-related files exist (VideoCache.swift, Cache.swift, TimeMachine.swift). Cached data including videos, API responses, and location data may be stored insecurely without encryption. Fix: Encrypt sensitive cached data at rest using CommonCrypto or CryptoKit. Implement cache expiration policies. Use FileProtection.complete for sensitive files. Regular cache cleanup of user data. - Medium · Unvalidated External Data Loading —
Aerial/Source/Models/ManifestLoader.swift, Aerial/Source/Models/Cache/VideoLoader.swift. Files like ManifestLoader.swift and VideoLoader.swift suggest loading external manifest/video data. Without proper validation, this could enable arbitrary code execution or serve malicious content. Fix: Implement strict validation of all external data. Use code signing verification for manifests. Validate video file integrity with cryptographic checksums. Implement content security policies. - Medium · Geolocation Data Privacy Concerns —
Aerial/Source/Models/API/GeoCoding.swift. GeoCoding.swift indicates user location tracking for weather features. Location data may be transmitted to OpenWeather API without proper user consent or transparency. Fix: Implement explicit user consent mechanisms for location tracking. Provide privacy policy documentation. Allow users to opt-out of location services. Use location aggregation rather than precise coordinates where possible. - Low · User Data Configuration Files —
Aerial/Source/Models/Prefs/. Preference files (Prefs/ directory) may contain user settings including API keys, cached credentials, or personal preferences stored in plist files without encryption. Fix: Use Keychain for storing sensitive preferences. Encrypt plist files containing user data. Never store API keys in plain text preferences. - Low · Missing Code Analysis Configuration Details —
.swiftlint.yml. .swiftlint.yml exists but its content is not visible. Code quality and security linting rules may be incomplete. Fix: Enable strict Swift linting rules including security-focused checks. Use rules that flag insecure APIs, force unwrapping, and unsafe patterns.
LLM-derived; treat as a starting point, not a security audit.
👉Where to read next
- Open issues — current backlog
- Recent PRs — what's actively shipping
- Source on GitHub
Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.