using System.Text.Json; namespace URLNotesGrabberCORE { // Port of ThreeTxtFileHelper/UpdateBlogPaths.cs. Reads .tumblr / .tmblrpriv metadata // files from a root\Index folder and populates Blogs.TTFolderPath in TL.db. // // Scan() is the reusable engine: --updatepaths wraps it as a standalone command and // --output calls it as a refresh step, because a TL.db synced between machines cannot // hold one absolute path that is correct on both. public static class UpdateBlogPathsRunner { public enum ScanOutcome { Completed, NoRootConfigured, IndexFolderMissing } public sealed class ScanResult { public ScanOutcome Outcome { get; init; } public string RootPath { get; init; } = string.Empty; public string IndexPath { get; init; } = string.Empty; public int MetadataFiles { get; init; } public int Written { get; init; } public int Unchanged { get; init; } public int NoLocation { get; init; } public int NoMatchingRow { get; init; } public int Errors { get; init; } } // verbose: log a line per metadata file. --updatepaths wants that detail; --output // only wants the counts, since a few hundred lines before the export would bury it. public static ScanResult Scan(string? rootPath, bool verbose) { if (string.IsNullOrWhiteSpace(rootPath)) return new ScanResult { Outcome = ScanOutcome.NoRootConfigured }; DataAccess.EnsureTTFileHelperColumnsExist(); string indexPath = Path.Combine(rootPath, "Index"); if (!Directory.Exists(indexPath)) { return new ScanResult { Outcome = ScanOutcome.IndexFolderMissing, RootPath = rootPath, IndexPath = indexPath }; } var blogFiles = Directory.GetFiles(indexPath, "*.tumblr") .Concat(Directory.GetFiles(indexPath, "*.tmblrpriv")) .ToList(); if (verbose) Console.WriteLine($"Found {blogFiles.Count} blog metadata files"); int updatedCount = 0; int unchangedCount = 0; int noLocationCount = 0; int noRowCount = 0; int errorCount = 0; foreach (var blogFile in blogFiles) { try { string blogName = Path.GetFileNameWithoutExtension(blogFile); string jsonContent = File.ReadAllText(blogFile); using JsonDocument doc = JsonDocument.Parse(jsonContent); JsonElement root = doc.RootElement; if (root.TryGetProperty("FileDownloadLocation", out JsonElement locationElement)) { string? fileDownloadLocation = locationElement.GetString()?.Trim(); if (!string.IsNullOrWhiteSpace(fileDownloadLocation)) { // Report the database's answer, not the fact that the file parsed. if (DataAccess.SetBlogTTFolderPath(blogName, fileDownloadLocation)) { updatedCount++; if (verbose) Console.WriteLine($"Updated {blogName}: {fileDownloadLocation}"); } else if (DataAccess.BlogExists(blogName)) { unchangedCount++; } else { noRowCount++; Console.WriteLine($"No Blogs row named '{blogName}' -- path not stored (name may differ in case)"); } } else { noLocationCount++; if (verbose) Console.WriteLine($"Empty FileDownloadLocation in {blogFile}"); } } else { noLocationCount++; if (verbose) Console.WriteLine($"No FileDownloadLocation found in {blogFile}"); } } catch (Exception ex) { errorCount++; Console.WriteLine($"Error processing {blogFile}: {ex.Message}"); } } return new ScanResult { Outcome = ScanOutcome.Completed, RootPath = rootPath, IndexPath = indexPath, MetadataFiles = blogFiles.Count, Written = updatedCount, Unchanged = unchangedCount, NoLocation = noLocationCount, NoMatchingRow = noRowCount, Errors = errorCount }; } public static int Run(string rootPath) { if (string.IsNullOrWhiteSpace(rootPath)) { Console.WriteLine("UpdateBlogPaths: rootPath is required."); return 1; } string indexPath = Path.Combine(rootPath, "Index"); Console.WriteLine($"Scanning Index folder: {indexPath}"); var result = Scan(rootPath, verbose: true); if (result.Outcome == ScanOutcome.IndexFolderMissing) { Console.WriteLine($"Index folder not found at: {result.IndexPath}"); return 1; } Console.WriteLine($"\n========== UpdateBlogPaths summary =========="); Console.WriteLine($"Metadata files: {result.MetadataFiles}"); Console.WriteLine($"TTFolderPath written: {result.Written}"); Console.WriteLine($"Already correct: {result.Unchanged}"); Console.WriteLine($"No FileDownloadLocation: {result.NoLocation}"); Console.WriteLine($"No matching blog row: {result.NoMatchingRow}"); Console.WriteLine($"Errors: {result.Errors}"); Console.WriteLine($"\nBlogs now holding a TTFolderPath: {DataAccess.CountBlogsWithTTFolderPath()}"); return result.Errors == 0 ? 0 : 2; } } }