A Discord bot that downloads and embeds media from URLs directly into Discord messages using yt-dlp and gallery-dl. Features slash commands, auto-embed channels, metadata extraction, and user-controlled deletion.
- Media Download: Downloads media from URLs using yt-dlp and gallery-dl (priority order: gallery-dl → yt-dlp)
- In-Memory Processing: Downloads media directly to memory and uploads to Discord (no disk I/O)
- Slash Command:
/embedcommand with options for URL, custom message, and spoiler mode - Auto-Embed Channels: Automatically processes URLs in configured channels without commands
- Metadata Extraction: Displays title, author, likes, and original URL with downloaded files
- File Size Limits: Enforces Discord's 25MB file size limit with user feedback
- Auto-Resize: Automatically resizes oversized media files using ffmpeg to fit Discord's 25MB limit
- Reaction Deletion: ❌ emoji reaction allows original poster or admins to delete embeds
Docker images are available on Docker Hub:
https://hub.docker.com/repository/docker/amadejkastelic/grabby
Pull the latest image:
docker pull amadejkastelic/grabby:latestRun the bot:
docker run -d \
-v /path/to/config.toml:/config.toml \
-e DISCORD_TOKEN=your_bot_token_here \
amadejkastelic/grabby:latestMulti-architecture images are also available on ghcr:
docker pull ghcr.io/amadejkastelic/grabby:latestInstall and run using Nix flakes:
# Run without cloning
nix run github:amadejkastelic/grabby --accept-flake-config
# Build the package
nix build .#grabby
# Run the package
nix run .#grabby
# Enter development shell
nix develop
# Build Docker image
nix build .#dockerThe project uses Cachix to cache build outputs, speeding up Nix builds.
To configure Cachix on NixOS, add this to your configuration:
{
nix.settings = {
substituters = ["https://amadejkastelic.cachix.org"];
trusted-public-keys = ["amadejkastelic.cachix.org-1:EiQfTbiT0UKsynF4q3nbNYjNH6/l7zuhrNkQTuXmyOs="];
};
}On NixOS systems, you can configure grabby as a system service:
# flake.nix
{
inputs.grabby.url = "github:amadejkastelic/grabby";
# ... other inputs
outputs = { self, nixpkgs, grabby, ... }: {
nixosConfigurations.yourHostname = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
modules = [
./configuration.nix
grabby.nixosModules.grabby
];
};
};
}# configuration.nix
{ config, pkgs, ... }: {
services.grabby = {
enable = true;
logLevel = "info";
environmentFile = config.sops.secrets.discord-token.path;
servers = [
{
serverId = "123456789";
autoEmbedChannels = [
"channel1"
"channel2"
];
embedEnabled = true;
}
];
};
# If using sops
sops.secrets.discord-token = {
owner = config.services.grabby.user;
group = config.services.grabby.group;
};
}Configuration is loaded from one of these locations (in order of priority):
- CLI argument:
grabby --config /path/to/config.toml - Environment variable:
CONFIG_FILE=/path/to/config.toml - XDG config directory:
$XDG_CONFIG_HOME/grabby/config.toml - Default home directory:
~/.config/grabby/config.toml
# Discord configuration (optional)
[discord]
# Bot token (will use DISCORD_TOKEN env var if not set)
# token = "your_bot_token_here"
# Logging configuration (optional)
[logging]
# Format: "json" or "pretty" (default: "json")
format = "json"
# Level: "trace", "debug", "info", "warn", "error" (default: "info")
level = "info"
[[servers]]
server_id = "YOUR_DISCORD_SERVER_ID"
auto_embed_channels = [
"CHANNEL_ID_1",
"CHANNEL_ID_2"
]
embed_enabled = true
# Add more servers by repeating the [[servers]] section
# [[servers]]
# server_id = "ANOTHER_SERVER_ID"
# auto_embed_channels = ["CHANNEL_ID_3"]
# embed_enabled = falseDISCORD_TOKEN: Discord bot token (optional if set in config file)CONFIG_FILE: Path to config file (optional)
Use the /embed command to embed media:
/embed url:https://example.com/video.mp4
Options:
url: The URL to download and embedmessage: Optional custom message to includespoiler: Mark the content as a spoiler (default: false)
Configure channels for automatic embedding in your config file. Any URL posted in these channels will be automatically embedded without requiring the /embed command.
React with ❌ to delete an embed. Only the message author or users with MANAGE_MESSAGES permission can delete embeds.
# Run the bot in development mode
cargo run
# Run tests
cargo test
# Check code formatting
cargo fmt --check
# Run clippy lints
cargo clippy -- -D warnings
# Build release version
cargo build --release# Enter development environment with pre-commit hooks
nix develop
# Run pre-commit checks
nix run .#checks.pre-commit-check- Discord Integration: Twilight async Discord library with gateway and HTTP clients
- Media Download: Abstraction layer supporting multiple downloaders (yt-dlp, gallery-dl)
- Async Runtime: Tokio for all async operations
- Cache: In-memory caching for Discord objects
- Config: Server/channel configuration for auto-embed channels