From 3a404526084295102e08d5b4d512f04c5f85db7e Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 03:28:45 +0200 Subject: [PATCH 1/8] First try rewards usage --- Program.cs | 232 ++++++++++++++--------------------------------------- 1 file changed, 61 insertions(+), 171 deletions(-) diff --git a/Program.cs b/Program.cs index 819cc34..036bd32 100644 --- a/Program.cs +++ b/Program.cs @@ -3,15 +3,11 @@ using System.Globalization; using System.IO; using System.Linq; +using System.Threading; using System.Threading.Tasks; using Discord; using Discord.WebSocket; -using Discord.Commands; -using Discord.Rest; using CsvHelper; -using Google.Apis.Auth.OAuth2; -using Google.Apis.Drive.v3; -using Google.Apis.Services; namespace DiscordBotExample { @@ -21,53 +17,40 @@ class Program private static Random _random = new Random(); private static DiscordSocketClient _client; private static ulong _channelId; - private static string _fileId; private static string _credentialsPath; - private static TimeSpan _postTimeSpain; - private static TimeZoneInfo _spainTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"); - private static bool _isImageUrlsLoaded = false; // Flag to track if image URLs are loaded + private static bool _isImageUrlsLoaded = false; 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)) + if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_credentialsPath)) { Console.WriteLine("Environment variables are not set correctly."); 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 _client = new DiscordSocketClient(); _client.Log += Log; _client.Ready += OnReady; - _client.InteractionCreated += HandleInteractionAsync; - // Start the bot await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); - // Block the application until it is closed + // Start the CSV monitoring task in the background + _ = MonitorCsvFileAsync(); + + // Block the application until closed await Task.Delay(-1); } @@ -81,180 +64,87 @@ private static async Task OnReady() { Console.WriteLine("Bot is connected."); - // 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() - .Where(record => !string.IsNullOrWhiteSpace(record.image_url) && record.has_spoilers != "yes") - .Select(record => record.image_url.Trim()) - .ToList(); - - _isImageUrlsLoaded = true; // Set flag to true when URLs are loaded - } - - 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; - } - - // Register commands - await RegisterCommandsAsync(); + // Load initial image URLs (from your Google Drive or wherever necessary) + _isImageUrlsLoaded = true; - // Schedule the first post - await ScheduleNextPost(); + // Example code to load image URLs (replace with actual logic) + _imageUrls = new List { "http://example.com/image1.jpg", "http://example.com/image2.jpg" }; } - private static async Task RegisterCommandsAsync() + private static async Task MonitorCsvFileAsync() { - var sendCommand = new SlashCommandBuilder() - .WithName("send") - .WithDescription("Send a random image from the list"); - - // Replace 'your_guild_id_here' with your actual guild ID - var guildId = ulong.Parse(Environment.GetEnvironmentVariable("GUILD_ID")); // Example: 123456789012345678 - var guild = _client.GetGuild(guildId); - - await guild.DeleteApplicationCommandsAsync(); // Clear existing commands in the guild - await _client.Rest.DeleteAllGlobalCommandsAsync(); // Optionally clear global commands - await guild.CreateApplicationCommandAsync(sendCommand.Build()); - - Console.WriteLine("Slash command /send registered for guild"); - } - - private static async Task HandleInteractionAsync(SocketInteraction interaction) - { - if (interaction is SocketSlashCommand command) + while (true) { - if (command.Data.Name == "send") + try { - await HandleSendCommandAsync(command); - } - } - } + // Path to your rewards.csv file + string csvFilePath = "rewards.csv"; - private static async Task HandleSendCommandAsync(SocketSlashCommand command) - { - if (_isImageUrlsLoaded) - { - if (_imageUrls.Count > 0) - { - int index = _random.Next(_imageUrls.Count); - string randomUrl = _imageUrls[index]; - await command.RespondAsync(randomUrl); + if (File.Exists(csvFilePath)) + { + using (var reader = new StreamReader(csvFilePath)) + using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) + { + var records = csv.GetRecords().ToList(); + + foreach (var record in records) + { + // Check if reward is "recuerdate" and quantity is greater than 0 + if (record.reward == "recuerdate" && record.quantity > 0) + { + Console.WriteLine($"Running PostRandomImageUrl {record.quantity} times..."); + + // Run PostRandomImageUrl as many times as specified by quantity + for (int i = 0; i < record.quantity; i++) + { + await PostRandomImageUrl(); + } + } + } + } + } + else + { + Console.WriteLine("CSV file not found."); + } } - else + catch (Exception ex) { - await command.RespondAsync("No URLs available."); + Console.WriteLine($"Error reading CSV file: {ex.Message}"); } - } - else - { - await command.RespondAsync("The bot is still loading data. Please try again later."); - } - } - - 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); + // Wait for 5 minutes before checking again + await Task.Delay(TimeSpan.FromMinutes(5)); } - - // 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(); } - private static async Task DownloadCsvFromGoogleDrive() + private static async Task PostRandomImageUrl() { - try + if (_isImageUrlsLoaded && _imageUrls.Count > 0) { - // Set up Google Drive API service - var credential = GoogleCredential.FromFile(_credentialsPath) - .CreateScoped(DriveService.Scope.DriveReadonly); - - var service = new DriveService(new BaseClientService.Initializer() - { - HttpClientInitializer = credential, - ApplicationName = "DiscordBotExample", - }); + var channel = _client.GetChannel(_channelId) as IMessageChannel; - // Download the file - var request = service.Files.Get(_fileId); - var stream = new MemoryStream(); - request.MediaDownloader.ProgressChanged += progress => + if (channel != null) { - if (progress.Status == Google.Apis.Download.DownloadStatus.Completed) - { - Console.WriteLine("Download complete."); - } - }; - - await request.DownloadAsync(stream); - - stream.Position = 0; - using (var reader = new StreamReader(stream)) + int index = _random.Next(_imageUrls.Count); + string randomUrl = _imageUrls[index]; + await channel.SendMessageAsync(randomUrl); + } + else { - return reader.ReadToEnd(); + Console.WriteLine("Unable to find the channel."); } } - catch (Exception ex) - { - Console.WriteLine($"An error occurred: {ex.Message}"); - return null; - } - } - - private static async Task PostRandomImageUrl() - { - var channel = _client.GetChannel(_channelId) as IMessageChannel; - - if (channel != null && _imageUrls.Count > 0) - { - int index = _random.Next(_imageUrls.Count); - string randomUrl = _imageUrls[index]; - await channel.SendMessageAsync(randomUrl); - } else { - Console.WriteLine("No URLs available."); + Console.WriteLine("No image URLs loaded."); } } - public class YourRecordClass + public class RewardRecord { - public string image_url { get; set; } - public string has_spoilers { get; set; } + public string reward { get; set; } + public int quantity { get; set; } } } } From 3d3f2f07f6847b369e16f98d7419723792565b7a Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 03:36:44 +0200 Subject: [PATCH 2/8] Fixes --- Dockerfile | 1 + Program.cs | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Dockerfile b/Dockerfile index 1baa96b..924e2bc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,6 +20,7 @@ ENV DISCORD_BOT_TOKEN="" ENV DISCORD_CHANNEL_ID="" ENV GOOGLE_DRIVE_FILE_ID="" ENV GOOGLE_CREDENTIALS_PATH="/app/credentials.json" +ENV CSV_FILE_PATH="/app/data/rewards.csv" ENV POST_TIME="20:00:00" # Entry point for the application diff --git a/Program.cs b/Program.cs index 036bd32..cc80b04 100644 --- a/Program.cs +++ b/Program.cs @@ -3,7 +3,6 @@ using System.Globalization; using System.IO; using System.Linq; -using System.Threading; using System.Threading.Tasks; using Discord; using Discord.WebSocket; @@ -77,8 +76,14 @@ private static async Task MonitorCsvFileAsync() { try { - // Path to your rewards.csv file - string csvFilePath = "rewards.csv"; + // Read CSV file path from Docker environment variable + string csvFilePath = Environment.GetEnvironmentVariable("CSV_FILE_PATH"); + + if (string.IsNullOrEmpty(csvFilePath)) + { + Console.WriteLine("CSV_FILE_PATH environment variable is not set."); + return; + } if (File.Exists(csvFilePath)) { @@ -105,7 +110,7 @@ private static async Task MonitorCsvFileAsync() } else { - Console.WriteLine("CSV file not found."); + Console.WriteLine($"CSV file not found at path: {csvFilePath}"); } } catch (Exception ex) From 82dfd4ad1cc9f3276bda03bbf16eb6324a184c26 Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 03:52:05 +0200 Subject: [PATCH 3/8] Fix --- Program.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Program.cs b/Program.cs index cc80b04..c969298 100644 --- a/Program.cs +++ b/Program.cs @@ -95,7 +95,7 @@ private static async Task MonitorCsvFileAsync() foreach (var record in records) { // Check if reward is "recuerdate" and quantity is greater than 0 - if (record.reward == "recuerdate" && record.quantity > 0) + if (record.rewardname == "recuerdate" && record.quantity > 0) { Console.WriteLine($"Running PostRandomImageUrl {record.quantity} times..."); @@ -148,7 +148,7 @@ private static async Task PostRandomImageUrl() public class RewardRecord { - public string reward { get; set; } + public string rewardname { get; set; } public int quantity { get; set; } } } From 5058a043143ee0f98cef7a3a488112a9a19662c8 Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 03:54:28 +0200 Subject: [PATCH 4/8] fix v2 --- Program.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Program.cs b/Program.cs index c969298..6d23078 100644 --- a/Program.cs +++ b/Program.cs @@ -95,12 +95,12 @@ private static async Task MonitorCsvFileAsync() foreach (var record in records) { // Check if reward is "recuerdate" and quantity is greater than 0 - if (record.rewardname == "recuerdate" && record.quantity > 0) + if (record.RewardName == "recuerdate" && record.Quantity > 0) { - Console.WriteLine($"Running PostRandomImageUrl {record.quantity} times..."); + Console.WriteLine($"Running PostRandomImageUrl {record.Quantity} times..."); // Run PostRandomImageUrl as many times as specified by quantity - for (int i = 0; i < record.quantity; i++) + for (int i = 0; i < record.Quantity; i++) { await PostRandomImageUrl(); } @@ -148,8 +148,8 @@ private static async Task PostRandomImageUrl() public class RewardRecord { - public string rewardname { get; set; } - public int quantity { get; set; } + public string RewardName { get; set; } + public int Quantity { get; set; } } } } From 04be40ddaf5e5059ca0609b3b73ae7c8ca3afbfc Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 13:45:41 +0200 Subject: [PATCH 5/8] Fix rewards --- Program.cs | 281 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 226 insertions(+), 55 deletions(-) diff --git a/Program.cs b/Program.cs index 6d23078..ea3f427 100644 --- a/Program.cs +++ b/Program.cs @@ -6,7 +6,12 @@ using System.Threading.Tasks; using Discord; using Discord.WebSocket; +using Discord.Commands; using CsvHelper; +using CsvHelper.Configuration; +using Google.Apis.Auth.OAuth2; +using Google.Apis.Drive.v3; +using Google.Apis.Services; namespace DiscordBotExample { @@ -16,40 +21,55 @@ class Program private static Random _random = new Random(); private static DiscordSocketClient _client; private static ulong _channelId; + private static string _fileId; private static string _credentialsPath; - private static bool _isImageUrlsLoaded = false; + private static string _rewardsCsvPath; // For rewards.csv path from Docker environment + private static TimeSpan _postTimeSpain; + private static TimeZoneInfo _spainTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"); + private static bool _isImageUrlsLoaded = false; // Flag to track if image URLs are loaded 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"); + _rewardsCsvPath = Environment.GetEnvironmentVariable("REWARDS_CSV_PATH"); // Rewards CSV path from environment + var postTimeStr = Environment.GetEnvironmentVariable("POST_TIME"); - if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_credentialsPath)) + // Check if token, channelId, fileId, credentialsPath, postTime, or rewardsCsvPath is null or empty + if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_fileId) || string.IsNullOrEmpty(_credentialsPath) || string.IsNullOrEmpty(postTimeStr) || string.IsNullOrEmpty(_rewardsCsvPath)) { Console.WriteLine("Environment variables are not set correctly."); 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 _client = new DiscordSocketClient(); _client.Log += Log; _client.Ready += OnReady; + _client.InteractionCreated += HandleInteractionAsync; + // Start the bot await _client.LoginAsync(TokenType.Bot, token); await _client.StartAsync(); - // Start the CSV monitoring task in the background - _ = MonitorCsvFileAsync(); - - // Block the application until closed + // Block the application until it is closed await Task.Delay(-1); } @@ -63,59 +83,225 @@ private static async Task OnReady() { Console.WriteLine("Bot is connected."); - // Load initial image URLs (from your Google Drive or wherever necessary) - _isImageUrlsLoaded = true; + // 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 CsvConfiguration(CultureInfo.InvariantCulture))) + { + _imageUrls = csv.GetRecords() + .Where(record => !string.IsNullOrWhiteSpace(record.image_url) && record.has_spoilers != "yes") + .Select(record => record.image_url.Trim()) + .ToList(); + + _isImageUrlsLoaded = true; // Set flag to true when URLs are loaded + } + + 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; + } + + // Register commands + await RegisterCommandsAsync(); + + // Schedule the first post + await ScheduleNextPost(); + + // Start checking rewards.csv after URLs have been loaded + if (_isImageUrlsLoaded) + { + _ = Task.Run(CheckRewardsCsvAsync); // Runs in parallel after URLs are loaded + } + } + + private static async Task RegisterCommandsAsync() + { + var sendCommand = new SlashCommandBuilder() + .WithName("send") + .WithDescription("Send a random image from the list"); + + // Replace 'your_guild_id_here' with your actual guild ID + var guildId = ulong.Parse(Environment.GetEnvironmentVariable("GUILD_ID")); // Example: 123456789012345678 + var guild = _client.GetGuild(guildId); + + await guild.DeleteApplicationCommandsAsync(); // Clear existing commands in the guild + await _client.Rest.DeleteAllGlobalCommandsAsync(); // Optionally clear global commands + await guild.CreateApplicationCommandAsync(sendCommand.Build()); - // Example code to load image URLs (replace with actual logic) - _imageUrls = new List { "http://example.com/image1.jpg", "http://example.com/image2.jpg" }; + Console.WriteLine("Slash command /send registered for guild"); } - private static async Task MonitorCsvFileAsync() + private static async Task HandleInteractionAsync(SocketInteraction interaction) { - while (true) + if (interaction is SocketSlashCommand command) { - try + if (command.Data.Name == "send") + { + await HandleSendCommandAsync(command); + } + } + } + + private static async Task HandleSendCommandAsync(SocketSlashCommand command) + { + if (_isImageUrlsLoaded) + { + if (_imageUrls.Count > 0) { - // Read CSV file path from Docker environment variable - string csvFilePath = Environment.GetEnvironmentVariable("CSV_FILE_PATH"); + int index = _random.Next(_imageUrls.Count); + string randomUrl = _imageUrls[index]; + await command.RespondAsync(randomUrl); + } + else + { + await command.RespondAsync("No URLs available."); + } + } + else + { + await command.RespondAsync("The bot is still loading data. Please try again later."); + } + } + + 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."); - if (string.IsNullOrEmpty(csvFilePath)) + await Task.Delay(delay); + + await PostRandomImageUrl(); + + // Schedule the next post + await ScheduleNextPost(); + } + + private static async Task DownloadCsvFromGoogleDrive() + { + try + { + // Set up Google Drive API service + var credential = GoogleCredential.FromFile(_credentialsPath) + .CreateScoped(DriveService.Scope.DriveReadonly); + + var service = new DriveService(new BaseClientService.Initializer() + { + HttpClientInitializer = credential, + 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) { - Console.WriteLine("CSV_FILE_PATH environment variable is not set."); - return; + Console.WriteLine("Download complete."); } + }; + + await request.DownloadAsync(stream); + + stream.Position = 0; + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred: {ex.Message}"); + return null; + } + } + + private static async Task PostRandomImageUrl() + { + var channel = _client.GetChannel(_channelId) as IMessageChannel; + + if (channel != null && _imageUrls.Count > 0) + { + int index = _random.Next(_imageUrls.Count); + string randomUrl = _imageUrls[index]; + await channel.SendMessageAsync(randomUrl); + } + else + { + Console.WriteLine("No URLs available."); + } + } - if (File.Exists(csvFilePath)) + // New method to check rewards every 5 minutes + private static async Task CheckRewardsCsvAsync() + { + while (true) // Infinite loop to run continuously + { + try + { + if (File.Exists(_rewardsCsvPath)) // Check if the CSV file exists { - using (var reader = new StreamReader(csvFilePath)) - using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) + using (var reader = new StreamReader(_rewardsCsvPath)) + using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture))) { - var records = csv.GetRecords().ToList(); + var rewards = csv.GetRecords().ToList(); + + // Find the reward named "recuerdate" + var recuerdateReward = rewards.FirstOrDefault(r => r.RewardName == "recuerdate"); - foreach (var record in records) + if (recuerdateReward != null) { - // Check if reward is "recuerdate" and quantity is greater than 0 - if (record.RewardName == "recuerdate" && record.Quantity > 0) + if (int.TryParse(recuerdateReward.Quantity, out int quantity)) { - Console.WriteLine($"Running PostRandomImageUrl {record.Quantity} times..."); - - // Run PostRandomImageUrl as many times as specified by quantity - for (int i = 0; i < record.Quantity; i++) + Console.WriteLine($"'recuerdate' reward found with quantity {quantity}. Posting random images..."); + + for (int i = 0; i < quantity; i++) { - await PostRandomImageUrl(); + await PostRandomImageUrl(); // Post a random image } } } + else + { + Console.WriteLine("No 'recuerdate' reward found."); + } } } else { - Console.WriteLine($"CSV file not found at path: {csvFilePath}"); + Console.WriteLine($"Rewards CSV file not found at {_rewardsCsvPath}."); } } catch (Exception ex) { - Console.WriteLine($"Error reading CSV file: {ex.Message}"); + Console.WriteLine($"Error reading rewards CSV: {ex.Message}"); } // Wait for 5 minutes before checking again @@ -123,33 +309,18 @@ private static async Task MonitorCsvFileAsync() } } - private static async Task PostRandomImageUrl() + // RewardRecord class to map CSV columns + public class RewardRecord { - if (_isImageUrlsLoaded && _imageUrls.Count > 0) - { - var channel = _client.GetChannel(_channelId) as IMessageChannel; - - if (channel != null) - { - int index = _random.Next(_imageUrls.Count); - string randomUrl = _imageUrls[index]; - await channel.SendMessageAsync(randomUrl); - } - else - { - Console.WriteLine("Unable to find the channel."); - } - } - else - { - Console.WriteLine("No image URLs loaded."); - } + public string RewardName { get; set; } + public string Quantity { get; set; } } - public class RewardRecord + // Your CSV record class (make sure the fields match your actual CSV file) + public class YourRecordClass { - public string RewardName { get; set; } - public int Quantity { get; set; } + public string image_url { get; set; } + public string has_spoilers { get; set; } } } } From d1ca6f9d3a7a9239e8000f9a7beda8a7218c6427 Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 17:15:51 +0200 Subject: [PATCH 6/8] New try --- Program.cs | 124 ++++++++++++++++++++++++++++++++--------------------- 1 file changed, 75 insertions(+), 49 deletions(-) diff --git a/Program.cs b/Program.cs index ea3f427..8ea3fb0 100644 --- a/Program.cs +++ b/Program.cs @@ -7,8 +7,8 @@ using Discord; using Discord.WebSocket; using Discord.Commands; +using Discord.Rest; using CsvHelper; -using CsvHelper.Configuration; using Google.Apis.Auth.OAuth2; using Google.Apis.Drive.v3; using Google.Apis.Services; @@ -23,7 +23,6 @@ class Program private static ulong _channelId; private static string _fileId; private static string _credentialsPath; - private static string _rewardsCsvPath; // For rewards.csv path from Docker environment private static TimeSpan _postTimeSpain; private static TimeZoneInfo _spainTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"); private static bool _isImageUrlsLoaded = false; // Flag to track if image URLs are loaded @@ -35,11 +34,10 @@ static async Task Main(string[] args) var channelIdStr = Environment.GetEnvironmentVariable("DISCORD_CHANNEL_ID"); _fileId = Environment.GetEnvironmentVariable("GOOGLE_DRIVE_FILE_ID"); _credentialsPath = Environment.GetEnvironmentVariable("GOOGLE_CREDENTIALS_PATH"); - _rewardsCsvPath = Environment.GetEnvironmentVariable("REWARDS_CSV_PATH"); // Rewards CSV path from environment var postTimeStr = Environment.GetEnvironmentVariable("POST_TIME"); - // Check if token, channelId, fileId, credentialsPath, postTime, or rewardsCsvPath is null or empty - if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_fileId) || string.IsNullOrEmpty(_credentialsPath) || string.IsNullOrEmpty(postTimeStr) || string.IsNullOrEmpty(_rewardsCsvPath)) + // 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."); return; @@ -89,7 +87,7 @@ private static async Task OnReady() if (csvData != null) { using (var reader = new StringReader(csvData)) - using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture))) + using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) { _imageUrls = csv.GetRecords() .Where(record => !string.IsNullOrWhiteSpace(record.image_url) && record.has_spoilers != "yes") @@ -111,17 +109,14 @@ private static async Task OnReady() return; } + // Process rewards + await ProcessRewards(); + // Register commands await RegisterCommandsAsync(); // Schedule the first post await ScheduleNextPost(); - - // Start checking rewards.csv after URLs have been loaded - if (_isImageUrlsLoaded) - { - _ = Task.Run(CheckRewardsCsvAsync); // Runs in parallel after URLs are loaded - } } private static async Task RegisterCommandsAsync() @@ -259,68 +254,99 @@ private static async Task PostRandomImageUrl() } } - // New method to check rewards every 5 minutes - private static async Task CheckRewardsCsvAsync() + private static async Task ProcessRewards() { - while (true) // Infinite loop to run continuously + var rewardsFileId = Environment.GetEnvironmentVariable("REWARDS_FILE_ID"); + if (string.IsNullOrEmpty(rewardsFileId)) { - try + Console.WriteLine("Rewards file ID is not set."); + return; + } + + var csvData = await DownloadCsvFromGoogleDrive(rewardsFileId); + + if (csvData != null) + { + using (var reader = new StringReader(csvData)) + using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) { - if (File.Exists(_rewardsCsvPath)) // Check if the CSV file exists + var records = csv.GetRecords().ToList(); + + foreach (var record in records) { - using (var reader = new StreamReader(_rewardsCsvPath)) - using (var csv = new CsvReader(reader, new CsvConfiguration(CultureInfo.InvariantCulture))) + if (record.RewardName == "recuerdate") { - var rewards = csv.GetRecords().ToList(); - - // Find the reward named "recuerdate" - var recuerdateReward = rewards.FirstOrDefault(r => r.RewardName == "recuerdate"); - - if (recuerdateReward != null) + if (int.TryParse(record.Quantity, out int quantity)) { - if (int.TryParse(recuerdateReward.Quantity, out int quantity)) + for (int i = 0; i < quantity; i++) { - Console.WriteLine($"'recuerdate' reward found with quantity {quantity}. Posting random images..."); - - for (int i = 0; i < quantity; i++) - { - await PostRandomImageUrl(); // Post a random image - } + await PostRandomImageUrl(); } } else { - Console.WriteLine("No 'recuerdate' reward found."); + Console.WriteLine($"Invalid Quantity value for record with RewardName '{record.RewardName}'."); } } } - else - { - Console.WriteLine($"Rewards CSV file not found at {_rewardsCsvPath}."); - } } - catch (Exception ex) - { - Console.WriteLine($"Error reading rewards CSV: {ex.Message}"); - } - - // Wait for 5 minutes before checking again - await Task.Delay(TimeSpan.FromMinutes(5)); + } + else + { + Console.WriteLine("Failed to download or read the rewards CSV file."); } } - // RewardRecord class to map CSV columns - public class RewardRecord + private static async Task DownloadCsvFromGoogleDrive(string fileId) { - public string RewardName { get; set; } - public string Quantity { get; set; } + try + { + // Set up Google Drive API service + var credential = GoogleCredential.FromFile(_credentialsPath) + .CreateScoped(DriveService.Scope.DriveReadonly); + + var service = new DriveService(new BaseClientService.Initializer() + { + HttpClientInitializer = credential, + 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) + { + Console.WriteLine("Download complete."); + } + }; + + await request.DownloadAsync(stream); + + stream.Position = 0; + using (var reader = new StreamReader(stream)) + { + return reader.ReadToEnd(); + } + } + catch (Exception ex) + { + Console.WriteLine($"An error occurred: {ex.Message}"); + return null; + } } - // Your CSV record class (make sure the fields match your actual CSV file) public class YourRecordClass { public string image_url { get; set; } public string has_spoilers { get; set; } } + + public class RewardRecordClass + { + public string RewardName { get; set; } + public string Quantity { get; set; } + } } } From 82d8f7ecc424a6a87f6998ae1ae8f1c47a160423 Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 17:18:37 +0200 Subject: [PATCH 7/8] Fix v2 --- Dockerfile | 2 +- Program.cs | 61 ++++++++++-------------------------------------------- 2 files changed, 12 insertions(+), 51 deletions(-) diff --git a/Dockerfile b/Dockerfile index 924e2bc..c044430 100644 --- a/Dockerfile +++ b/Dockerfile @@ -20,7 +20,7 @@ ENV DISCORD_BOT_TOKEN="" ENV DISCORD_CHANNEL_ID="" ENV GOOGLE_DRIVE_FILE_ID="" ENV GOOGLE_CREDENTIALS_PATH="/app/credentials.json" -ENV CSV_FILE_PATH="/app/data/rewards.csv" +ENV REWARDS_CSV_PATH="/app/data/rewards.csv" ENV POST_TIME="20:00:00" # Entry point for the application diff --git a/Program.cs b/Program.cs index 8ea3fb0..fc2de84 100644 --- a/Program.cs +++ b/Program.cs @@ -27,6 +27,9 @@ class Program private static TimeZoneInfo _spainTimeZone = TimeZoneInfo.FindSystemTimeZoneById("Central European Standard Time"); private static bool _isImageUrlsLoaded = false; // Flag to track if image URLs are loaded + // Path to the local rewards CSV file + private static string _rewardsCsvPath; + static async Task Main(string[] args) { // Read environment variables @@ -35,9 +38,10 @@ static async Task Main(string[] args) _fileId = Environment.GetEnvironmentVariable("GOOGLE_DRIVE_FILE_ID"); _credentialsPath = Environment.GetEnvironmentVariable("GOOGLE_CREDENTIALS_PATH"); var postTimeStr = Environment.GetEnvironmentVariable("POST_TIME"); + _rewardsCsvPath = Environment.GetEnvironmentVariable("REWARDS_CSV_PATH"); - // 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)) + // Check if token, channelId, fileId, credentialsPath, postTime, or rewardsCsvPath is null or empty + if (string.IsNullOrEmpty(token) || string.IsNullOrEmpty(channelIdStr) || string.IsNullOrEmpty(_fileId) || string.IsNullOrEmpty(_credentialsPath) || string.IsNullOrEmpty(postTimeStr) || string.IsNullOrEmpty(_rewardsCsvPath)) { Console.WriteLine("Environment variables are not set correctly."); return; @@ -256,18 +260,15 @@ private static async Task PostRandomImageUrl() private static async Task ProcessRewards() { - var rewardsFileId = Environment.GetEnvironmentVariable("REWARDS_FILE_ID"); - if (string.IsNullOrEmpty(rewardsFileId)) + if (string.IsNullOrEmpty(_rewardsCsvPath) || !File.Exists(_rewardsCsvPath)) { - Console.WriteLine("Rewards file ID is not set."); + Console.WriteLine("Rewards CSV file not found."); return; } - var csvData = await DownloadCsvFromGoogleDrive(rewardsFileId); - - if (csvData != null) + try { - using (var reader = new StringReader(csvData)) + using (var reader = new StreamReader(_rewardsCsvPath)) using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) { var records = csv.GetRecords().ToList(); @@ -291,49 +292,9 @@ private static async Task ProcessRewards() } } } - else - { - Console.WriteLine("Failed to download or read the rewards CSV file."); - } - } - - private static async Task DownloadCsvFromGoogleDrive(string fileId) - { - try - { - // Set up Google Drive API service - var credential = GoogleCredential.FromFile(_credentialsPath) - .CreateScoped(DriveService.Scope.DriveReadonly); - - var service = new DriveService(new BaseClientService.Initializer() - { - HttpClientInitializer = credential, - 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) - { - Console.WriteLine("Download complete."); - } - }; - - await request.DownloadAsync(stream); - - stream.Position = 0; - using (var reader = new StreamReader(stream)) - { - return reader.ReadToEnd(); - } - } catch (Exception ex) { - Console.WriteLine($"An error occurred: {ex.Message}"); - return null; + Console.WriteLine($"An error occurred while processing the rewards file: {ex.Message}"); } } From ff6dd14eb15399130088746d583bed9ef82f13b9 Mon Sep 17 00:00:00 2001 From: Winnie Date: Thu, 5 Sep 2024 17:26:56 +0200 Subject: [PATCH 8/8] Update the csv accordingly --- Program.cs | 39 +++++++++++++++++++++++++++------------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/Program.cs b/Program.cs index fc2de84..9b782c0 100644 --- a/Program.cs +++ b/Program.cs @@ -268,29 +268,44 @@ private static async Task ProcessRewards() try { + var records = new List(); + + // Read the existing rewards data using (var reader = new StreamReader(_rewardsCsvPath)) using (var csv = new CsvReader(reader, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) { - var records = csv.GetRecords().ToList(); + records = csv.GetRecords().ToList(); + } - foreach (var record in records) + foreach (var record in records) + { + if (record.RewardName == "recuerdate") { - if (record.RewardName == "recuerdate") + if (int.TryParse(record.Quantity, out int quantity)) { - if (int.TryParse(record.Quantity, out int quantity)) + var imagesSent = 0; + for (int i = 0; i < quantity; i++) { - for (int i = 0; i < quantity; i++) - { - await PostRandomImageUrl(); - } - } - else - { - Console.WriteLine($"Invalid Quantity value for record with RewardName '{record.RewardName}'."); + await PostRandomImageUrl(); + imagesSent++; } + + // Update the Quantity field + record.Quantity = (quantity - imagesSent).ToString(); + } + else + { + Console.WriteLine($"Invalid Quantity value for record with RewardName '{record.RewardName}'."); } } } + + // Write the updated rewards data back to the CSV file + using (var writer = new StreamWriter(_rewardsCsvPath)) + using (var csv = new CsvWriter(writer, new CsvHelper.Configuration.CsvConfiguration(CultureInfo.InvariantCulture))) + { + csv.WriteRecords(records); + } } catch (Exception ex) {