Skip to content

Commit

Permalink
fixes+
Browse files Browse the repository at this point in the history
  • Loading branch information
outerwinnie committed Sep 2, 2024
1 parent 141da05 commit 4abecfa
Showing 1 changed file with 94 additions and 59 deletions.
153 changes: 94 additions & 59 deletions Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,19 @@
using System.Linq;
using System.Threading.Tasks;
using Discord;
using Discord.Commands;
using Discord.WebSocket;
using Discord.Commands;
using CsvHelper;
using Google.Apis.Auth.OAuth2;
using Google.Apis.Drive.v3;
using Google.Apis.Services;
using Microsoft.Extensions.DependencyInjection;

namespace DiscordBotExample
{
class Program
{
private static List<string> _imageUrls;
private static Random _random = new Random();
private static DiscordSocketClient _client;
private static CommandService _commands;
private static IServiceProvider _services;
Expand All @@ -28,45 +29,51 @@ class Program

static async Task Main(string[] args)
{
// Read environment variables
var token = Environment.GetEnvironmentVariable("DISCORD_BOT_TOKEN");
var channelIdStr = Environment.GetEnvironmentVariable("DISCORD_CHANNEL_ID");
_fileId = Environment.GetEnvironmentVariable("GOOGLE_DRIVE_FILE_ID");
_credentialsPath = Environment.GetEnvironmentVariable("GOOGLE_CREDENTIALS_PATH");
var postTimeStr = Environment.GetEnvironmentVariable("POST_TIME");

// Check if token, channelId, fileId, credentialsPath, or postTime is null or empty
if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_fileId) || string.IsNullOrEmpty(_credentialsPath) || string.IsNullOrEmpty(postTimeStr))
{
Console.WriteLine("Environment variables are not set correctly.");
Console.WriteLine($"DISCORD_BOT_TOKEN: {(string.IsNullOrEmpty(token) ? "Not set" : "Set")}");
Console.WriteLine($"DISCORD_CHANNEL_ID: {(string.IsNullOrEmpty(channelIdStr) ? "Not set" : "Set")}");
Console.WriteLine($"GOOGLE_DRIVE_FILE_ID: {(string.IsNullOrEmpty(_fileId) ? "Not set" : "Set")}");
Console.WriteLine($"GOOGLE_CREDENTIALS_PATH: {(string.IsNullOrEmpty(_credentialsPath) ? "Not set" : "Set")}");
Console.WriteLine($"POST_TIME: {(string.IsNullOrEmpty(postTimeStr) ? "Not set" : "Set")}");
return;
}

// Parse channel ID
if (!ulong.TryParse(channelIdStr, out _channelId))
{
Console.WriteLine("Invalid DISCORD_CHANNEL_ID format.");
return;
}

// Parse post time
if (!TimeSpan.TryParse(postTimeStr, out _postTimeSpain))
{
Console.WriteLine("Invalid POST_TIME format. It must be in the format HH:mm:ss.");
return;
}

// Initialize the Discord client and command service
_client = new DiscordSocketClient();
_commands = new CommandService();
_services = new ServiceCollection()
.AddSingleton(_client)
.AddSingleton(_commands)
.BuildServiceProvider();

_client.Log += Log;
_client.Ready += OnReady;
_client.MessageReceived += HandleCommandAsync;

// Start the bot
await _client.LoginAsync(TokenType.Bot, token);
await _client.StartAsync();

// Prevent application from closing
// Block the application until it is closed
await Task.Delay(-1);
}

Expand All @@ -80,63 +87,102 @@ private static async Task OnReady()
{
Console.WriteLine("Bot is connected.");

// Call asynchronous tasks without blocking
await Task.Run(() => RegisterCommandsAsync()).ConfigureAwait(false);
await Task.Run(() => ScheduleNextPost()).ConfigureAwait(false);
// Download and process the CSV file from Google Drive
var csvData = await DownloadCsvFromGoogleDrive();

if (csvData != null)
{
using (var reader = new StringReader(csvData))
using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)))
{
_imageUrls = csv.GetRecords<YourRecordClass>()
.Where(record => !string.IsNullOrWhiteSpace(record.image_url) && record.has_spoilers != "yes")
.Select(record => record.image_url.Trim())
.ToList();
}

Console.WriteLine("Filtered URLs read from CSV:");
foreach (var url in _imageUrls)
{
Console.WriteLine(url);
}
}
else
{
Console.WriteLine("Failed to download or read the CSV file. Exiting...");
return;
}

// Check if imageUrls is empty
if (_imageUrls.Count == 0)
{
Console.WriteLine("No valid URLs available. Exiting...");
return;
}

// Register commands
await RegisterCommandsAsync();

// Schedule the first post
await ScheduleNextPost();
}

private static async Task RegisterCommandsAsync()
{
await _commands.AddModuleAsync<CommandModule>(_services);
// Add commands to the CommandService
await _commands.AddModulesAsync(typeof(Program).Assembly, _services);
}

