diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index f27cadf..b99baac 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -22,18 +22,18 @@ This document provides essential context for AI agents working with URLNotesGrab ```powershell dotnet build dotnet run # Process all files in input directory -dotnet run -- -parse [blogname] # Process specific blog -dotnet run -- -test [blogname] [postID] # Test API for specific post +dotnet run -- --parse [blogname] # Process specific blog +dotnet run -- --test [blogname] [postID] # Test API for specific post ``` ### Command-Line Interface -- `-parse [blogname]`: Parse text files for specific blog -- `-test [blogname] [postID]`: Test API note collection -- `-posts`: Export post blogs to file -- `-blogs`: Export blog list to file -- `-collect`: Collect notes for all posts in DB -- `-blogsR`: Export reply blogs to file -- `-blogsO [start] [stop]`: Export blogs within range +- `--parse [blogname]`: Parse text files for specific blog +- `--test [blogname] [postID]`: Test API note collection +- `--posts`: Export post blogs to file +- `--blogs`: Export blog list to file +- `--collect`: Collect notes for all posts in DB +- `--blogsR`: Export reply blogs to file +- `--blogsO [start] [stop]`: Export blogs within range ## Project Conventions diff --git a/URLNotesGrabberCORE/Program.cs b/URLNotesGrabberCORE/Program.cs index 9b24be2..1604dd8 100644 --- a/URLNotesGrabberCORE/Program.cs +++ b/URLNotesGrabberCORE/Program.cs @@ -55,31 +55,27 @@ namespace URLNotesGrabberCORE break; } - if (string.Equals(args[i], "-force", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[i], "--force", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(args[i], "--force", StringComparison.OrdinalIgnoreCase)) { forceIgnoreCooldown = true; continue; } - if (string.Equals(args[i], "-api3", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[i], "--api3", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(args[i], "--api3", StringComparison.OrdinalIgnoreCase)) { apiSectionName = "TumblrApi3"; apiExplicitlySet = true; continue; } - if (string.Equals(args[i], "-api4", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[i], "--api4", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(args[i], "--api4", StringComparison.OrdinalIgnoreCase)) { apiSectionName = "TumblrApi4"; apiExplicitlySet = true; continue; } - if (string.Equals(args[i], "-api", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[i], "--api", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(args[i], "--api", StringComparison.OrdinalIgnoreCase)) { if (i + 1 < args.Length && !string.IsNullOrWhiteSpace(args[i + 1])) { @@ -89,13 +85,12 @@ namespace URLNotesGrabberCORE } else { - Console.WriteLine("--Missing API section after -api/--api. Using default TumblrApi.--"); + Console.WriteLine("--Missing API section after --api. Using default TumblrApi.--"); } continue; } - if (string.Equals(args[i], "-start", StringComparison.OrdinalIgnoreCase) || - string.Equals(args[i], "--start", StringComparison.OrdinalIgnoreCase)) + if (string.Equals(args[i], "--start", StringComparison.OrdinalIgnoreCase)) { if (i + 1 < args.Length && !string.IsNullOrWhiteSpace(args[i + 1])) { @@ -104,7 +99,7 @@ namespace URLNotesGrabberCORE } else { - Console.WriteLine("--Missing blog name after -start/--start. Ignoring.--"); + Console.WriteLine("--Missing blog name after --start. Ignoring.--"); } continue; } @@ -179,7 +174,7 @@ namespace URLNotesGrabberCORE Console.WriteLine(System.Reflection.Assembly.GetExecutingAssembly().GetName().Version?.ToString() ?? "unknown"); break; - case "-parse": + case "--parse": string blogNameToParse = args[1]; int postsAdded = 0; try @@ -194,23 +189,23 @@ namespace URLNotesGrabberCORE Console.WriteLine($"Total posts added: {postsAdded}"); break; - case "-test": + case "--test": Console.WriteLine("Test command not implemented"); break; - case "-post": + case "--post": TraverseDirectoryForCorruption(settings.GetValue("PathInput"), settings.GetValue("PathOutputBlogs"), contains); break; - case "-posts": //write post's blogs to file + case "--posts": //write post's blogs to file WritePostBlogsToFile(settings.GetValue("PathOutputPosts")); break; - case "-blogs": //write blogs to file + case "--blogs": //write blogs to file WriteBlogsToFile(settings.GetValue("PathOutputBlogs")); break; - case "-collect": //collect notes from all posts + case "--collect": //collect notes from all posts bool withoutNotesOnly = true; DateTime? beforeDate = DateTime.Now; bool explicitDateSupplied = false; @@ -281,11 +276,11 @@ namespace URLNotesGrabberCORE CollectNotes(settings.GetValue("PathOutput"), withoutNotesOnly, beforeDate, managedCollectRun).GetAwaiter().GetResult(); break; - case "-blogsR": //collect notes from all posts + case "--blogsR": //collect notes from all posts WriteBlogsToFile(settings.GetValue("PathOutputBlogs"), true); break; - case "-blogsO": //collect notes from all posts + case "--blogsO": //collect notes from all posts int from = 1, to = 999999, top = 100; if (args[1] is not null && args[2] is not null && args[3] is not null) @@ -302,7 +297,7 @@ namespace URLNotesGrabberCORE WriteBlogsToFile(settings.GetValue("PathOutputBlogs"), false, from, to, top); break; - case "-bop": //collect notes from all posts + case "--bop": //collect notes from all posts from = 1; to = 999999; top = 100; if (args[1] is not null && args[2] is not null && args[3] is not null) @@ -319,54 +314,54 @@ namespace URLNotesGrabberCORE WriteBlogsToFileAll(settings.GetValue("PathOutputBlogs"), false, from, to, top); break; - case "-replies": //update reply text + case "--replies": //update reply text CollectMissingReplyText().GetAwaiter().GetResult(); break; - case "-likes": + case "--likes": string likeBlog = args.Length > 1 ? args[1] : null; int cooldownDays = settings.GetValue("LikesRefreshCooldownDays", 7); CollectLikes(likeBlog, contains, cooldownDays, forceIgnoreCooldown).GetAwaiter().GetResult(); break; - case "-urldump": + case "--urldump": DumpUrls(settings.GetValue("PathOutputUrls")); break; - case "-ingest": + case "--ingest": exitCode = IngestMode.Run(config, args.Skip(1).ToArray()); break; - case "-output": + case "--output": exitCode = OutputMode.Run(config); break; - case "-revert": + case "--revert": exitCode = RevertMode.Run(config, args.Length > 1 ? args[1] : null); break; - case "-correct": + case "--correct": { - bool applyChanges = args.Skip(1).Any(a => string.Equals(a, "-apply", StringComparison.OrdinalIgnoreCase) || string.Equals(a, "--apply", StringComparison.OrdinalIgnoreCase)); + bool applyChanges = args.Skip(1).Any(a => string.Equals(a, "--apply", StringComparison.OrdinalIgnoreCase)); var correctArgs = args.Skip(1) - .Where(a => !string.Equals(a, "-apply", StringComparison.OrdinalIgnoreCase) && !string.Equals(a, "--apply", StringComparison.OrdinalIgnoreCase)) + .Where(a => !string.Equals(a, "--apply", StringComparison.OrdinalIgnoreCase)) .ToArray(); exitCode = CorrectMode.Run(config, correctArgs, applyChanges); break; } - case "-updatepaths": + case "--updatepaths": { string rootPath = args.Length > 1 ? args[1] : (settings.GetValue("PathTTRoot") ?? settings.GetValue("PathInput") ?? string.Empty); exitCode = UpdateBlogPathsRunner.Run(rootPath); break; } - case "-importposts": + case "--importposts": { if (args.Length < 2) { - Console.WriteLine("Usage: -importposts "); + Console.WriteLine("Usage: --importposts "); exitCode = 2; break; } @@ -398,53 +393,53 @@ namespace URLNotesGrabberCORE Console.WriteLine("--\t End of options: treat every following token as a literal operand"); - Console.WriteLine("-parse\t Parse .txt files with specified blogname"); + Console.WriteLine("--parse\t Parse .txt files with specified blogname"); - Console.WriteLine("-test\t Calls API for given blogname and postID"); + Console.WriteLine("--test\t Calls API for given blogname and postID"); - Console.WriteLine("-post\t Traverse the input directory tree checking .txt files for corruption"); + Console.WriteLine("--post\t Traverse the input directory tree checking .txt files for corruption"); - Console.WriteLine("-posts\t For each Post in DB, write blogname to file"); + Console.WriteLine("--posts\t For each Post in DB, write blogname to file"); - Console.WriteLine("-blogs\t For each Blog in DB, write blogname to file"); + Console.WriteLine("--blogs\t For each Blog in DB, write blogname to file"); - Console.WriteLine("-collect [0|1] [datetime]\t Collect Notes from API. 1=only posts without notes. 0=full re-check of all posts: a single resumable pass (interrupt & relaunch to resume; stops when complete, retrigger for a new pass). Optional datetime overrides the cutoff and runs as a one-off (bypasses resume tracking)."); + Console.WriteLine("--collect [0|1] [datetime]\t Collect Notes from API. 1=only posts without notes. 0=full re-check of all posts: a single resumable pass (interrupt & relaunch to resume; stops when complete, retrigger for a new pass). Optional datetime overrides the cutoff and runs as a one-off (bypasses resume tracking)."); - Console.WriteLine("-blogsR\t For each Note that is a REPLY, write blogname to file "); + Console.WriteLine("--blogsR\t For each Note that is a REPLY, write blogname to file "); - Console.WriteLine("-blogsO\t For each Blog in DB, write blogname to file, but limit via a passed start and stop range "); + Console.WriteLine("--blogsO\t For each Blog in DB, write blogname to file, but limit via a passed start and stop range "); - Console.WriteLine("-bop [from] [to] [top]\t Write ALL blog names to file, limited by FROM TO TOP range arguments"); + Console.WriteLine("--bop [from] [to] [top]\t Write ALL blog names to file, limited by FROM TO TOP range arguments"); - Console.WriteLine("-replies\t Fetch and update missing reply text for all replies in database"); + Console.WriteLine("--replies\t Fetch and update missing reply text for all replies in database"); - Console.WriteLine("-likes\t Fetch likes: initial backfill for new blogs, incremental refresh for blogs past cooldown. Optional blog name forces single-blog run."); + Console.WriteLine("--likes\t Fetch likes: initial backfill for new blogs, incremental refresh for blogs past cooldown. Optional blog name forces single-blog run."); - Console.WriteLine("-force\t (with -likes) Ignore cooldown and refresh every fully-backfilled blog"); + Console.WriteLine("--force\t (with --likes) Ignore cooldown and refresh every fully-backfilled blog"); - Console.WriteLine("-urldump\t Scan all posts' text columns and extract suspected URLs to configured file"); + Console.WriteLine("--urldump\t Scan all posts' text columns and extract suspected URLs to configured file"); - Console.WriteLine("-api3\t Use TumblrApi3 settings from appsettings.json"); + Console.WriteLine("--api3\t Use TumblrApi3 settings from appsettings.json"); - Console.WriteLine("-api4\t Use TumblrApi4 settings from appsettings.json"); + Console.WriteLine("--api4\t Use TumblrApi4 settings from appsettings.json"); - Console.WriteLine("-start [blogname]\t Start traversal alphabetically at this blog name"); + Console.WriteLine("--start [blogname]\t Start traversal alphabetically at this blog name"); - Console.WriteLine("-api [section]\t Use a specific API settings section from appsettings.json (e.g. TumblrApi3)"); + Console.WriteLine("--api [section]\t Use a specific API settings section from appsettings.json (e.g. TumblrApi3)"); - Console.WriteLine("-ingest [blogname]\t Ingest Tumblr .txt exports from appSettings:PathTTRoot into TL.db (all blogs, or single blog if name given)"); + Console.WriteLine("--ingest [blogname]\t Ingest Tumblr .txt exports from appSettings:PathTTRoot into TL.db (all blogs, or single blog if name given)"); - Console.WriteLine("-output\t Export posts from TL.db back to .txt files in each blog's TTFolderPath"); + Console.WriteLine("--output\t Export posts from TL.db back to .txt files in each blog's TTFolderPath"); - Console.WriteLine("-revert [blogname]\t Recursively scan the PathInput tree and restore *.bak back to *.txt (current .txt saved as next-free .bkN); optional blogname filters by path substring"); + Console.WriteLine("--revert [blogname]\t Recursively scan the PathInput tree and restore *.bak back to *.txt (current .txt saved as next-free .bkN); optional blogname filters by path substring"); - Console.WriteLine("-correct [bakPath]\t Dry-run: report multi-line field updates available from a BAK directory"); + Console.WriteLine("--correct [bakPath]\t Dry-run: report multi-line field updates available from a BAK directory"); - Console.WriteLine("-correct -apply [bakPath]\t Apply BAK-file corrections to matching posts (prompts yes/no)"); + Console.WriteLine("--correct --apply [bakPath]\t Apply BAK-file corrections to matching posts (prompts yes/no)"); - Console.WriteLine("-updatepaths [rootPath]\t Read .tumblr/.tmblrpriv metadata from \\Index and set Blogs.TTFolderPath"); + Console.WriteLine("--updatepaths [rootPath]\t Read .tumblr/.tmblrpriv metadata from \\Index and set Blogs.TTFolderPath"); - Console.WriteLine("-importposts [path-to-posts.db]\t One-time migration: copy legacy ThreeTxtFileHelper posts.db rows into TL.db"); + Console.WriteLine("--importposts [path-to-posts.db]\t One-time migration: copy legacy ThreeTxtFileHelper posts.db rows into TL.db"); Console.WriteLine(); Console.WriteLine("Exit status: 0 = success; 1 = unexpected error; 2 = usage error (unknown command or bad/missing arguments)"); diff --git a/URLNotesGrabberCORE/Properties/launchSettings.json b/URLNotesGrabberCORE/Properties/launchSettings.json index f489d4e..65035e1 100644 --- a/URLNotesGrabberCORE/Properties/launchSettings.json +++ b/URLNotesGrabberCORE/Properties/launchSettings.json @@ -2,7 +2,7 @@ "profiles": { "URLNotesGrabberCORE": { "commandName": "Project", - "commandLineArgs": "-collect 1 -api4" + "commandLineArgs": "--collect 1 --api4" } } } \ No newline at end of file