mirror of
https://github.com/tonytins/StaggerPost.git
synced 2025-03-17 19:21:21 +00:00
Switch to Json (broken)
This commit is contained in:
parent
5cccb9a4b2
commit
ac1d3862c6
8 changed files with 213 additions and 37 deletions
128
.editorconfig
Normal file
128
.editorconfig
Normal file
|
@ -0,0 +1,128 @@
|
|||
# editorconfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Default settings:
|
||||
# A newline ending every file
|
||||
# Use 4 spaces as indentation
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = crlf
|
||||
indent_style = tab
|
||||
indent_size = 4
|
||||
insert_final_newline = false
|
||||
trim_trailing_whitespace = true
|
||||
dotnet_style_operator_placement_when_wrapping = beginning_of_line
|
||||
tab_width = 4
|
||||
|
||||
# C# files
|
||||
[*.cs]
|
||||
# New line preferences
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = true
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
csharp_new_line_between_query_expression_clauses = true
|
||||
|
||||
# Indentation preferences
|
||||
csharp_indent_block_contents = true
|
||||
csharp_indent_braces = false
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
csharp_indent_labels = one_less_than_current
|
||||
|
||||
# avoid this. unless absolutely necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
|
||||
# only use var when it's obvious what the variable type is
|
||||
csharp_style_var_for_built_in_types = true:none
|
||||
csharp_style_var_when_type_is_apparent = true:none
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
|
||||
# use language keywords instead of BCL types
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
|
||||
# Use UPPER_CASE for private or internal constant fields
|
||||
dotnet_naming_rule.constants_should_be_upper_case.severity = suggestion
|
||||
dotnet_naming_rule.constants_should_be_upper_case.symbols = constants
|
||||
dotnet_naming_rule.constants_should_be_upper_case.style = constant_style
|
||||
|
||||
dotnet_naming_symbols.constants.applicable_kinds = field, local
|
||||
dotnet_naming_symbols.constants.required_modifiers = const
|
||||
|
||||
dotnet_naming_style.constant_style.capitalization = all_upper
|
||||
|
||||
# Comment this group and uncomment out the next group if you don't want _ prefixed fields.
|
||||
|
||||
# internal and private fields should be _camel_case
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.severity = suggestion
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.symbols = private_internal_fields
|
||||
dotnet_naming_rule.camel_case_for_private_internal_fields.style = camel_case_underscore_style
|
||||
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_kinds = field
|
||||
dotnet_naming_symbols.private_internal_fields.applicable_accessibilities = private, internal
|
||||
|
||||
dotnet_naming_style.camel_case_underscore_style.required_prefix = _
|
||||
dotnet_naming_style.camel_case_underscore_style.capitalization = camel_case
|
||||
|
||||
# Code style defaults
|
||||
dotnet_sort_system_directives_first = true
|
||||
csharp_preserve_single_line_blocks = true
|
||||
csharp_preserve_single_line_statements = false
|
||||
|
||||
# Expression-level preferences
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
|
||||
# Expression-bodied members
|
||||
csharp_style_expression_bodied_methods = false:none
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
csharp_style_expression_bodied_operators = false:none
|
||||
csharp_style_expression_bodied_properties = true:none
|
||||
csharp_style_expression_bodied_indexers = true:none
|
||||
csharp_style_expression_bodied_accessors = true:none
|
||||
|
||||
# Pattern matching
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
|
||||
# Null checking preferences
|
||||
csharp_style_throw_expression = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
|
||||
# Space preferences
|
||||
csharp_space_after_cast = false
|
||||
csharp_space_after_colon_in_inheritance_clause = true
|
||||
csharp_space_after_comma = true
|
||||
csharp_space_after_dot = false
|
||||
csharp_space_after_keywords_in_control_flow_statements = true
|
||||
csharp_space_after_semicolon_in_for_statement = true
|
||||
csharp_space_around_binary_operators = before_and_after
|
||||
csharp_space_before_colon_in_inheritance_clause = true
|
||||
csharp_space_before_comma = false
|
||||
csharp_space_before_dot = false
|
||||
csharp_space_before_open_square_brackets = false
|
||||
csharp_space_before_semicolon_in_for_statement = false
|
||||
csharp_space_between_empty_square_brackets = false
|
||||
csharp_space_between_method_call_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_call_name_and_opening_parenthesis = false
|
||||
csharp_space_between_method_call_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_empty_parameter_list_parentheses = false
|
||||
csharp_space_between_method_declaration_name_and_open_parenthesis = false
|
||||
csharp_space_between_method_declaration_parameter_list_parentheses = false
|
||||
csharp_space_between_parentheses = false
|
||||
csharp_space_between_square_brackets = false
|
||||
csharp_using_directive_placement = outside_namespace:silent
|
||||
csharp_prefer_simple_using_statement = true:suggestion
|
||||
csharp_prefer_braces = when_multiline:silent
|
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -546,3 +546,4 @@ FodyWeavers.xsd
|
|||
.idea/**
|
||||
*.txt
|
||||
*.toml
|
||||
*.json
|
|
@ -10,15 +10,15 @@ public class Config
|
|||
/// <summary>
|
||||
/// Gets or sets the name of the schedule file.
|
||||
/// </summary>
|
||||
public string? File { get; set; }
|
||||
public string File { get; set; } = "schedule.txt";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the directory path where the schedule file is stored.
|
||||
/// </summary>
|
||||
public string? Path { get; set; }
|
||||
public string Path { get; set; } = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the list of available topics from the configuration file.
|
||||
/// </summary>
|
||||
public TomlArray? Topics { get; set; }
|
||||
public IList<string> Topics { get; set; } = new[] { "Games", "Politics", "Research", "Technology" };
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
global using Tomlyn;
|
||||
global using Tomlyn.Model;
|
||||
global using PublishTimes;
|
||||
global using System.Text.Json;
|
||||
global using System.Text.Json.Serialization;
|
94
Program.cs
94
Program.cs
|
@ -1,5 +1,27 @@
|
|||
// I hereby waive this project under the public domain - see UNLICENSE for details.
|
||||
|
||||
/// <summary>
|
||||
/// Retrieves configuration settings from a TOML file if it exists; otherwise, returns a default configuration.
|
||||
/// </summary>
|
||||
/// <param name="file">The name of the configuration file (defaults to "config.toml").</param>
|
||||
/// <returns>A Config object populated with values from the file, or a default Config instance if the file is not found.</returns>
|
||||
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<Config>(toml);
|
||||
|
||||
return model;
|
||||
}
|
||||
|
||||
return new Config();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Prompts the user with a yes/no question and returns their choice as a boolean value.
|
||||
/// </summary>
|
||||
|
@ -90,7 +112,7 @@ string SelectTopics(List<string> topics)
|
|||
}
|
||||
|
||||
var selection = string.Join(", ", userChoices.ToArray());
|
||||
Console.WriteLine($"{Environment.NewLine}Select a Topic (Choose a Number){Environment.NewLine}{selection}");
|
||||
Console.WriteLine($"{Environment.NewLine}Select a Number{Environment.NewLine}{selection}");
|
||||
var input = Console.ReadLine();
|
||||
|
||||
// Attempt to parse a number.
|
||||
|
@ -114,7 +136,7 @@ string NewTopic(List<string> topics)
|
|||
if (UserChoice("Choose a Topic?"))
|
||||
newTopic = SelectTopics(topics);
|
||||
else
|
||||
newTopic = "===";
|
||||
newTopic = "Any";
|
||||
|
||||
return newTopic;
|
||||
}
|
||||
|
@ -130,24 +152,24 @@ void ExportSchedule(List<String> storeSchedule)
|
|||
var appDir = AppDomain.CurrentDomain.BaseDirectory;
|
||||
// File directory is used for file location set in config
|
||||
var outputDir = Directory.GetCurrentDirectory();
|
||||
var defaultTopics = new[] { "Games", "Politics", "Research", "Technology" };
|
||||
var outputFile = "schedule.txt";
|
||||
var cfgFile = "config.toml";
|
||||
|
||||
var topics = new List<string>();
|
||||
var cfgPath = Path.Combine(appDir, cfgFile);
|
||||
var filePath = Path.Combine(outputDir, outputFile);
|
||||
var appendSchedule = false;
|
||||
var topic = "";
|
||||
var config = GetConfig(cfgPath);
|
||||
var outputFile = config.File;
|
||||
var filePath = Path.Combine(outputDir, outputFile!);
|
||||
var chosenTopic = "";
|
||||
|
||||
|
||||
// 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 model = Toml.ToModel<Config>(toml);
|
||||
var usrDir = model.Path;
|
||||
var usrFileName = model.File;
|
||||
var tomlList = string.Join(", ", model.Topics);
|
||||
var usrList = tomlList.Split(',');
|
||||
var usrDir = config.Path;
|
||||
var usrFileName = config.File;
|
||||
// Convert list into array
|
||||
var usrTopics = config.Topics;
|
||||
|
||||
if (!string.IsNullOrEmpty(usrDir))
|
||||
outputDir = usrDir;
|
||||
|
@ -155,33 +177,42 @@ void ExportSchedule(List<String> storeSchedule)
|
|||
if (!string.IsNullOrEmpty(usrFileName))
|
||||
outputFile = usrFileName;
|
||||
|
||||
if (usrList.Length > 0)
|
||||
defaultTopics = usrList;
|
||||
// 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);
|
||||
filePath = Path.Combine(outputDir, outputFile!);
|
||||
}
|
||||
|
||||
topic = NewTopic(defaultTopics.ToList());
|
||||
// Set new topic
|
||||
topics = config.Topics.ToList();
|
||||
chosenTopic = NewTopic(topics);
|
||||
|
||||
// If the file already exists, assume a previous schedule was written
|
||||
if (File.Exists(filePath))
|
||||
// Write to file.
|
||||
JsonWriterOptions options = new()
|
||||
{
|
||||
if (UserChoice("Add to existing file?"))
|
||||
appendSchedule = true;
|
||||
Indented = true
|
||||
};
|
||||
|
||||
// Write to file.
|
||||
using (var outputFile = new StreamWriter(filePath, appendSchedule))
|
||||
{
|
||||
outputFile.WriteLine($" === {topic} ===");
|
||||
foreach (var line in storeSchedule)
|
||||
outputFile.WriteLine(line);
|
||||
}
|
||||
}
|
||||
var jsonList = JsonSerializer.Deserialize<List<Schedule>>(filePath)
|
||||
?? new List<Schedule>();
|
||||
|
||||
// Clear list from memory before exit
|
||||
jsonList.Add(new Schedule()
|
||||
{
|
||||
Topic = chosenTopic,
|
||||
Times = storeSchedule,
|
||||
});
|
||||
var jsonString = JsonSerializer.Serialize(jsonList);
|
||||
Console.WriteLine(jsonString);
|
||||
// File.WriteAllText(filePath, jsonString);
|
||||
Console.WriteLine($"{Environment.NewLine}Written to: {filePath}");
|
||||
|
||||
// Clear list from memory
|
||||
storeSchedule.Clear();
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -193,13 +224,14 @@ void PrintSchedule(bool isRestart = false)
|
|||
var storeSchedule = new List<String>();
|
||||
var scheduledTimes = GenerateSchedule();
|
||||
|
||||
// Clear the screen on restart
|
||||
if (isRestart)
|
||||
Console.Clear();
|
||||
|
||||
Console.WriteLine("=== Publish Times ===");
|
||||
foreach (var time in scheduledTimes)
|
||||
{
|
||||
var articleTime = $"Article {scheduledTimes.IndexOf(time) + 1} Scheduled at: {ConvertTo12Hour(time)}";
|
||||
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
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
# Publish Times
|
||||
|
||||
This is a very simple console application that generates a list of times to publish news articles within a randomized 2-3 hour delay while avoiding time conflicts within a 30-minute window.
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
## 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.
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
|
@ -14,6 +16,8 @@ An optional ``config.toml`` file allows for further customization of file name,
|
|||
|
||||
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.
|
||||
|
||||
This tool was originally intended with a simple purpose: suggest some publishing times. However, when customable topics were added, it became more versatile. It can be used with anything that can be scheduled to publish, from news, art, or anything else.
|
||||
|
||||
## License
|
||||
|
||||
I hereby waive this project under the public domain - see [UNLICENSE](UNLICENSE) for details.
|
||||
|
|
9
Schedule.cs
Normal file
9
Schedule.cs
Normal file
|
@ -0,0 +1,9 @@
|
|||
|
||||
public class Schedule
|
||||
{
|
||||
[JsonPropertyName("topic")]
|
||||
public string Topic { get; set; } = "";
|
||||
|
||||
[JsonPropertyName("times")]
|
||||
public IList<string> Times { get; set; } = new List<string>();
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
path = "/home/tonytins/Documents/"
|
||||
file = "newscycle.txt"
|
||||
file = "newscycle.json"
|
||||
topics = [
|
||||
"Games",
|
||||
"News",
|
||||
|
|
Loading…
Add table
Reference in a new issue