Fixed loads of oversights

- Forgot I used IList instead of List
- Introduced the Tracer class. This allows writing text to the terminal in Debug mode, regardless of if a Debugger is attached.
Added version to 0.2.101 (0.1 outputting the original .txt file)
- Default config settings (if no file is found) is now set in GetConfig()

Honestly, this turned out to be bigger than I anticipated, but I'm enjoying myself.
This commit is contained in:
Tony Bark 2025-03-16 16:01:18 -04:00
parent 2dd63ccba0
commit 0c18cb0c34
6 changed files with 130 additions and 27 deletions

View file

@ -10,15 +10,16 @@ public class Config
/// <summary>
/// Gets or sets the name of the schedule file.
/// </summary>
public string File { get; set; } = "schedule.json";
public string? File { get; set; }
/// <summary>
/// Gets or sets the directory path where the schedule file is stored.
/// </summary>
public string Path { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
public string? Path { get; set; }
/// <summary>
/// Gets or sets the list of available topics from the configuration file.
/// </summary>
public IList<string> Topics { get; set; } = new[] { "Games", "Politics", "Research", "Technology" };
public List<string> Topics { get; set; } = new List<string>();
}

View file

@ -1,3 +1,4 @@
global using System.Diagnostics;
global using Tomlyn;
global using Tomlyn.Model;
global using PublishTimes;

View file

