A simple bluesky bot to post sublime pictures of our universe. Powers the Sublime Space Bluesky account.
This project is licensed under the AGPL-3.0-or-later License. See the LICENSE.md file for details.
- Posts NASA's Astronomy Picture of the Day to Bluesky
- Posts NASA EPIC Earth imagery weekly
- Posts NASA SDO solar imagery weekly
- Posts ESA/Hubble archive imagery weekly
- Posts new ESA/Webb Picture of the Month images when they appear
- Posts NSF NOIRLab Image of the Week imagery weekly
- Automatically compresses images to meet Bluesky's size limits
- Supports image APODs and video APODs with Bluesky link cards
- Includes alt text plus a source and credit reply for each post
- Adds
#Astronomyand#Spaceto the main post for discovery
The src/post-apod.ts script:
- fetches the APOD from
https://api.nasa.gov/planetary/apod; - downloads the daily image when
media_type=image; - compresses images below Bluesky's 1 MB limit;
- publishes image APODs with the image and alt text;
- publishes video APODs as Bluesky link cards with thumbnails when NASA provides one;
- replies to the main post with the APOD source and credit.
If the daily APOD is a video, the bot does not re-upload the video file. It links to the original video source and uses NASA's thumbnail when available.
The src/post-epic.ts script:
- fetches the latest natural color Earth images from
https://api.nasa.gov/EPIC/api/natural; - picks the latest available image;
- downloads and compresses the image below Bluesky's 1 MB limit;
- publishes the image with a short Earth-focused caption;
- replies to the main post with NASA EPIC/DSCOVR credit and the source image URL.
The src/post-sdo.ts script:
- downloads the latest Solar Dynamics Observatory images from
https://sdo.gsfc.nasa.gov/assets/img/latest/; - compresses images below Bluesky's 1 MB limit;
- publishes a multi-image post with complementary solar views;
- replies to the main post with NASA/SDO/AIA credit and the source URL.
The src/post-hubble.ts script:
- computes the ESA/Hubble Picture of the Week archive ID for the current week;
- fetches image metadata from
https://esahubble.org/images/{imageId}/api/json/; - downloads and compresses the image below Bluesky's 1 MB limit;
- publishes the image with a short Hubble-focused caption;
- replies to the main post with ESA/Hubble credit and the source URL.
The weekly rotation starts at potw1101a, advances by one archive image per week, and wraps back to the start after potw2552a.
The src/post-webb.ts script:
- fetches the latest ESA/Webb Picture of the Month from
https://esawebb.org/images/potm/json/; - fetches image metadata from
https://esawebb.org/images/{imageId}/api/json/; - skips the run when that
imageIdhas already been posted; - downloads and compresses the image below Bluesky's 1 MB limit;
- publishes the image with a short Webb-focused caption;
- replies to the main post with ESA/Webb credit and the source URL.
The duplicate guard is stored in .bot-state.json, which is ignored by git.
The src/post-noirlab.ts script:
- fetches the latest NSF NOIRLab Image of the Week from
https://noirlab.edu/public/images/iotw/feed/; - reads the image, title, source, and publication date from the RSS item;
- skips the run when that image has already been posted;
- downloads and compresses the image below Bluesky's 1 MB limit;
- publishes the image with a short NOIRLab-focused caption;
- replies to the main post with NSF NOIRLab credit and the source URL.
Prerequisite: Node.js 24 or later with Corepack enabled.
On your server or local machine, clone this repo and run:
corepack enable
pnpm install
cp .env.example .envThen create:
- a NASA API key at https://api.nasa.gov/;
- a Bluesky App Password in Settings -> Privacy and Security -> App Passwords.
Fill in .env, then test without posting:
pnpm dry-run:apod
pnpm dry-run:epic
pnpm dry-run:hubble
pnpm dry-run:noirlab
pnpm dry-run:sdo
pnpm dry-run:webbPublish for real:
pnpm post:apod
pnpm post:epic
pnpm post:hubble
pnpm post:noirlab
pnpm post:sdo
pnpm post:webbInstall or update all cron jobs from the repository root:
pnpm install:cronThis preserves unrelated cron entries and replaces existing Sublime Space Bot entries.
All jobs run from the repository directory, retry up to 3 times with 1 hour between attempts, and append logs to bot.log.
View installed cron jobs:
crontab -lFollow bot logs:
tail -f bot.log