Skip to content

A bot which posts a random image to discord channel from Azure Blob Storage.

License

Notifications You must be signed in to change notification settings

Hekku2/discord-image-poster

Repository files navigation

Discord Image Poster

A bot which posts periodically a random image to discord channel from Azure Storage.

Currently this is designed to work with one server and one channel.

How does it work?

In short, software periodically selects random image from image storage and sends it to discord channel.

In depth

  1. Image sending is periodically triggered by Function App TimerTrigger.
  2. When Image sending is triggered, software selects a random image from index. Selection is not really random, it prefers less posted images. See RandomizationService for implementation details.
  • If there is no index, software builds an index of images available in source.
  1. After image is selected, software downloads the image from storage to memory
  • If Image is removed, error is logged and image is not sent to channel.
  1. After file is downloaded, image is sent to Azure AI Vision for analysis
  • This functionality can be disabled with from Feature Settings
  1. Caption and tags from Azure AI Vision response are saved to index.
  2. Image is sent to discord with received caption. If image analysis is not used, file name is used as caption.

Same with flowchart:

flowchart TD
  A[Timer triggered] --> B{Is index built?};
  B -- Yes --> D[Get random image from index];
  B -- No --> C[Build index!];
  C ----> D;
  D ----> E{Does Image exist?};
  E -- No --> X[Process finished];
  E -- Yes --> F[Download image];
  F ----> G{Image analysis enabled};
  G -- Yes --> H[Send to Image Analysis Service];
  G -- No --> I{Is Discord sending enabled?};
  H ----> I;
  I -- Yes --> K[Send image to Discord];
  I -- No --> X;
  K ----> X;
Loading

Indexing

  • Indexing is performed automatically if index doesn't exist.
  • Image index can be regenerated by calling the related function.
  • Currently changes in storage don't trigger image index regeneration.
  • The index contains data of the images and how often those have been posted and other similar metadata.
  • Images can also be ignored. Ignored images are not selected by randomization logic.

Tools

This section lists tools that are used in developing and deploying this software. Some are not strictly needed, but make developing easier.

Development

  • Dotnet 8.0 (or later)
  • Azure Powershell
    • Bicep with version that supports importing user types (0.28.1 is enough, earlier may also suffice)
  • Docker (and docker compose).

Deployment and running

Following section describes what needs be done to deploy and run this application. Instructions are still WIP, proper documentation and scripts can be provided later.

This service can be run in following ways

  1. Local, without container. (Azure Core Tools, func start)
  2. Local, with container (docker compose)
  3. From Azure (the intended way for production)

Configuration

Discord

  1. Create application in Discord portal.
  2. Installing Discord Bot to Discord Server
  3. Get Token from Discord Portal (Check the bot page)
  4. Get Guild Id (server ID) and Channel Id from Discord server. Easies way to is to navigate to Discord server with browser and take those ids from browser url, such as https://discord.com/channels/123123/666666

Installing Discord Bot to Discord Server

Not sure if there is an easier way, but the current way is to call following url: https://discord.com/oauth2/authorize?client_id=<bot id here>&permissions=2048&scope=bot

  • Permission 2048 is "Send Messages"
  • Other combinations can be checked from https://discord.com/developers/applications/<id here>/bot

Running locally with Azure Core Tools

This requires Azurite or proper Azure Storage to function correctly.

Settings are read from local.settings.json which needs to be generated.

Example:

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
        "DiscordOptions__Token": "token here",
        "DiscordOptions__GuildId": "server id here",
        "DiscordOptions__ChannelId": "channel id here",
        "BlobStorageImageSourceOptions__ConnectionString": "DefaultEndpointsProtocol=https;AccountName=devstoreaccount1;AccountKey=Eby8vdM02xNOcqFlqUwJPLlmEtlCDXJ1OUzFT50uSRZ6IFsuFq2UVErCz4I6tq/K1SZFPTOtr/KBHBeksoGMGw==;BlobEndpoint=http://local.storage.emulator:10000/devstoreaccount1;QueueEndpoint=http://local.storage.emulator:10001/devstoreaccount1;",
        "BlobStorageImageSourceOptions__ContainerName": "images",
        "BlobStorageImageSourceOptions__FolderPath": "testfolder"
    }
}

To start

cd ./src/FunctionApp.Isolated/
func start

Running locally in container

Preparation

  1. Create developer-settings.json (based on developer-settings-sample.json)
  2. Create .env file for docker compose
docker compose build
docker compose up

NOTE: For some reason, timer doesn't seem start correctly on the first time, but it seems to after retry. Microsoft.Azure.WebJobs.Host.Listeners.FunctionListenerException: The listener for function 'Functions.SendRandomImage' was unable to start

Then call http://localhost:8080/api/SendImage?code=mock-secret-for-local-testing

Running in Azure

Preparation

  1. Create developer-settings.json (based on developer-settings-sample.json)
./Create-Environment.ps1
./Publish-App.ps1

Then get the url from Azure Portal etc.

Outside documentation

Relevant parts of documentation