@ -18,8 +18,13 @@ Config GetConfig(string file = "config.toml")
return model;
}
return new Config();
var defaultList = new[] { "Games", "Politics", "Research", "Technology" };
return new Config()
{
File = "schedule.json",
Path = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
Topics = defaultList.ToList()
};
}
/// <summary>
@ -42,7 +47,7 @@ bool UserChoice(string choice)
/// delay between each while avoiding time conflicts within a 30-minute window.
/// </summary>
/// <returns>A list of TimeSpan objects representing scheduled article times.</returns>
List<TimeSpan> GenerateSchedule()
List<TimeSpan> GenerateTimes()
{
var numberOfArticles = 5; // Define how many articles to schedule
var startTime = new TimeSpan(9, 0, 0); // Starting time at 9:00 AM
@ -149,7 +154,7 @@ string NewTopic(List<string> topics)
void ExportSchedule(List<String> storeTimes)
{
// App directory is used for config file
var appDir = AppDomain.CurrentDomain.BaseDirectory;
var appDir = Tracer.AppDirectory;
// File directory is used for file location set in config
var outputDir = Directory.GetCurrentDirectory();
var cfgFile = "config.toml";
@ -166,24 +171,32 @@ void ExportSchedule(List<String> storeTimes)
// 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 usrTopics = config.Topics;
var list = config.Topics;
var tomlList = string.Join(", ", list);
var usrTopics = tomlList.Split(',');
if (!string.IsNullOrEmpty(usrDir))
outputDir = usrDir;
if (string.IsNullOrEmpty(usrDir))
return;
if (!string.IsNullOrEmpty(usrFileName))
outputFile = usrFileName;
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);
// If array is populated, apply config
if (!usrTopics.Any())
{
foreach (var usrTopic in usrTopics)
topics.Add(usrTopic);
}
// Set new file Path
filePath = Path.Combine(outputDir, outputFile!);
@ -211,10 +224,14 @@ void ExportSchedule(List<String> storeTimes)
Times = times,
});
var jsonString = JsonSerializer.Serialize(jsonList);
Console.WriteLine(jsonList);
var jsonOptions = new JsonSerializerOptions()
{
WriteIndented = true,
};
var jsonString = JsonSerializer.Serialize(jsonList, jsonOptions);
File.WriteAllText(filePath, jsonString);
Console.WriteLine($"{Environment.NewLine}Written to: {filePath}");
Tracer.WriteLine($"{jsonString}{Environment.NewLine}Written to: {filePath}");
// Clear list from memory
storeTimes.Clear();
@ -224,10 +241,10 @@ void ExportSchedule(List<String> storeTimes)
/// Displays the scheduled article times in a formatted manner and provides
/// options to export the schedule or restart the scheduling process.
/// </summary>
void PrintSchedule(bool isRestart = false)
void PrintTimes(bool isRestart = false)
{
var storeSchedule = new List<String>();
var scheduledTimes = GenerateSchedule();
var scheduledTimes = GenerateTimes();
// Clear the screen on restart
if (isRestart)
@ -245,14 +262,14 @@ void PrintSchedule(bool isRestart = false)
// Give the user an option to export the schedule
if (UserChoice("Retry?"))
PrintSchedule(true);
PrintTimes(true);
// Give the user an option to export the schedule
if (UserChoice("Export?"))
ExportSchedule(storeSchedule);
if (UserChoice("Generate A New Batch?"))
PrintSchedule(true);
PrintTimes(true);
else
{
Console.Clear();
@ -261,4 +278,4 @@ void PrintSchedule(bool isRestart = false)
}
// Start the loop
PrintSchedule();
PrintTimes();

View file

@ -4,6 +4,7 @@
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Version>0.2.101</Version>
<Nullable>enable</Nullable>
</PropertyGroup>

View file

@ -6,12 +6,29 @@ It is not recommended for use with hot topics. Instead, you should focus on over
## Exporting
Once it generates a list of times, you can retry or export the times. If you export, you're requested to select from a number of topics or default to none if no selection is made. Upon export, you can start over or exit.
Once it generates a list of times, you can retry or export it as a JSON format. If you export, you're requested to select from a number of topics or default to none if no selection is made. Upon export, you can start over or exit.
Choice selection is based on the Y/N keys. ``Enter`` works the same as ``Y`` while pressing any other key is the equivalent of ``N``. You can make mistakes, but it expects failure.
An optional ``config.toml`` file allows for further customization of file name, directory, and topics.
### Example
```json
[
{
"topic": "Games",
"times": [
"11:41 AM",
"2:05 PM",
"5:05 PM",
"8:18 PM",
"11:02 PM"
]
}
]
```
## Background
A while back, I [found a tool](https://schedule.lemmings.world) to schedule articles on Lemmy. I've been posting within a few hours apart at random minutes and I wanted to something decide that for me. I had AI write the base algorithm, everything else is my own touches.

66
Tracer.cs Normal file
View file

@ -0,0 +1,66 @@
// I hereby waive this project under the public domain - see UNLICENSE for details.
namespace PublishTimes;
/// <summary>
/// Provides debug-only console output methods.
/// These methods are only executed when the application is compiled in DEBUG mode.
/// </summary>
internal static class Tracer
{
/// <summary>
/// Writes a line of text to the console, but only when in DEBUG mode.
/// </summary>
/// <param name="content">The text to write to the console.</param>
[Conditional("DEBUG")]
internal static void WriteLine(string content) =>
Console.WriteLine(content);
/// <summary>
/// Writes text to the console without a newline, but only when in DEBUG mode.
/// </summary>
/// <param name="content">The text to write to the console.</param>
[Conditional("DEBUG")]
internal static void Write(string content) =>
Console.Write(content);
/// <summary>
/// Writes multiple lines of text to the console, but only when in DEBUG mode.
/// </summary>
/// <param name="contents">A collection of text lines to write to the console.</param>
[Conditional("DEBUG")]
internal static void WriteLine(IEnumerable<string> contents)
{
foreach (var content in contents)
{
Console.WriteLine(content);
}
}
/// <summary>
/// Writes multiple text entries to the console without newlines, but only when in DEBUG mode.
/// </summary>
/// <param name="contents">A collection of text entries to write to the console.</param>
[Conditional("DEBUG")]
internal static void Write(IEnumerable<string> contents)
{
foreach (var content in contents)
{
Console.Write(content);
}
}
/// <summary>
/// Gets the current working directory in DEBUG mode or the application's base directory in release mode.
/// </summary>
internal static string AppDirectory
{
get
{
#if DEBUG
return Directory.GetCurrentDirectory();
#else
return AppDomain.CurrentDomain.BaseDirectory;
#endif
}
}
}