From 188318c72409c4ca3295f93e4f3d14d0cc23c1f1 Mon Sep 17 00:00:00 2001 From: Tony Bark Date: Sat, 22 Mar 2025 19:37:05 -0400 Subject: [PATCH] Huge Refactor - Cleaned up Program.cs by moving a lot of functions to their own classes - Renamed topics to community - Choosing a community is no longer optional with the switch to JSON - Added csharpier tool and reformttered all code --- .config/dotnet-tools.json | 13 ++ .gitignore | 2 +- Config.cs | 25 ++- Export.cs | 128 +++++++++++++++ Generator.cs | 60 +++++++ GlobalUsings.cs | 7 +- Interactive.cs | 95 +++++++++++ Program.cs | 333 +++----------------------------------- README.md | 2 +- Schedule.cs | 13 +- Tracer.cs | 98 +++++------ config.toml.sample | 2 +- 12 files changed, 396 insertions(+), 382 deletions(-) create mode 100644 .config/dotnet-tools.json create mode 100644 Export.cs create mode 100644 Generator.cs create mode 100644 Interactive.cs diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json new file mode 100644 index 0000000..393d187 --- /dev/null +++ b/.config/dotnet-tools.json @@ -0,0 +1,13 @@ +{ + "version": 1, + "isRoot": true, + "tools": { + "csharpier": { + "version": "0.30.6", + "commands": [ + "dotnet-csharpier" + ], + "rollForward": false + } + } +} \ No newline at end of file diff --git a/.gitignore b/.gitignore index cbc3037..2f4c5de 100644 --- a/.gitignore +++ b/.gitignore @@ -546,4 +546,4 @@ FodyWeavers.xsd .idea/** *.txt *.toml -*.json \ No newline at end of file +schedule.json \ No newline at end of file diff --git a/Config.cs b/Config.cs index 9641754..bff3157 100644 --- a/Config.cs +++ b/Config.cs @@ -7,19 +7,18 @@ namespace StaggerPost; /// public class Config { - /// - /// Gets or sets the name of the schedule file. - /// - public string? File { get; set; } + /// + /// Gets or sets the name of the schedule file. + /// + public string? File { get; set; } - /// - /// Gets or sets the directory path where the schedule file is stored. - /// - public string? Path { get; set; } - - /// - /// Gets or sets the list of available topics from the configuration file. - /// - public List Topics { get; set; } = new List(); + /// + /// Gets or sets the directory path where the schedule file is stored. + /// + public string? Path { get; set; } + /// + /// Gets or sets the list of available topics from the configuration file. + /// + public List Communities { get; set; } = new List(); } diff --git a/Export.cs b/Export.cs new file mode 100644 index 0000000..ec55658 --- /dev/null +++ b/Export.cs @@ -0,0 +1,128 @@ +// I hereby waive this project under the public domain - see UNLICENSE for details. +namespace StaggerPost; + +internal static class Export +{ + /// + /// Retrieves configuration settings from a TOML file if it exists; otherwise, returns a default configuration. + /// + /// The name of the configuration file (defaults to "config.toml"). + /// A Config object populated with values from the file, or a default Config instance if the file is not found. + static Config GetConfig(string file) + { + var cfgPath = Path.Combine(Tracer.AppDirectory, file); + + if (!File.Exists(cfgPath)) + { + Tracer.LogLine("Config file not found. Switching to defaults."); + var defaultList = new[] + { + "games@lemmy.world", + "politics@lemmy.world", + "science@lemmy.world", + "technology@lemmy.world", + }; + + var config = new Config() + { + File = "schedule.json", + Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), + Communities = defaultList.ToList(), + }; + + return config; + } + + Tracer.LogLine($"Discovered config file: {cfgPath}"); + var toml = File.ReadAllText(cfgPath); + var model = Toml.ToModel(toml); + + return model; + } + + /// + /// Exports the scheduled articles to a file, allowing the user to modify + /// the directory, filename, and list of topics based on + /// a configuration file if available. + /// + public static void ToJSON(List storeTimes, string cfgPath) + { + // File directory is used for file location set in config + var outputDir = Directory.GetCurrentDirectory(); + var topics = new List(); + var config = GetConfig(cfgPath); + var outputFile = config.File; + var filePath = Path.Combine(outputDir, outputFile!); + var chosenTopic = ""; + var times = new List(); + + // If the config file exists, read from that but don't assume anything is filled + if (File.Exists(cfgPath)) + { + var toml = File.ReadAllText(cfgPath); + var usrDir = config.Path; + var usrFileName = config.File; + // Convert list into array + var list = config.Communities; + var tomlList = string.Join(", ", list); + var usrTopics = tomlList.Split(','); + + if (string.IsNullOrEmpty(usrDir)) + return; + + outputDir = usrDir; + + if (string.IsNullOrEmpty(usrFileName)) + return; + + outputFile = usrFileName; + + // If array is empty, return; otherwise, apply config + if (usrTopics.Length < 0) + return; + + foreach (var usrTopic in usrTopics) + topics.Add(usrTopic); + + // Set new file Path + filePath = Path.Combine(outputDir, outputFile!); + } + + if (!File.Exists(filePath)) + File.WriteAllText(filePath, "[]"); + + foreach (var time in storeTimes) + times.Add(time.Trim()); + + // Set new topic + topics = config.Communities.ToList(); + Console.Clear(); + chosenTopic = Interactive.SelectTopics(topics); + + var date = Interactive.SelectDate(); + + // Write to file. + var jsonFile = File.ReadAllText(filePath); + var jsonList = string.IsNullOrWhiteSpace(jsonFile) + ? new List() + : JsonSerializer.Deserialize>(jsonFile) ?? new List(); + + jsonList.Add( + new Schedule() + { + Community = chosenTopic.Trim(), + Date = date.Trim(), + Times = times, + } + ); + + var jsonOptions = new JsonSerializerOptions() { WriteIndented = true }; + + var json = JsonSerializer.Serialize(jsonList, jsonOptions); + File.WriteAllText(filePath, json); + Tracer.LogLine($"{json}{Environment.NewLine}Written to: {filePath}"); + + // Clear list from memory + storeTimes.Clear(); + } +} diff --git a/Generator.cs b/Generator.cs new file mode 100644 index 0000000..d0cd437 --- /dev/null +++ b/Generator.cs @@ -0,0 +1,60 @@ +// I hereby waive this project under the public domain - see UNLICENSE for details. +namespace StaggerPost; + +internal static class Generator +{ + /// + /// Generates a schedule of article publishing times, ensuring a randomized + /// delay between each while avoiding time conflicts within a 30-minute window. + /// + /// A list of TimeSpan objects representing scheduled article times. + public static List GenerateTimes() + { + var numberOfArticles = 5; // Define how many articles to schedule + var startTime = new TimeSpan(9, 0, 0); // Starting time at 9:00 AM + var rng = new Random(); + var scheduledTimes = new List(); + + for (int i = 0; i < numberOfArticles; i++) + { + var baseDelayHours = rng.Next(2, 4); // Randomly choose between 2-3 hours delay + var minutesToAdd = rng.Next(0, 60); // Randomly choose minutes (0-59) + + // Calculate new time by adding base delay and random minutes + var nextTime = startTime.Add(new TimeSpan(baseDelayHours, minutesToAdd, 0)); + + // Check if the new time is within 30 minutes of any existing time + while ( + scheduledTimes.Exists(previousTime => + Math.Abs((nextTime - previousTime).TotalMinutes) < 30 + ) + ) + { + // If the new time is within 30 minutes of an existing time, adjust it + nextTime = nextTime.Add(new TimeSpan(0, 30, 0)); + } + + scheduledTimes.Add(nextTime); + startTime = nextTime; // Update start time for the next article + } + + return scheduledTimes; + } + + /// + /// Converts a TimeSpan into a 12-hour AM/PM formatted time string. + /// + /// The TimeSpan representing the time of day. + /// A formatted string representing the time in AM/PM format. + public static string ConvertTo12Hour(TimeSpan time) + { + var minutes = time.TotalMinutes; + var hours12 = time.Hours % 12; + + if (hours12 == 0) + hours12 = 1; + + var period = time.Hours >= 12 ? "PM" : "AM"; + return $"{hours12}:{time.Minutes:D2} {period}"; + } +} diff --git a/GlobalUsings.cs b/GlobalUsings.cs index 6a39b5d..40e65af 100644 --- a/GlobalUsings.cs +++ b/GlobalUsings.cs @@ -1,6 +1,7 @@ global using System.Diagnostics; +global using System.Text; +global using System.Text.Json; +global using System.Text.Json.Serialization; +global using StaggerPost; global using Tomlyn; global using Tomlyn.Model; -global using StaggerPost; -global using System.Text.Json; -global using System.Text.Json.Serialization; \ No newline at end of file diff --git a/Interactive.cs b/Interactive.cs new file mode 100644 index 0000000..db2d3e8 --- /dev/null +++ b/Interactive.cs @@ -0,0 +1,95 @@ +// I hereby waive this project under the public domain - see UNLICENSE for details. +namespace StaggerPost; + +internal static class Interactive +{ + /// + /// Prompts the user with a yes/no question and returns their choice as a boolean value. + /// + /// The message to display to the user. + /// True if the user selects 'Y' or presses Enter, otherwise false. + public static bool UserChoice(string choice) + { + Console.WriteLine($"{Environment.NewLine}{choice} Y/N"); + var input = Console.ReadKey().Key; + if (input == ConsoleKey.Y || input == ConsoleKey.Enter) + return true; + + return false; + } + + /// + /// Prompts the user to select a topic from a given list + /// and returns the chosen topic. + /// + /// An array of available topics. + /// The selected topic as a string. + public static string SelectTopics(List communities) + { + var topicChoice = ""; + var topicNum = 0; + var userChoices = new List(); + var numOfTopics = 0; + var topicDict = new Dictionary(); + + foreach (var community in communities) + { + numOfTopics++; + var title = community.Trim(); + topicDict.Add(numOfTopics, title); + userChoices.Add( + $"{Environment.NewLine}{numOfTopics} {title.TrimEnd(new char[] { ',' })}" + ); + } + + var topicSelect = string.Join(", ", userChoices.ToArray()); + Console.WriteLine($"{Environment.NewLine}Choose a Topic{Environment.NewLine}{topicSelect}"); + var input = Console.ReadLine(); + + // Attempt to parse a number. + if (int.TryParse(input, out topicNum) == true) + topicChoice = topicDict[topicNum]; + else + SelectTopics(communities); + + return topicChoice; + } + + /// + /// Prompts the user to select a date (either today or tomorrow) and returns the selected date as a formatted string. + /// + /// A string representing the selected date in a short date format. + public static string SelectDate() + { + var dtChoices = new[] { "Today", "Tomorrow" }; + var dtDict = new Dictionary(); + var dtSelection = new List(); + var dtChoice = 0; + var dtNum = 0; + + foreach (var days in dtChoices) + { + dtNum++; + var day = days.Trim(); + dtDict.Add(dtNum, day); + dtSelection.Add($"{dtNum} {day}"); + } + + var topicSelect = string.Join(", ", dtSelection.ToArray()); + Console.WriteLine($"{Environment.NewLine}Choose a Date{Environment.NewLine}{topicSelect}"); + var input = Console.ReadLine(); + + // Attempt to parse a number. + if (int.TryParse(input, out dtNum) == true) + dtChoice = dtNum; + + // Any choice above 2 tomorrow + if (dtChoice >= 2) + { + var dt = DateTime.Now.AddDays(1); + return dt.ToString("d"); + } + + return DateTime.Today.ToString("d"); + } +} diff --git a/Program.cs b/Program.cs index 2b8e318..754ae66 100644 --- a/Program.cs +++ b/Program.cs @@ -1,322 +1,41 @@ // I hereby waive this project under the public domain - see UNLICENSE for details. -/// -/// Retrieves configuration settings from a TOML file if it exists; otherwise, returns a default configuration. -/// -/// The name of the configuration file (defaults to "config.toml"). -/// A Config object populated with values from the file, or a default Config instance if the file is not found. -Config GetConfig(string file = "config.toml") -{ - // App directory is used for config file - var appDir = AppDomain.CurrentDomain.BaseDirectory; - var cfgPath = Path.Combine(appDir, file); - - if (File.Exists(cfgPath)) - { - var toml = File.ReadAllText(cfgPath); - var model = Toml.ToModel(toml); - - return model; - } - var defaultList = new[] { "Games", "Politics", "Research", "Technology" }; - return new Config() - { - File = "schedule.json", - Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), - Topics = defaultList.ToList() - }; -} - -/// -/// Prompts the user with a yes/no question and returns their choice as a boolean value. -/// -/// The message to display to the user. -/// True if the user selects 'Y' or presses Enter, otherwise false. -bool UserChoice(string choice) -{ - Console.WriteLine($"{Environment.NewLine}{choice} Y/N"); - var input = Console.ReadKey().Key; - if (input == ConsoleKey.Y || input == ConsoleKey.Enter) - return true; - - return false; -} - -/// -/// Generates a schedule of article publishing times, ensuring a randomized -/// delay between each while avoiding time conflicts within a 30-minute window. -/// -/// A list of TimeSpan objects representing scheduled article times. -List GenerateTimes() -{ - var numberOfArticles = 5; // Define how many articles to schedule - var startTime = new TimeSpan(9, 0, 0); // Starting time at 9:00 AM - var rng = new Random(); - var scheduledTimes = new List(); - - for (int i = 0; i < numberOfArticles; i++) - { - var baseDelayHours = rng.Next(2, 4); // Randomly choose between 2-3 hours delay - var minutesToAdd = rng.Next(0, 60); // Randomly choose minutes (0-59) - - // Calculate new time by adding base delay and random minutes - var nextTime = startTime.Add(new TimeSpan(baseDelayHours, minutesToAdd, 0)); - - // Check if the new time is within 30 minutes of any existing time - while (scheduledTimes.Exists(previousTime => Math.Abs((nextTime - previousTime).TotalMinutes) < 30)) - { - // If the new time is within 30 minutes of an existing time, adjust it - nextTime = nextTime.Add(new TimeSpan(0, 30, 0)); - } - - scheduledTimes.Add(nextTime); - startTime = nextTime; // Update start time for the next article - } - - return scheduledTimes; -} - -/// -/// Converts a TimeSpan into a 12-hour AM/PM formatted time string. -/// -/// The TimeSpan representing the time of day. -/// A formatted string representing the time in AM/PM format. -string ConvertTo12Hour(TimeSpan time) -{ - var minutes = time.TotalMinutes; - var hours12 = time.Hours % 12; - - if (hours12 == 0) - hours12 = 1; - - var period = time.Hours >= 12 ? "PM" : "AM"; - return $"{hours12}:{time.Minutes:D2} {period}"; -} - -/// -/// Prompts the user to select a topic from a given list -/// and returns the chosen topic. -/// -/// An array of available topics. -/// The selected topic as a string. -string SelectTopics(List topics) -{ - var topicChoice = ""; - var topicNum = 0; - var userChoices = new List(); - var numOfTopics = 0; - var topicDict = new Dictionary(); - - foreach (var topic in topics) - { - numOfTopics++; - var title = topic.Trim(); - topicDict.Add(numOfTopics, title); - userChoices.Add($"{numOfTopics} {title}"); - } - - var topicSelect = string.Join(", ", userChoices.ToArray()); - Console.WriteLine($"{Environment.NewLine}Choose a Topic{Environment.NewLine}{topicSelect}"); - var input = Console.ReadLine(); - - // Attempt to parse a number. - if (int.TryParse(input, out topicNum) == true) - topicChoice = topicDict[topicNum]; - else - NewTopic(topics); - - return topicChoice; -} - -/// -/// Prompts the user to select a date (either today or tomorrow) and returns the selected date as a formatted string. -/// -/// A string representing the selected date in a short date format. -string SelectDate() -{ - var dtChoices = new[] { "Today", "Tomorrow" }; - var dtDict = new Dictionary(); - var dtSelection = new List(); - var dtChoice = 0; - var dtNum = 0; - - foreach (var days in dtChoices) - { - dtNum++; - var day = days.Trim(); - dtDict.Add(dtNum, day); - dtSelection.Add($"{dtNum} {day}"); - } - - var topicSelect = string.Join(", ", dtSelection.ToArray()); - Console.WriteLine($"{Environment.NewLine}Choose a Date{Environment.NewLine}{topicSelect}"); - var input = Console.ReadLine(); - - // Attempt to parse a number. - if (int.TryParse(input, out dtNum) == true) - dtChoice = dtNum; - - // Any choice above 2 tomorrow - if (dtChoice >= 2) - { - var dt = DateTime.Now.AddDays(1); - return dt.ToString("d"); - } - - return DateTime.Today.ToString("d"); -} - -/// -/// Allows the user to choose a new topic from a given list or default to placeholder if no selection is made. -/// -/// A list of available topics. -/// The selected topic or a default placeholder if none is chosen. -string NewTopic(List topics) -{ - var newTopic = ""; - - if (UserChoice("Choose a Topic?")) - newTopic = SelectTopics(topics); - else - newTopic = "Any"; - - return newTopic; -} - -/// -/// Exports the scheduled articles to a file, allowing the user to modify -/// the directory, filename, and list of topics based on -/// a configuration file if available. -/// -void ExportSchedule(List storeTimes) -{ - // App directory is used for config file - var appDir = Tracer.AppDirectory; - // File directory is used for file location set in config - var outputDir = Directory.GetCurrentDirectory(); - var cfgFile = "config.toml"; - - var topics = new List(); - var cfgPath = Path.Combine(appDir, cfgFile); - var config = GetConfig(cfgPath); - var outputFile = config.File; - var filePath = Path.Combine(outputDir, outputFile!); - var chosenTopic = ""; - var times = new List(); - - - // If the config file exists, read from that but don't assume anything is filled - if (File.Exists(cfgPath)) - { - Tracer.WriteLine(cfgPath); - var toml = File.ReadAllText(cfgPath); - var usrDir = config.Path; - var usrFileName = config.File; - // Convert list into array - var list = config.Topics; - var tomlList = string.Join(", ", list); - var usrTopics = tomlList.Split(','); - - if (string.IsNullOrEmpty(usrDir)) - return; - - outputDir = usrDir; - - if (string.IsNullOrEmpty(usrFileName)) - return; - - outputFile = usrFileName; - - // If array is empty, return; otherwise, apply config - if (usrTopics.Length < 0) - return; - - foreach (var usrTopic in usrTopics) - topics.Add(usrTopic); - - - // Set new file Path - filePath = Path.Combine(outputDir, outputFile!); - } - - if (!File.Exists(filePath)) - File.WriteAllText(filePath, "[]"); - - foreach (var time in storeTimes) - times.Add(time.Trim()); - - // Set new topic - topics = config.Topics.ToList(); - chosenTopic = NewTopic(topics); - - var date = SelectDate(); - - // Write to file. - var jsonContent = File.ReadAllText(filePath); - var jsonList = string.IsNullOrWhiteSpace(jsonContent) ? new List() - : JsonSerializer.Deserialize>(jsonContent) ?? new List(); - - - jsonList.Add(new Schedule() - { - Topic = chosenTopic.Trim(), - Date = date.Trim(), - Times = times, - }); - - var jsonOptions = new JsonSerializerOptions() - { - WriteIndented = true, - }; - - var jsonString = JsonSerializer.Serialize(jsonList, jsonOptions); - File.WriteAllText(filePath, jsonString); - Tracer.WriteLine($"{jsonString}{Environment.NewLine}Written to: {filePath}"); - - // Clear list from memory - storeTimes.Clear(); -} - /// /// Displays the scheduled article times in a formatted manner and provides /// options to export the schedule or restart the scheduling process. /// -void PrintTimes(bool isRestart = false) +void PrintTimes() { - var storeSchedule = new List(); - var scheduledTimes = GenerateTimes(); + var storeSchedule = new List(); + var scheduledTimes = Generator.GenerateTimes(); - // Clear the screen on restart - if (isRestart) - Console.Clear(); + // Clear the screen on restart + Console.Clear(); - Console.WriteLine("=== Publish Times ==="); - foreach (var time in scheduledTimes) - { - var articleTime = $"{ConvertTo12Hour(time)}"; - // Correct format string to display time in 12-hour format with AM/PM - Console.WriteLine(articleTime); - // Store the schedule to memory for option export - storeSchedule.Add(articleTime); - } + Console.WriteLine("=== Publish Times ==="); + foreach (var time in scheduledTimes) + { + var articleTime = $"{Generator.ConvertTo12Hour(time)}"; + // Correct format string to display time in 12-hour format with AM/PM + Console.WriteLine(articleTime); + // Store the schedule to memory for option export + storeSchedule.Add(articleTime); + } - // Give the user an option to export the schedule - if (UserChoice("Retry?")) - PrintTimes(true); + // Give the user an option to export the schedule + if (Interactive.UserChoice("Retry?")) + PrintTimes(); - // Give the user an option to export the schedule - if (UserChoice("Export?")) - ExportSchedule(storeSchedule); + // Give the user an option to export the schedule + Export.ToJSON(storeSchedule, "config.toml"); - if (UserChoice("Generate A New Batch?")) - PrintTimes(true); - else - { - Console.Clear(); - Environment.Exit(Environment.ExitCode); - } + if (Interactive.UserChoice("Generate A New Batch?")) + PrintTimes(); + else + { + Console.Clear(); + Environment.Exit(Environment.ExitCode); + } } // Start the loop diff --git a/README.md b/README.md index 6d51334..f95aa56 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # StaggerPost -This is a very simple console application that generates a list of times to publish news articles within a randomized 2-3 hour delay within a 30-minute window to avoid conflicts. This keeps thing flowing at an organic and slow pace. +This is a very simple console application that suggests a list of times to post news articles within a randomized 2-3 hour and 30-minute delay to avoid conflicts. This keeps thing flowing at an organic and slow pace. It is not recommended for use with hot topics. Instead, you should focus on overlooked foreign affairs, local news or op-eds. Of course, this is just covering general news. diff --git a/Schedule.cs b/Schedule.cs index c430bc9..0591288 100644 --- a/Schedule.cs +++ b/Schedule.cs @@ -1,12 +1,11 @@ - public class Schedule { - [JsonPropertyName("topic")] - public string Topic { get; set; } = ""; + [JsonPropertyName("community")] + public string Community { get; set; } = ""; - [JsonPropertyName("date")] - public string Date { get; set; } = ""; + [JsonPropertyName("date")] + public string Date { get; set; } = ""; - [JsonPropertyName("times")] - public IList Times { get; set; } = new List(); + [JsonPropertyName("times")] + public IList Times { get; set; } = new List(); } diff --git a/Tracer.cs b/Tracer.cs index ca6190e..a64c3a6 100644 --- a/Tracer.cs +++ b/Tracer.cs @@ -7,60 +7,60 @@ namespace StaggerPost; /// internal static class Tracer { - /// - /// Writes a line of text to the console, but only when in DEBUG mode. - /// - /// The text to write to the console. - [Conditional("DEBUG")] - internal static void WriteLine(string content) => - Console.WriteLine(content); + const string LOG = "[LOG]:"; - /// - /// Writes text to the console without a newline, but only when in DEBUG mode. - /// - /// The text to write to the console. - [Conditional("DEBUG")] - internal static void Write(string content) => - Console.Write(content); + /// + /// Writes a line of text to the console, but only when in DEBUG mode. + /// + /// The text to write to the console. + [Conditional("DEBUG")] + internal static void LogLine(string content) => Console.WriteLine($"{LOG} {content}"); - /// - /// Writes multiple lines of text to the console, but only when in DEBUG mode. - /// - /// A collection of text lines to write to the console. - [Conditional("DEBUG")] - internal static void WriteLine(IEnumerable contents) - { - foreach (var content in contents) - { - Console.WriteLine(content); - } - } + /// + /// Writes text to the console without a newline, but only when in DEBUG mode. + /// + /// The text to write to the console. + [Conditional("DEBUG")] + internal static void Log(string content) => Console.Write($"{LOG} {content}"); - /// - /// Writes multiple text entries to the console without newlines, but only when in DEBUG mode. - /// - /// A collection of text entries to write to the console. - [Conditional("DEBUG")] - internal static void Write(IEnumerable contents) - { - foreach (var content in contents) - { - Console.Write(content); - } - } + /// + /// Writes multiple lines of text to the console, but only when in DEBUG mode. + /// + /// A collection of text lines to write to the console. + [Conditional("DEBUG")] + internal static void LogLine(IEnumerable contents) + { + foreach (var content in contents) + { + Console.WriteLine($"{LOG} {content}"); + } + } - /// - /// Gets the current working directory in DEBUG mode or the application's base directory in release mode. - /// - internal static string AppDirectory - { - get - { + /// + /// Writes multiple text entries to the console without newlines, but only when in DEBUG mode. + /// + /// A collection of text entries to write to the console. + [Conditional("DEBUG")] + internal static void Log(IEnumerable contents) + { + foreach (var content in contents) + { + Console.Write($"{LOG} {content}"); + } + } + + /// + /// Gets the current working directory in DEBUG mode or the application's base directory in release mode. + /// + internal static string AppDirectory + { + get + { #if DEBUG - return Directory.GetCurrentDirectory(); + return Directory.GetCurrentDirectory(); #else - return AppDomain.CurrentDomain.BaseDirectory; + return AppDomain.CurrentDomain.BaseDirectory; #endif - } - } + } + } } diff --git a/config.toml.sample b/config.toml.sample index c17da12..109b81f 100644 --- a/config.toml.sample +++ b/config.toml.sample @@ -1,6 +1,6 @@ path = "/home/tonytins/Documents/" file = "newscycle.json" -topics = [ +communities = [ "Games", "News", "Science",