private static async Task HandleCommandAsync(SocketMessage messageParam)
private static async Task HandleCommandAsync(SocketMessage arg)
{
var message = messageParam as SocketUserMessage;
var message = arg as SocketUserMessage;
var context = new SocketCommandContext(_client, message);

if (message == null || message.Author.IsBot)
return;
if (message.Author.IsBot) return;

int argPos = 0;

if (message.HasStringPrefix("/", ref argPos))
{
var result = await _commands.ExecuteAsync(context, argPos, _services);

if (!result.IsSuccess)
{
Console.WriteLine($"Command failed: {result.ErrorReason}");
await context.Channel.SendMessageAsync($"Error: {result.ErrorReason}");
}
if (!result.IsSuccess) Console.WriteLine(result.ErrorReason);
}
}

private static async Task ScheduleNextPost()
{
var nowUtc = DateTime.UtcNow;
var spainTime = TimeZoneInfo.ConvertTimeFromUtc(nowUtc, _spainTimeZone);

// Specify that nextPostTimeSpain is unspecified in terms of kind because we will convert it to a specific time zone
var nextPostTimeSpain = DateTime.SpecifyKind(DateTime.Today.Add(_postTimeSpain), DateTimeKind.Unspecified);

if (nextPostTimeSpain <= spainTime)
{
// If the time has already passed for today, schedule for tomorrow
nextPostTimeSpain = nextPostTimeSpain.AddDays(1);
}

// Convert the unspecified time to Spain time zone and then to UTC
nextPostTimeSpain = TimeZoneInfo.ConvertTimeToUtc(nextPostTimeSpain, _spainTimeZone);

// Calculate the delay
var delay = nextPostTimeSpain - nowUtc;

Console.WriteLine($"Scheduling next post in {delay.TotalMinutes} minutes.");

await Task.Delay(delay);

await PostRandomImageUrl();

// Schedule the next post
await ScheduleNextPost();
}

public static async Task<string> DownloadCsvFromGoogleDrive()
private static async Task<string> DownloadCsvFromGoogleDrive()
{
try
{
// Set up Google Drive API service
var credential = GoogleCredential.FromFile(_credentialsPath)
.CreateScoped(DriveService.Scope.DriveReadonly);

Expand All @@ -146,9 +192,9 @@ public static async Task<string> DownloadCsvFromGoogleDrive()
ApplicationName = "DiscordBotExample",
});

// Download the file
var request = service.Files.Get(_fileId);
var stream = new MemoryStream();

request.MediaDownloader.ProgressChanged += progress =>
{
if (progress.Status == Google.Apis.Download.DownloadStatus.Completed)
Expand All @@ -172,57 +218,46 @@ public static async Task<string> DownloadCsvFromGoogleDrive()
}
}

public static async Task PostRandomImageUrl()
private static async Task PostRandomImageUrl()
{
var channel = _client.GetChannel(_channelId) as IMessageChannel;

if (channel != null)
if (channel != null && _imageUrls.Count > 0)
{
string csvData = await DownloadCsvFromGoogleDrive();
int index = _random.Next(_imageUrls.Count);
string randomUrl = _imageUrls[index];
await channel.SendMessageAsync(randomUrl);
}
else
{
Console.WriteLine("No URLs available.");
}
}

if (!string.IsNullOrEmpty(csvData))
[Group("image")]
public class ImageCommands : ModuleBase<SocketCommandContext>
{
[Command("send")]
public async Task SendRandomImage()
{
if (Program._imageUrls.Count > 0)
{
using (var reader = new StringReader(csvData))
using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture)))
{
var imageUrls = csv.GetRecords<YourRecordClass>()
.Where(record => !string.IsNullOrWhiteSpace(record.image_url) && record.has_spoilers != "yes")
.Select(record => record.image_url.Trim())
.ToArray();

if (imageUrls.Length > 0)
{
int index = new Random().Next(imageUrls.Length);
string randomUrl = imageUrls[index];
await channel.SendMessageAsync(randomUrl);
}
else
{
Console.WriteLine("No valid URLs available.");
}
}
int index = Program._random.Next(Program._imageUrls.Count);
string randomUrl = Program._imageUrls[index];
await Context.Channel.SendMessageAsync(randomUrl);
}
else
{
Console.WriteLine("Failed to download or read the CSV file.");
await Context.Channel.SendMessageAsync("No URLs available.");
}
}
}
}

// Define a class that matches the CSV structure
public class YourRecordClass
{
public string image_url { get; set; }
public string has_spoilers { get; set; }
}

public class CommandModule : ModuleBase<SocketCommandContext>
{
[Command("send")]
public async Task SendRandomImage()
{
await Program.PostRandomImageUrl();
await ReplyAsync("Random image sent!");
}
}
}

0 comments on commit 4abecfa

Please sign in to comment.