A Discord bot that monitors a Dropbox folder for new images and automatically uploads them to a Discord channel.
- Monitors Dropbox folder recursively via OAuth2
- Supports JPG, PNG, GIF, WebP, BMP
- Automatic token refresh (no manual intervention)
- SQLite tracking (no duplicate uploads)
- Health check endpoints
- Docker support
- Voting system: React with number emojis (1️⃣-5️⃣) to copy images to wallpapers folder
- Create a bot at Discord Developer Portal
- Copy the bot token
- Enable "MESSAGE CONTENT INTENT" in Bot settings
- Invite bot with permissions:
Send Messages,Attach Files,Add Reactions,Read Message History - Enable Developer Mode in Discord and copy your channel ID
The bot requires these Dropbox API permissions:
files.metadata.read- List files in the monitored folderfiles.content.read- Download images to upload to Discordfiles.content.write- Copy voted images to the wallpapers folder
Run the OAuth setup tool to get your credentials (permissions are requested automatically):
go run cmd/oauth-setup/main.goSee OAUTH_SETUP for detailed instructions.
# Required
export DISCORD_BOT_TOKEN="your-bot-token"
export DISCORD_CHANNEL_ID="your-channel-id"
export DROPBOX_APP_KEY="your-app-key"
export DROPBOX_APP_SECRET="your-app-secret"
export DROPBOX_REFRESH_TOKEN="your-refresh-token"
# Optional
export DROPBOX_FOLDER="/Photos/gallery-dl"
export WALLPAPERS_FOLDER="/Photos/Wallpapers"
export POLL_INTERVAL="5m"
export PORT="8080"Or use .env file (see .env.example)
Go:
go build -o artgrabber
./artgrabberDocker:
docker build -t artgrabber .
docker run --rm --env-file .env -v artgrabber-data:/data -p 8080:8080 artgrabberTask: (see task --list for all commands)
task build && ./artgrabber- Bot polls Dropbox folder every
POLL_INTERVAL(default: 5 minutes) - New images are downloaded and uploaded to Discord with numbered reactions (1️⃣-5️⃣)
- SQLite database tracks processed files to prevent duplicates
- Access tokens refresh automatically via OAuth2
- Users can vote for images by clicking the number reactions
- Voted images are automatically copied to the wallpapers folder in Dropbox
| Variable | Required | Default | Description |
|---|---|---|---|
DISCORD_BOT_TOKEN |
Yes | - | Discord bot token |
DISCORD_CHANNEL_ID |
Yes | - | Target Discord channel |
DROPBOX_APP_KEY |
Yes | - | Dropbox app key |
DROPBOX_APP_SECRET |
Yes | - | Dropbox app secret |
DROPBOX_REFRESH_TOKEN |
Yes | - | OAuth refresh token |
DROPBOX_FOLDER |
No | /Photos/gallery-dl |
Folder to monitor |
WALLPAPERS_FOLDER |
No | /Photos/Wallpapers |
Folder for voted images |
POLL_INTERVAL |
No | 5m |
Check interval |
PORT |
No | 8080 |
HTTP server port |
GET /- Status page with last upload infoGET /health- Health checkGET /ready- Readiness check (Discord connection)
When the bot posts images to Discord:
- Each image path is numbered with emoji reactions (1️⃣, 2️⃣, 3️⃣, 4️⃣, 5️⃣)
- The bot automatically adds these reactions to the message
- Click any number reaction to vote for that image
- The bot will copy the voted image to your configured wallpapers folder in Dropbox
- A confirmation message is posted showing which file was copied and who voted
Example:
1️⃣ /Photos/gallery-dl/art/image1.jpg
2️⃣ /Photos/gallery-dl/art/image2.jpg
3️⃣ /Photos/gallery-dl/art/image3.jpg
Click 2️⃣ → Bot copies image2.jpg to /Photos/Wallpapers/
Uses Task for automation. Run task --list to see all commands.
Common tasks:
task build # Build binary
task run # Run bot
task lint # Lint and format
task test # Run testsImages not uploading:
- Check Discord bot permissions (Send Messages, Attach Files, Add Reactions, Read Message History)
- Verify channel ID is correct
- Confirm Dropbox OAuth credentials are valid
- Check folder path (case-sensitive)
Token expired errors:
- Run
go run cmd/oauth-setup/main.goto get fresh credentials - Verify all three OAuth variables are set (APP_KEY, APP_SECRET, REFRESH_TOKEN)
Duplicate uploads:
- Ensure
/datavolume persists between restarts - Check
/data/artgrabber.dbexists and is not corrupted
Files too large:
- Discord limit: 8MB (50MB with Nitro)
- Bot automatically skips files over limit
MIT - See LICENSE file.