Write index.yml.md
Helper to diff video files Move matches from directory Bug fix for DirectoryToISO Find replace instead of remove Rename Directory Amazon Immich Person PersonKeyToName PullIconsForBLM New links
This commit is contained in:
parent
299aa19d53
commit
47e6b85c21
6
.vscode/mklink.md
vendored
6
.vscode/mklink.md
vendored
@ -15,7 +15,7 @@ mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.kanbn" "D:\5-Other-Small\Kanban
|
||||
```
|
||||
|
||||
```bash
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.6.0"
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.6.0"
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.6.0"
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode" "C:\Users\phares\.vscode\extensions\ifx.type-script-helper-1.6.1"
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-oss" "C:\Users\phares\.vscode-oss\extensions\ifx.type-script-helper-1.6.1"
|
||||
mklink /J "L:\DevOps\Mesa_FI\File-Folder-Helper\.extensions-vscode-insiders" "C:\Users\phares\.vscode-insiders\extensions\ifx.type-script-helper-1.6.1"
|
||||
```
|
||||
|
@ -33,7 +33,10 @@ internal static partial class Helper20240107
|
||||
string destinationDirectory = args[3];
|
||||
logger.LogInformation(sourceDirectory);
|
||||
if (sourceDirectory == "C:/ProgramData")
|
||||
{
|
||||
sourceDirectory = destinationDirectory;
|
||||
destinationDirectory = Path.GetDirectoryName(destinationDirectory) ?? throw new NotSupportedException();
|
||||
}
|
||||
bool mapOnly = sourceDirectory.Length == 2;
|
||||
if (!Directory.Exists(destinationDirectory))
|
||||
_ = Directory.CreateDirectory(destinationDirectory);
|
||||
|
34
Day/2024-Q2/Helper-2024-05-10.cs
Normal file
34
Day/2024-Q2/Helper-2024-05-10.cs
Normal file
@ -0,0 +1,34 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240510
|
||||
{
|
||||
|
||||
internal static void PullIconsForBLM(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string fileName;
|
||||
FileInfo fileInfo;
|
||||
string searchPattern = args[4];
|
||||
string sourceDirectory = args[3];
|
||||
string root = Path.GetFullPath(args[0]);
|
||||
string createDirectory = Path.Combine(root, args[2]);
|
||||
if (!Directory.Exists(createDirectory))
|
||||
_ = Directory.CreateDirectory(createDirectory);
|
||||
string[] files = Directory.GetFiles(sourceDirectory, searchPattern, SearchOption.TopDirectoryOnly);
|
||||
foreach (string file in files)
|
||||
{
|
||||
fileName = Path.GetFileName(file);
|
||||
fileInfo = new(Path.Combine(createDirectory, fileName));
|
||||
if (fileInfo.Exists && fileInfo.LastWriteTime == new FileInfo(file).LastWriteTime)
|
||||
continue;
|
||||
File.Copy(file, fileInfo.FullName, overwrite: true);
|
||||
logger.LogInformation("<{fileName}> copied", fileName);
|
||||
}
|
||||
logger.LogWarning("What reactor is this near?");
|
||||
string? reactor = Console.ReadLine();
|
||||
if (!string.IsNullOrEmpty(reactor))
|
||||
_ = Directory.CreateDirectory(Path.Combine(sourceDirectory, Environment.MachineName, reactor));
|
||||
}
|
||||
|
||||
}
|
39
Day/2024-Q2/Helper-2024-05-13.cs
Normal file
39
Day/2024-Q2/Helper-2024-05-13.cs
Normal file
@ -0,0 +1,39 @@
|
||||
using File_Folder_Helper.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240513
|
||||
{
|
||||
|
||||
internal static void PersonKeyToName(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
Person? person;
|
||||
string directoryName;
|
||||
string checkDirectory;
|
||||
string root = Path.GetFullPath(args[0]);
|
||||
string json = File.ReadAllText(args[2]);
|
||||
Dictionary<string, Person> keyValuePairs = [];
|
||||
string[] directories = Directory.GetDirectories(root, "*", SearchOption.TopDirectoryOnly);
|
||||
Dictionary<long, Person> people = JsonSerializer.Deserialize(json, PeopleSourceGenerationContext.Default.DictionaryInt64Person) ?? throw new NullReferenceException();
|
||||
foreach (KeyValuePair<long, Person> keyValuePair in people)
|
||||
{
|
||||
if (keyValuePair.Value.Birth?.Note is null)
|
||||
continue;
|
||||
keyValuePairs.Add(keyValuePair.Value.Birth.Note, keyValuePair.Value);
|
||||
}
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
directoryName = Path.GetFileName(directory);
|
||||
if (!keyValuePairs.TryGetValue(directoryName, out person) || person.Name?.ForwardSlashFull is null)
|
||||
continue;
|
||||
checkDirectory = Path.Combine(root, $"{person.Name.ForwardSlashFull.Replace('/', '-')}{directoryName}-{person.Id}");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
continue;
|
||||
Directory.Move(directory, checkDirectory);
|
||||
logger.LogInformation("<{directory}> was moved", directory);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
334
Day/2024-Q2/Helper-2024-05-17.cs
Normal file
334
Day/2024-Q2/Helper-2024-05-17.cs
Normal file
@ -0,0 +1,334 @@
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240517
|
||||
{
|
||||
|
||||
public record ContentSignature([property: JsonPropertyName("contentSignature")] string Value,
|
||||
[property: JsonPropertyName("contentSignatureType")] string ContentSignatureType);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ContentSignature))]
|
||||
public partial class ContentSignatureGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Type([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Type))]
|
||||
public partial class TypeGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record ImageAmazon([property: JsonPropertyName("colorSpace")] string ColorSpace,
|
||||
[property: JsonPropertyName("dateTime")] DateTime DateTime,
|
||||
[property: JsonPropertyName("dateTimeDigitized")] DateTime DateTimeDigitized,
|
||||
[property: JsonPropertyName("dateTimeOriginal")] DateTime DateTimeOriginal,
|
||||
[property: JsonPropertyName("exposureMode")] string ExposureMode,
|
||||
[property: JsonPropertyName("exposureProgram")] string ExposureProgram,
|
||||
[property: JsonPropertyName("exposureTime")] string ExposureTime,
|
||||
[property: JsonPropertyName("flash")] string Flash,
|
||||
[property: JsonPropertyName("focalLength")] string FocalLength,
|
||||
[property: JsonPropertyName("height")] int Height,
|
||||
[property: JsonPropertyName("make")] string Make,
|
||||
[property: JsonPropertyName("meteringMode")] string MeteringMode,
|
||||
[property: JsonPropertyName("model")] string Model,
|
||||
[property: JsonPropertyName("orientation")] string Orientation,
|
||||
[property: JsonPropertyName("resolutionUnit")] string ResolutionUnit,
|
||||
[property: JsonPropertyName("sensingMethod")] string SensingMethod,
|
||||
[property: JsonPropertyName("sharpness")] string Sharpness,
|
||||
[property: JsonPropertyName("software")] string Software,
|
||||
[property: JsonPropertyName("subSecTime")] string SubSecTime,
|
||||
[property: JsonPropertyName("subSecTimeDigitized")] string SubSecTimeDigitized,
|
||||
[property: JsonPropertyName("subSecTimeOriginal")] string SubSecTimeOriginal,
|
||||
[property: JsonPropertyName("whiteBalance")] string WhiteBalance,
|
||||
[property: JsonPropertyName("width")] int Width,
|
||||
[property: JsonPropertyName("apertureValue")] string ApertureValue);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ImageAmazon))]
|
||||
public partial class ImageAmazonGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record ContentProperties([property: JsonPropertyName("contentDate")] DateTime ContentDate,
|
||||
[property: JsonPropertyName("contentSignatures")] IReadOnlyList<ContentSignature> ContentSignatures,
|
||||
[property: JsonPropertyName("contentType")] string ContentType,
|
||||
[property: JsonPropertyName("extension")] string Extension,
|
||||
[property: JsonPropertyName("image")] ImageAmazon Image,
|
||||
[property: JsonPropertyName("md5")] string Md5,
|
||||
[property: JsonPropertyName("size")] int Size,
|
||||
[property: JsonPropertyName("version")] int Version);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ContentProperties))]
|
||||
public partial class ContentPropertiesGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record XAccntParentMap();
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(XAccntParentMap))]
|
||||
public partial class XAccntParentMapGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Datum([property: JsonPropertyName("accessRuleIds")] IReadOnlyList<object> AccessRuleIds,
|
||||
[property: JsonPropertyName("childAssetTypeInfo")] IReadOnlyList<object> ChildAssetTypeInfo,
|
||||
[property: JsonPropertyName("contentProperties")] ContentProperties ContentProperties,
|
||||
[property: JsonPropertyName("createdBy")] string CreatedBy,
|
||||
[property: JsonPropertyName("createdDate")] DateTime CreatedDate,
|
||||
[property: JsonPropertyName("eTagResponse")] string ETagResponse,
|
||||
[property: JsonPropertyName("groupPermissions")] IReadOnlyList<object> GroupPermissions,
|
||||
[property: JsonPropertyName("id")] string Id,
|
||||
[property: JsonPropertyName("isRoot")] bool IsRoot,
|
||||
[property: JsonPropertyName("isShared")] bool IsShared,
|
||||
[property: JsonPropertyName("keywords")] IReadOnlyList<object> Keywords,
|
||||
[property: JsonPropertyName("kind")] string Kind,
|
||||
[property: JsonPropertyName("labels")] IReadOnlyList<object> Labels,
|
||||
[property: JsonPropertyName("modifiedDate")] DateTime ModifiedDate,
|
||||
[property: JsonPropertyName("name")] string Name,
|
||||
[property: JsonPropertyName("ownerId")] string OwnerId,
|
||||
[property: JsonPropertyName("parentMap")] ParentMap ParentMap,
|
||||
[property: JsonPropertyName("parents")] IReadOnlyList<string> Parents,
|
||||
[property: JsonPropertyName("protectedFolder")] bool ProtectedFolder,
|
||||
[property: JsonPropertyName("restricted")] bool Restricted,
|
||||
[property: JsonPropertyName("status")] string Status,
|
||||
[property: JsonPropertyName("subKinds")] IReadOnlyList<object> SubKinds,
|
||||
[property: JsonPropertyName("transforms")] IReadOnlyList<string> Transforms,
|
||||
[property: JsonPropertyName("version")] int Version,
|
||||
[property: JsonPropertyName("xAccntParentMap")] XAccntParentMap XAccntParentMap,
|
||||
[property: JsonPropertyName("xAccntParents")] IReadOnlyList<object> XAccntParents,
|
||||
[property: JsonPropertyName("match")] bool? Match);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Datum))]
|
||||
public partial class DatumGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Dictionary<string, Datum>))]
|
||||
public partial class DictionaryDatumGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record LocationAmazon([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(LocationAmazon))]
|
||||
public partial class LocationAmazonGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record LocationInfo([property: JsonPropertyName("city")] string City,
|
||||
[property: JsonPropertyName("country")] string Country,
|
||||
[property: JsonPropertyName("countryIso3Code")] string CountryIso3Code,
|
||||
[property: JsonPropertyName("state")] string State,
|
||||
[property: JsonPropertyName("stateCode")] string StateCode);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(LocationInfo))]
|
||||
public partial class LocationInfoGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record SearchData([property: JsonPropertyName("clusterName")] string ClusterName,
|
||||
[property: JsonPropertyName("locationId")] string LocationId,
|
||||
[property: JsonPropertyName("locationInfo")] LocationInfo LocationInfo,
|
||||
[property: JsonPropertyName("thingId")] string ThingId);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(SearchData))]
|
||||
public partial class SearchDataGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record AllPerson([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(AllPerson))]
|
||||
public partial class AllPersonGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record PersonAmazon([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(PersonAmazon))]
|
||||
public partial class PersonAmazonGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record ClusterId([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ClusterId))]
|
||||
public partial class ClusterIdGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Thing([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Thing))]
|
||||
public partial class ThingGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record Time([property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("match")] string Match,
|
||||
[property: JsonPropertyName("searchData")] SearchData SearchData);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Time))]
|
||||
public partial class TimeGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record ParentMap([property: JsonPropertyName("FOLDER")] IReadOnlyList<string> FOLDER);
|
||||
|
||||
public record Aggregations([property: JsonPropertyName("allPeople")] IReadOnlyList<AllPerson> AllPeople,
|
||||
[property: JsonPropertyName("clusterId")] IReadOnlyList<ClusterId> ClusterId,
|
||||
[property: JsonPropertyName("location")] IReadOnlyList<LocationAmazon> Location,
|
||||
[property: JsonPropertyName("people")] IReadOnlyList<PersonAmazon> People,
|
||||
[property: JsonPropertyName("things")] IReadOnlyList<Thing> Things,
|
||||
[property: JsonPropertyName("time")] IReadOnlyList<Time> Time,
|
||||
[property: JsonPropertyName("type")] IReadOnlyList<Type> Type);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Aggregations))]
|
||||
public partial class AggregationsGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(ParentMap))]
|
||||
public partial class ParentMapGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
public record RootAmazon([property: JsonPropertyName("aggregations")] Aggregations Aggregations,
|
||||
[property: JsonPropertyName("count")] int Count,
|
||||
[property: JsonPropertyName("data")] IReadOnlyList<Datum> Data);
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(RootAmazon))]
|
||||
public partial class RootAmazonGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static ReadOnlyCollection<(string, string)> GetAggregationLines(string harFile)
|
||||
{
|
||||
List<(string, string)> results = [];
|
||||
if (!File.Exists(harFile))
|
||||
throw new Exception();
|
||||
string lastUrl = string.Empty;
|
||||
string text = "\"text\": \"{";
|
||||
string[] lines = File.ReadAllLines(harFile);
|
||||
foreach (string line in lines)
|
||||
{
|
||||
if (line.Contains("\"url\": \""))
|
||||
lastUrl = line;
|
||||
if (!line.Contains(text))
|
||||
continue;
|
||||
if (!line.Contains("aggregations"))
|
||||
continue;
|
||||
if (lastUrl.Contains("search?asset=NONE"))
|
||||
continue;
|
||||
results.Add(new(lastUrl, line.Trim()[(text.Length - 1)..^1].Replace("\\\"", "\"")));
|
||||
lastUrl = string.Empty;
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static void SaveAmazon(IReadOnlyList<Datum> data, string personIdFile)
|
||||
{
|
||||
string json;
|
||||
Dictionary<string, Datum> keyValuePairs = [];
|
||||
foreach (Datum datum in data)
|
||||
_ = keyValuePairs.TryAdd(datum.Name.Split('.')[0], datum);
|
||||
json = JsonSerializer.Serialize(keyValuePairs, DictionaryDatumGenerationContext.Default.DictionaryStringDatum);
|
||||
File.WriteAllText(personIdFile, json);
|
||||
}
|
||||
|
||||
private static void SaveAmazon(string destination, string harFile)
|
||||
{
|
||||
string offset;
|
||||
string personId;
|
||||
RootAmazon amazon;
|
||||
string? personName;
|
||||
string personIdFile;
|
||||
string personDirectory;
|
||||
PersonAmazon personAmazon;
|
||||
Dictionary<string, string> keyValuePairs = [];
|
||||
ReadOnlyCollection<(string Url, string AggregationLine)> aggregationLines = GetAggregationLines(harFile);
|
||||
foreach ((string url, string aggregationLine) in aggregationLines)
|
||||
{
|
||||
if (aggregationLine.Contains(",\"category\":\"allPeople\"}"))
|
||||
continue;
|
||||
amazon = JsonSerializer.Deserialize(aggregationLine, RootAmazonGenerationContext.Default.RootAmazon) ?? throw new Exception();
|
||||
if (amazon.Aggregations?.People is null || amazon.Aggregations.People.Count < 1)
|
||||
continue;
|
||||
personAmazon = amazon.Aggregations.People[0];
|
||||
if (!url.Contains(personAmazon.Match))
|
||||
continue;
|
||||
personDirectory = Path.Combine(destination, personAmazon.SearchData.ClusterName);
|
||||
_ = Directory.CreateDirectory(personDirectory);
|
||||
personIdFile = Path.Combine(personDirectory, $"000) {personAmazon.Match}.json");
|
||||
_ = keyValuePairs.TryAdd(personAmazon.Match, personAmazon.SearchData.ClusterName);
|
||||
SaveAmazon(amazon.Data, personIdFile);
|
||||
}
|
||||
foreach ((string url, string aggregationLine) in aggregationLines)
|
||||
{
|
||||
if (aggregationLine.Contains(",\"category\":\"allPeople\"}"))
|
||||
continue;
|
||||
amazon = JsonSerializer.Deserialize(aggregationLine, RootAmazonGenerationContext.Default.RootAmazon) ?? throw new Exception();
|
||||
if (amazon.Aggregations?.People is not null && amazon.Aggregations.People.Count > 0)
|
||||
continue;
|
||||
if (!url.Contains("offset="))
|
||||
continue;
|
||||
offset = url.Split("offset=")[1];
|
||||
if (!url.Contains("people%3A("))
|
||||
continue;
|
||||
personId = url.Split("people%3A(")[1].Split(')')[0];
|
||||
if (!keyValuePairs.TryGetValue(personId, out personName))
|
||||
continue;
|
||||
personDirectory = Path.Combine(destination, personName);
|
||||
_ = Directory.CreateDirectory(personDirectory);
|
||||
personIdFile = Path.Combine(personDirectory, $"{offset.Split('&')[0]}) {personId}.json");
|
||||
SaveAmazon(amazon.Data, personIdFile);
|
||||
}
|
||||
}
|
||||
|
||||
internal static void SaveAmazon(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string root = Path.GetFullPath(args[0]);
|
||||
string destination = Path.GetFullPath(args[2]);
|
||||
if (string.IsNullOrEmpty(root))
|
||||
throw new NullReferenceException(nameof(root));
|
||||
string[] harFiles = Directory.GetFiles(root, "*.har", SearchOption.TopDirectoryOnly);
|
||||
foreach (string harFile in harFiles)
|
||||
SaveAmazon(destination, harFile);
|
||||
logger?.LogInformation("{harFiles} count", harFiles.Length);
|
||||
}
|
||||
|
||||
}
|
35
Day/2024-Q2/Helper-2024-05-18.cs
Normal file
35
Day/2024-Q2/Helper-2024-05-18.cs
Normal file
@ -0,0 +1,35 @@
|
||||
using File_Folder_Helper.Models;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240518
|
||||
{
|
||||
|
||||
internal static void PersonKeyToImmichImport(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string name;
|
||||
string birthDate;
|
||||
string ownerId = args[5];
|
||||
List<string> inserts = [];
|
||||
string tableName = args[3];
|
||||
string birthDateFormat = args[6];
|
||||
string[] columns = args[4].Split(',');
|
||||
string json = File.ReadAllText(args[2]);
|
||||
string root = Path.GetFullPath(args[0]);
|
||||
Dictionary<long, Person> people = JsonSerializer.Deserialize(json, PeopleSourceGenerationContext.Default.DictionaryInt64Person) ?? throw new NullReferenceException();
|
||||
foreach (KeyValuePair<long, Person> keyValuePair in people)
|
||||
{
|
||||
if (keyValuePair.Value.Birth?.Note is null || keyValuePair.Value.Name?.ForwardSlashFull is null || keyValuePair.Value.Birth?.Date is null)
|
||||
continue;
|
||||
birthDate = keyValuePair.Value.Birth.Date.Value.ToString(birthDateFormat);
|
||||
name = keyValuePair.Value.Name.ForwardSlashFull.Replace("/", string.Empty);
|
||||
inserts.Add($"insert into \"{tableName}\" (\"{string.Join("\", \"", columns)}\") values ('{ownerId}', '{name}', '{birthDate}');");
|
||||
}
|
||||
string file = Path.Combine(root, $"{DateTime.Now.Ticks}.sql");
|
||||
logger.LogInformation("<{file}> saved", file);
|
||||
File.WriteAllLines(file, inserts);
|
||||
}
|
||||
|
||||
}
|
80
Day/2024-Q2/Helper-2024-05-19.cs
Normal file
80
Day/2024-Q2/Helper-2024-05-19.cs
Normal file
@ -0,0 +1,80 @@
|
||||
using File_Folder_Helper.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240519
|
||||
{
|
||||
|
||||
private record Record(long Length, long Ticks);
|
||||
|
||||
private static ReadOnlyDictionary<string, Record> GetKeyValuePairs(string source, string[] sourceFiles)
|
||||
{
|
||||
Dictionary<string, Record> results = [];
|
||||
string key;
|
||||
Record? record;
|
||||
FileInfo fileInfo;
|
||||
int sourceLength = source.Length;
|
||||
foreach (string sourceFile in sourceFiles)
|
||||
{
|
||||
fileInfo = new(sourceFile);
|
||||
key = sourceFile[sourceLength..];
|
||||
if (results.TryGetValue(key, out record))
|
||||
throw new NotSupportedException();
|
||||
results.Add(key, new(fileInfo.Length, fileInfo.LastWriteTime.Ticks));
|
||||
}
|
||||
return new(results);
|
||||
}
|
||||
|
||||
internal static void FindReplaceDirectoryName(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
string checkDirectory;
|
||||
string replaceText = args[3];
|
||||
string[] findTexts = args[2].Split(',');
|
||||
string root = Path.GetFullPath(args[0]);
|
||||
string[] directories = Directory.GetDirectories(root, "*", SearchOption.TopDirectoryOnly);
|
||||
foreach (string directory in directories)
|
||||
{
|
||||
checkDirectory = directory;
|
||||
foreach (string findText in findTexts)
|
||||
checkDirectory = checkDirectory.Replace(findText, replaceText);
|
||||
if (checkDirectory == directory)
|
||||
continue;
|
||||
if (Directory.Exists(checkDirectory))
|
||||
continue;
|
||||
logger.LogInformation("<{directory}> to <{checkDirectory}>", directory, checkDirectory);
|
||||
Directory.Move(directory, checkDirectory);
|
||||
}
|
||||
string key;
|
||||
Record? record;
|
||||
string checkFile;
|
||||
FileInfo fileInfo;
|
||||
string target = Path.GetFullPath(args[6]);
|
||||
string source = Path.GetFullPath(args[4]);
|
||||
string compare = Path.GetFullPath(args[5]);
|
||||
string[] sourceFiles = Directory.GetFiles(source, "*", SearchOption.AllDirectories);
|
||||
ReadOnlyDictionary<string, Record> keyValuePairs = GetKeyValuePairs(source, sourceFiles);
|
||||
string[] compareFiles = Directory.GetFiles(compare, "*", SearchOption.AllDirectories);
|
||||
int compareLength = compare.Length;
|
||||
foreach (string compareFile in compareFiles)
|
||||
{
|
||||
fileInfo = new(compareFile);
|
||||
key = compareFile[compareLength..];
|
||||
if (!keyValuePairs.TryGetValue(key, out record))
|
||||
continue;
|
||||
if (fileInfo.Length != record.Length || fileInfo.LastWriteTime.Ticks != record.Ticks)
|
||||
continue;
|
||||
checkFile = $"{target}{key}";
|
||||
checkDirectory = Path.GetDirectoryName(checkFile) ?? throw new NotSupportedException();
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
logger.LogInformation("<{compareFile}> to <{checkFile}>", compareFile, checkFile);
|
||||
File.Move(compareFile, checkFile);
|
||||
}
|
||||
HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, compare);
|
||||
}
|
||||
|
||||
}
|
160
Day/2024-Q2/Helper-2024-05-20.cs
Normal file
160
Day/2024-Q2/Helper-2024-05-20.cs
Normal file
@ -0,0 +1,160 @@
|
||||
using File_Folder_Helper.Helpers;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace File_Folder_Helper.Day;
|
||||
|
||||
internal static partial class Helper20240520
|
||||
{
|
||||
|
||||
private record RecordA(string Directory, string Extension, string SourceFile, Identifier Identifier);
|
||||
|
||||
private record RecordB(ReadOnlyDictionary<int, Identifier> IdTo, ReadOnlyDictionary<long, Identifier> LengthTo, ReadOnlyDictionary<string, Identifier> PaddedTo);
|
||||
|
||||
internal sealed record Identifier(int Id, long Length, string PaddedId, long Ticks)
|
||||
{
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string result = JsonSerializer.Serialize(this, IdentifierSourceGenerationContext.Default.Identifier);
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier))]
|
||||
internal partial class IdentifierSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
[JsonSourceGenerationOptions(WriteIndented = true)]
|
||||
[JsonSerializable(typeof(Identifier[]))]
|
||||
internal partial class IdentifierCollectionSourceGenerationContext : JsonSerializerContext
|
||||
{
|
||||
}
|
||||
|
||||
private static RecordB GetRecordB(string jsonFile)
|
||||
{
|
||||
RecordB result;
|
||||
Dictionary<int, Identifier> idTo = [];
|
||||
Dictionary<long, Identifier> lengthTo = [];
|
||||
Dictionary<string, Identifier> paddedTo = [];
|
||||
string? json = !File.Exists(jsonFile) ? null : File.ReadAllText(jsonFile);
|
||||
Identifier[]? identifiers = json is null ? null : JsonSerializer.Deserialize(json, IdentifierCollectionSourceGenerationContext.Default.IdentifierArray);
|
||||
if (identifiers is null && !string.IsNullOrEmpty(jsonFile))
|
||||
throw new Exception($"Invalid {nameof(jsonFile)}");
|
||||
if (identifiers is not null)
|
||||
{
|
||||
foreach (Identifier identifier in identifiers)
|
||||
{
|
||||
idTo.Add(identifier.Id, identifier);
|
||||
paddedTo.Add(identifier.PaddedId, identifier);
|
||||
if (lengthTo.ContainsKey(identifier.Length))
|
||||
{
|
||||
_ = lengthTo.Remove(identifier.Length);
|
||||
continue;
|
||||
}
|
||||
lengthTo.Add(identifier.Length, identifier);
|
||||
}
|
||||
}
|
||||
result = new(new(idTo), new(lengthTo), new(paddedTo));
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static void IdentifierRename(ILogger<Worker> logger, List<string> args)
|
||||
{
|
||||
int id;
|
||||
string key;
|
||||
RecordA recordA;
|
||||
string checkFile;
|
||||
FileInfo fileInfo;
|
||||
string checkDirectory;
|
||||
Identifier? identifier;
|
||||
string offset = args[5];
|
||||
string option = args[7];
|
||||
string jsonFile = args[4];
|
||||
string fileNameWithoutExtension;
|
||||
List<RecordA> recordACollection = [];
|
||||
RecordB recordB = GetRecordB(jsonFile);
|
||||
string deterministicHashCode = args[3];
|
||||
string source = Path.GetFullPath(args[0]);
|
||||
int intMinValueLength = int.Parse(args[2]);
|
||||
string destination = Path.GetFullPath(args[6]);
|
||||
bool isOffsetDeterministicHashCode = offset == deterministicHashCode;
|
||||
string[] sourceFiles = Directory.GetFiles(source, "*", SearchOption.AllDirectories);
|
||||
logger.LogInformation("Found {files}(s)", sourceFiles.Length);
|
||||
int sourceLength = source.Length;
|
||||
foreach (string sourceFile in sourceFiles)
|
||||
{
|
||||
fileInfo = new(sourceFile);
|
||||
fileNameWithoutExtension = Path.GetFileNameWithoutExtension(fileInfo.FullName);
|
||||
if (fileInfo.Directory is null)
|
||||
throw new NotSupportedException();
|
||||
if (option == "Padded")
|
||||
{
|
||||
if (fileNameWithoutExtension.Length < intMinValueLength)
|
||||
continue;
|
||||
key = fileNameWithoutExtension;
|
||||
if (recordB.PaddedTo.TryGetValue(key, out identifier))
|
||||
{
|
||||
recordACollection.Add(new($"{destination}{fileInfo.Directory.FullName[sourceLength..]}", fileInfo.Extension, fileInfo.FullName, identifier));
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (option == "Length")
|
||||
{
|
||||
if (recordB.LengthTo.TryGetValue(fileInfo.Length, out identifier))
|
||||
{
|
||||
checkDirectory = $"{destination}{fileInfo.Directory.FullName[sourceLength..]}";
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, $"{identifier.PaddedId}{fileInfo.Extension}");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Copy(fileInfo.FullName, checkFile);
|
||||
logger.LogInformation("<{fileInfo.FullName}> was moved to <{checkFile}>", fileInfo.FullName, checkFile);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (option == "Id")
|
||||
{
|
||||
if (int.TryParse(fileNameWithoutExtension, out id))
|
||||
{
|
||||
if (recordB.IdTo.TryGetValue(id, out identifier))
|
||||
{
|
||||
checkDirectory = $"{destination}{fileInfo.Directory.FullName[sourceLength..]}";
|
||||
if (!Directory.Exists(checkDirectory))
|
||||
_ = Directory.CreateDirectory(checkDirectory);
|
||||
checkFile = Path.Combine(checkDirectory, $"{identifier.PaddedId}{fileInfo.Extension}");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(fileInfo.FullName, checkFile);
|
||||
logger.LogInformation("<{fileInfo.FullName}> was moved to <{checkFile}>", fileInfo.FullName, checkFile);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (option == "Padded")
|
||||
{
|
||||
if (!isOffsetDeterministicHashCode)
|
||||
recordACollection = (from l in recordACollection orderby l.Identifier.Ticks select l).ToList();
|
||||
for (int i = 0; i < recordACollection.Count; i++)
|
||||
{
|
||||
recordA = recordACollection[i];
|
||||
if (!Directory.Exists(recordA.Directory))
|
||||
_ = Directory.CreateDirectory(recordA.Directory);
|
||||
checkFile = Path.Combine(recordA.Directory, isOffsetDeterministicHashCode ? $"{recordA.Identifier.PaddedId}{recordA.Extension}" : $"{offset + i}{recordA.Identifier.PaddedId}{recordA.Extension}");
|
||||
if (File.Exists(checkFile))
|
||||
continue;
|
||||
File.Move(recordA.SourceFile, checkFile);
|
||||
logger.LogInformation("<{recordA.SourceFile}> was moved to <{checkFile}>", recordA.SourceFile, checkFile);
|
||||
}
|
||||
}
|
||||
HelperDeleteEmptyDirectories.DeleteEmptyDirectories(logger, source);
|
||||
}
|
||||
|
||||
}
|
@ -60,6 +60,18 @@ internal static class HelperDay
|
||||
Day.Helper20240427.Immich(appSettings, logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-04-29")
|
||||
Day.Helper20240429.GitConfigCleanUp(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-10")
|
||||
Day.Helper20240510.PullIconsForBLM(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-13")
|
||||
Day.Helper20240513.PersonKeyToName(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-17")
|
||||
Day.Helper20240517.SaveAmazon(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-18")
|
||||
Day.Helper20240518.PersonKeyToImmichImport(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-19")
|
||||
Day.Helper20240519.FindReplaceDirectoryName(logger, args);
|
||||
else if (args[1] == "Day-Helper-2024-05-20")
|
||||
Day.Helper20240520.IdentifierRename(logger, args);
|
||||
else
|
||||
throw new Exception(appSettings.Company);
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Nullable>enable</Nullable>
|
||||
<OutputType>Exe</OutputType>
|
||||
@ -16,9 +16,9 @@
|
||||
<PackageReference Include="DiscUtils.Iso9660" Version="0.16.13" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="8.0.0" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.4" />
|
||||
<PackageReference Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="8.0.6" />
|
||||
<PackageReference Include="System.Text.Json" Version="8.0.3" />
|
||||
<PackageReference Include="TextCopy" Version="6.2.1" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.1.0" />
|
||||
<PackageReference Include="WindowsShortcutFactory" Version="1.2.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -33,7 +33,7 @@ internal static partial class HelperKanbanMetadata
|
||||
}
|
||||
|
||||
private static void TestParamCases()
|
||||
{
|
||||
{ // cSpell:disable
|
||||
if (GetParamCase("PascalCase") != "pascal-case")
|
||||
throw new Exception("PascalCase");
|
||||
if (GetParamCase("camelCase") != "camel-case")
|
||||
@ -68,7 +68,7 @@ internal static partial class HelperKanbanMetadata
|
||||
throw new Exception("יקספּערמענאַל פּרובירן");
|
||||
if (GetParamCase("я надеюсь, что это сработает") != "я-надеюсь-что-это-сработает")
|
||||
throw new Exception("я надеюсь, что это сработает");
|
||||
}
|
||||
} // cSpell:restore
|
||||
|
||||
private static List<Record> GetCollectionFromIndex(string sourceDirectory, ReadOnlyCollection<string> lines)
|
||||
{
|
||||
@ -105,38 +105,94 @@ internal static partial class HelperKanbanMetadata
|
||||
private static void WriteKanbanBoardFile(string directory, List<Record> records, string h1)
|
||||
{
|
||||
string? last = null;
|
||||
List<string> lines = [h1];
|
||||
List<string> results = [h1];
|
||||
foreach (Record record in records)
|
||||
{
|
||||
if (last is null || record.Group != last)
|
||||
{
|
||||
lines.Add(string.Empty);
|
||||
lines.Add($"## {record.Group}");
|
||||
lines.Add(string.Empty);
|
||||
results.Add(string.Empty);
|
||||
results.Add($"## {record.Group}");
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
lines.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}");
|
||||
results.Add($"- [ ] {Path.GetFileNameWithoutExtension(record.FileInfo.Name)}");
|
||||
last = record.Group;
|
||||
}
|
||||
File.WriteAllLines(Path.Combine(directory, "index.knb.md"), lines);
|
||||
string file = Path.Combine(directory, "index.knb.md");
|
||||
if (File.Exists(file))
|
||||
{
|
||||
string allText = File.ReadAllText(file);
|
||||
if (string.Join(Environment.NewLine, results) == allText)
|
||||
results.Clear();
|
||||
}
|
||||
if (results.Count > 0)
|
||||
File.WriteAllText(file, string.Join(Environment.NewLine, results));
|
||||
}
|
||||
|
||||
internal static void SetMetadata(string sourceDirectory, string indexFile)
|
||||
private static void WriteKanbanBoardYmlView(string directory, List<Record> records, string kanbanIndexH1)
|
||||
{
|
||||
List<string> results = [kanbanIndexH1, string.Empty];
|
||||
string h1;
|
||||
TimeSpan timeSpan;
|
||||
List<string> lines;
|
||||
LineNumber lineNumber;
|
||||
Record[] sorted = (from l in records orderby l.GroupCount, l.FileInfo.LastWriteTime descending select l).ToArray();
|
||||
foreach (Record record in sorted)
|
||||
{
|
||||
if (record.ItemLineNumber == 0)
|
||||
throw new NotSupportedException();
|
||||
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(record.FileInfo);
|
||||
if (lines.Count == 0)
|
||||
continue;
|
||||
timeSpan = new(record.FileInfo.LastWriteTime.Ticks - record.FileInfo.CreationTime.Ticks);
|
||||
h1 = lineNumber.H1 is null ? Path.GetFileNameWithoutExtension(record.FileInfo.Name) : lines[lineNumber.H1.Value];
|
||||
results.Add($"#{h1}");
|
||||
results.Add(string.Empty);
|
||||
results.Add("```yaml");
|
||||
results.Add($"CreationTime: {record.FileInfo.CreationTime:yyyy-MM-dd}");
|
||||
results.Add($"LastWriteTime: {record.FileInfo.LastWriteTime:yyyy-MM-dd}");
|
||||
results.Add($"TotalDays: {Math.Round(timeSpan.TotalDays, 2)}");
|
||||
if (lineNumber.FrontMatterYamlEnd is not null && lines.Count >= lineNumber.FrontMatterYamlEnd.Value)
|
||||
{
|
||||
for (int i = 0; i < lineNumber.FrontMatterYamlEnd; i++)
|
||||
{
|
||||
if (lines[i] == "---")
|
||||
continue;
|
||||
results.Add(lines[i]);
|
||||
}
|
||||
}
|
||||
results.Add($"status: \"{record.GroupCount}-{record.Group}\"");
|
||||
results.Add("```");
|
||||
results.Add(string.Empty);
|
||||
}
|
||||
string file = Path.Combine(directory, "index.yml.md");
|
||||
if (File.Exists(file))
|
||||
{
|
||||
string allText = File.ReadAllText(file);
|
||||
if (string.Join(Environment.NewLine, results) == allText)
|
||||
results.Clear();
|
||||
}
|
||||
if (results.Count > 0)
|
||||
File.WriteAllText(file, string.Join(Environment.NewLine, results));
|
||||
}
|
||||
|
||||
internal static void SetMetadata(string sourceDirectory, ReadOnlyCollection<string> kanbanIndexFileLines, LineNumber kanbanIndexFileLineNumber, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
bool? match;
|
||||
bool gitCheck;
|
||||
string? paramCase;
|
||||
string statusLine;
|
||||
List<string> lines;
|
||||
LineNumber lineNumber;
|
||||
FileInfo fileInfo = new(indexFile);
|
||||
string? directory = Path.GetDirectoryName(sourceDirectory);
|
||||
(lines, lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
|
||||
ReadOnlyCollection<string> indexFileLines = new(lines);
|
||||
List<Record> records = GetCollectionFromIndex(sourceDirectory, indexFileLines);
|
||||
if (directory is not null && lineNumber.H1 is not null)
|
||||
List<Record> records = GetCollectionFromIndex(sourceDirectory, kanbanIndexFileLines);
|
||||
if (directory is not null && kanbanIndexFileLineNumber.H1 is not null)
|
||||
{
|
||||
string checkDirectory = Path.Combine(directory, ".vscode", "helper");
|
||||
if (Directory.Exists(checkDirectory))
|
||||
WriteKanbanBoardFile(checkDirectory, records, indexFileLines[lineNumber.H1.Value]);
|
||||
{
|
||||
WriteKanbanBoardFile(checkDirectory, records, kanbanIndexFileLines[kanbanIndexFileLineNumber.H1.Value]);
|
||||
WriteKanbanBoardYmlView(checkDirectory, records, kanbanIndexFileLines[kanbanIndexFileLineNumber.H1.Value]);
|
||||
}
|
||||
}
|
||||
foreach (Record record in records)
|
||||
{
|
||||
@ -160,6 +216,9 @@ internal static partial class HelperKanbanMetadata
|
||||
continue;
|
||||
lines[lineNumber.Status.Value] = statusLine;
|
||||
}
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(record.FileInfo.FullName);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(record.FileInfo.FullName, lines);
|
||||
}
|
||||
}
|
||||
@ -171,10 +230,14 @@ internal static partial class HelperKanbanMetadata
|
||||
if (!Directory.Exists(fullPath))
|
||||
_ = Directory.CreateDirectory(fullPath);
|
||||
string indexFile = Path.Combine(fullPath, "index.md");
|
||||
if (File.Exists(indexFile))
|
||||
SetMetadata(fullPath, indexFile);
|
||||
else
|
||||
if (!File.Exists(indexFile))
|
||||
logger.LogInformation("<{indexFile}> doesn't exist!", indexFile);
|
||||
else
|
||||
{
|
||||
FileInfo fileInfo = new(indexFile);
|
||||
(List<string> lines, LineNumber lineNumber) = HelperMarkdown.GetStatusAndFrontMatterYamlEndLineNumbers(fileInfo);
|
||||
SetMetadata(fullPath, new(lines), lineNumber, gitOthersModifiedAndDeletedExcludingStandardFiles: new([]));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -163,7 +163,7 @@ internal static partial class HelperMarkdown
|
||||
/// </summary>
|
||||
/// <param name="filename">The text file to analyze.</param>
|
||||
/// <returns>The detected encoding.</returns>
|
||||
internal static Encoding? GetEncoding(string filename)
|
||||
private static Encoding? GetEncoding(string filename)
|
||||
{
|
||||
Encoding? result;
|
||||
byte[] bom = new byte[4];
|
||||
@ -538,10 +538,11 @@ internal static partial class HelperMarkdown
|
||||
return new(results);
|
||||
}
|
||||
|
||||
private static int ConvertFileToSlugName(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int ConvertFileToSlugName(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
string h1;
|
||||
bool gitCheck;
|
||||
string h1Check;
|
||||
string[] lines;
|
||||
string checkName;
|
||||
@ -553,6 +554,7 @@ internal static partial class HelperMarkdown
|
||||
continue;
|
||||
lines = relativeTo.Value.Lines;
|
||||
markdownFile = relativeTo.Value.MarkdownFile;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (markdownFile.LineNumber.H1 is not null)
|
||||
{
|
||||
h1 = lines[markdownFile.LineNumber.H1.Value];
|
||||
@ -561,6 +563,8 @@ internal static partial class HelperMarkdown
|
||||
h1Check = $"# {h1[2..]}";
|
||||
if (h1Check.Length == h1.Length && h1Check != h1)
|
||||
{
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
lines[markdownFile.LineNumber.H1.Value] = h1Check;
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
@ -575,25 +579,28 @@ internal static partial class HelperMarkdown
|
||||
checkName = Path.Combine(markdownFile.Directory, checkFileName);
|
||||
if (checkName == markdownFile.File)
|
||||
continue;
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.Move(markdownFile.File, checkName);
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
internal static string[] GetFiles(AppSettings appSettings, string directory)
|
||||
private static string[] GetFiles(AppSettings appSettings, string directory)
|
||||
{
|
||||
string[] results = Directory.GetFiles(directory, "*.md", SearchOption.AllDirectories).
|
||||
Where(l => !appSettings.ExcludeDirectoryNames.Any(m => l.Contains(m))).ToArray();
|
||||
return results;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, string[] files, bool force)
|
||||
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, string[] files, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles, bool force)
|
||||
{
|
||||
Dictionary<string, MarkdownFileAndLines> results = [];
|
||||
string h1;
|
||||
string key;
|
||||
string type;
|
||||
bool gitCheck;
|
||||
FileInfo fileInfo;
|
||||
bool isKanbanIndex;
|
||||
List<string> lines;
|
||||
@ -602,7 +609,7 @@ internal static partial class HelperMarkdown
|
||||
MarkdownFile markdownFile;
|
||||
string fileNameWithoutExtension;
|
||||
foreach (string file in files)
|
||||
{
|
||||
{ // cSpell:disable
|
||||
fileInfo = new(file);
|
||||
if (fileInfo.DirectoryName is null)
|
||||
continue;
|
||||
@ -614,6 +621,9 @@ internal static partial class HelperMarkdown
|
||||
(type, h1) = GetTypeAndH1(appSettings, h1, lines, lineNumber);
|
||||
else
|
||||
{
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(file);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
type = appSettings.DefaultNoteType;
|
||||
File.WriteAllLines(file, ["---", $"type: \"{type}\"", "---", string.Empty, $"# {h1}"]);
|
||||
lines = File.ReadAllLines(file).ToList();
|
||||
@ -636,7 +646,7 @@ internal static partial class HelperMarkdown
|
||||
results.Add(key, new(markdownFile, lines.ToArray()));
|
||||
else
|
||||
results.Add(key, new(markdownFile, []));
|
||||
}
|
||||
} // cSpell:restore
|
||||
return new(results);
|
||||
}
|
||||
|
||||
@ -834,11 +844,12 @@ internal static partial class HelperMarkdown
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int ConvertFrontMatterToJsonFriendly(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int ConvertFrontMatterToJsonFriendly(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
List<string> results = [];
|
||||
bool write;
|
||||
bool gitCheck;
|
||||
string[] lines;
|
||||
MarkdownFile markdownFile;
|
||||
string[] frontMatterYamlLines;
|
||||
@ -872,6 +883,9 @@ internal static partial class HelperMarkdown
|
||||
if (!write)
|
||||
continue;
|
||||
}
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, results);
|
||||
File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime);
|
||||
result += 1;
|
||||
@ -879,11 +893,12 @@ internal static partial class HelperMarkdown
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int CircularReference(ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int CircularReference(ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
string line;
|
||||
string check;
|
||||
bool gitCheck;
|
||||
string[] lines;
|
||||
bool circularReference;
|
||||
MarkdownFile markdownFile;
|
||||
@ -931,21 +946,24 @@ internal static partial class HelperMarkdown
|
||||
if (!circularReference)
|
||||
circularReference = true;
|
||||
}
|
||||
if (circularReference)
|
||||
{
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
if (!circularReference)
|
||||
continue;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int FindReplace(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int FindReplace(ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
bool found;
|
||||
string line;
|
||||
string check;
|
||||
bool gitCheck;
|
||||
string[] lines;
|
||||
MarkdownFile markdownFile;
|
||||
foreach (KeyValuePair<string, MarkdownFileAndLines> relativeTo in relativeToCollection)
|
||||
@ -979,20 +997,23 @@ internal static partial class HelperMarkdown
|
||||
if (!found)
|
||||
found = true;
|
||||
}
|
||||
if (found)
|
||||
{
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
if (!found)
|
||||
continue;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int ConvertToRelativePath(ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int ConvertToRelativePath(ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
bool write;
|
||||
string line;
|
||||
bool gitCheck;
|
||||
string[] lines;
|
||||
string[] segmentsA;
|
||||
string[] segmentsB;
|
||||
@ -1029,21 +1050,24 @@ internal static partial class HelperMarkdown
|
||||
if (!write)
|
||||
write = true;
|
||||
}
|
||||
if (write)
|
||||
{
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
if (!write)
|
||||
continue;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static int ConvertFileToSlugName(AppSettings appSettings, ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection)
|
||||
private static int ConvertFileToSlugName(AppSettings appSettings, ILogger<Worker> logger, ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
int result = 0;
|
||||
bool write;
|
||||
string file;
|
||||
string line;
|
||||
bool gitCheck;
|
||||
string[] lines;
|
||||
string fileName;
|
||||
string checkName;
|
||||
@ -1124,22 +1148,24 @@ internal static partial class HelperMarkdown
|
||||
if (!write)
|
||||
write = true;
|
||||
}
|
||||
if (write)
|
||||
{
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
if (!write)
|
||||
continue;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, lines);
|
||||
result += 1;
|
||||
}
|
||||
if (result == 0)
|
||||
result = ConvertFileToSlugName(relativeToCollection);
|
||||
result = ConvertFileToSlugName(relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
return result;
|
||||
}
|
||||
|
||||
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, bool force = false)
|
||||
private static ReadOnlyDictionary<string, MarkdownFileAndLines> GetRelativeToCollection(AppSettings appSettings, Input input, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles, bool force = false)
|
||||
{
|
||||
ReadOnlyDictionary<string, MarkdownFileAndLines> results;
|
||||
string[] files = GetFiles(appSettings, input.Source);
|
||||
results = GetRelativeToCollection(appSettings, input, files, force);
|
||||
results = GetRelativeToCollection(appSettings, input, files, gitOthersModifiedAndDeletedExcludingStandardFiles, force);
|
||||
return new(results);
|
||||
}
|
||||
|
||||
@ -1167,12 +1193,16 @@ internal static partial class HelperMarkdown
|
||||
return results;
|
||||
}
|
||||
|
||||
private static void Write(Input input, List<MarkdownFileAndLines> markdownFileAndLinesCollection)
|
||||
private static void Write(Input input, List<MarkdownFileAndLines> markdownFileAndLinesCollection, ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles)
|
||||
{
|
||||
bool gitCheck;
|
||||
foreach (MarkdownFileAndLines markdownFileAndLines in markdownFileAndLinesCollection)
|
||||
{
|
||||
if (input.Destination is null)
|
||||
continue;
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFileAndLines.MarkdownFile.File);
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(Path.Combine(input.Destination, markdownFileAndLines.MarkdownFile.FileName), markdownFileAndLines.Lines);
|
||||
}
|
||||
}
|
||||
@ -1231,8 +1261,6 @@ internal static partial class HelperMarkdown
|
||||
markdownFile = relativeTo.Value.MarkdownFile;
|
||||
if (markdownFile.IsKanbanMarkdown)
|
||||
continue;
|
||||
if (markdownFile.IsKanbanIndex)
|
||||
HelperKanbanMetadata.SetMetadata(markdownFile.Directory, markdownFile.File);
|
||||
results.AddRange(lines);
|
||||
typeLine = $"type: \"{appSettings.DefaultNoteType}\"";
|
||||
h1Line = $"# {markdownFile.FileNameWithoutExtension}";
|
||||
@ -1240,6 +1268,8 @@ internal static partial class HelperMarkdown
|
||||
gitCheck = gitOthersModifiedAndDeletedExcludingStandardFiles.Contains(markdownFile.File);
|
||||
createdLine = $"created: \"{creationDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\"";
|
||||
updatedLine = $"updated: \"{markdownFile.LastWriteDateTime.ToUniversalTime():yyyy-MM-ddTHH:mm:ss.fffZ}\"";
|
||||
if (markdownFile.IsKanbanIndex)
|
||||
HelperKanbanMetadata.SetMetadata(markdownFile.Directory, new(lines), markdownFile.LineNumber, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (markdownFile.LineNumber.FrontMatterYamlEnd is null)
|
||||
{
|
||||
if (markdownFile.LineNumber.H1 is not null)
|
||||
@ -1305,6 +1335,8 @@ internal static partial class HelperMarkdown
|
||||
}
|
||||
if (results.Count == lines.Length && string.Join('\r', lines) == string.Join('\r', results))
|
||||
continue;
|
||||
if (!gitCheck)
|
||||
continue;
|
||||
File.WriteAllLines(markdownFile.File, results);
|
||||
File.SetLastWriteTime(markdownFile.File, markdownFile.LastWriteDateTime);
|
||||
result += 1;
|
||||
@ -1321,51 +1353,51 @@ internal static partial class HelperMarkdown
|
||||
internal static void MarkdownWikiLinkVerification(AppSettings appSettings, ILogger<Worker> logger, List<string> args, CancellationToken cancellationToken)
|
||||
{
|
||||
int updated;
|
||||
bool usePathCombine = false;
|
||||
bool usePathCombine = true;
|
||||
Input input = GetInput(args);
|
||||
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
ReadOnlyCollection<string> gitOthersModifiedAndDeletedExcludingStandardFiles = HelperGit.GetOthersModifiedAndDeletedExcludingStandardFiles(input.Source, usePathCombine, cancellationToken);
|
||||
ReadOnlyDictionary<string, MarkdownFileAndLines> relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
updated = SetFrontMatterAndH1(appSettings, logger, input, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
updated = ConvertFrontMatterToJsonFriendly(relativeToCollection);
|
||||
updated = ConvertFrontMatterToJsonFriendly(relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
updated = CircularReference(logger, relativeToCollection);
|
||||
updated = CircularReference(logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
updated = FindReplace(relativeToCollection);
|
||||
updated = FindReplace(relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
updated = ConvertToRelativePath(logger, relativeToCollection);
|
||||
updated = ConvertToRelativePath(logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
updated = ConvertFileToSlugName(appSettings, logger, relativeToCollection);
|
||||
updated = ConvertFileToSlugName(appSettings, logger, relativeToCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
if (updated != 0)
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
logger.LogInformation("{updated} Markdown file(s) were updated", updated);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(input.StartAt) && !string.IsNullOrEmpty(input.Destination))
|
||||
{
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, force: true);
|
||||
relativeToCollection = GetRelativeToCollection(appSettings, input, gitOthersModifiedAndDeletedExcludingStandardFiles, force: true);
|
||||
List<MarkdownFileAndLines> markdownFileAndLinesCollection = GetRecursiveLines(appSettings, input, logger, relativeToCollection);
|
||||
Write(input, markdownFileAndLinesCollection);
|
||||
Write(input, markdownFileAndLinesCollection, gitOthersModifiedAndDeletedExcludingStandardFiles);
|
||||
}
|
||||
if (!string.IsNullOrEmpty(input.StartAt) && !string.IsNullOrEmpty(input.Destination))
|
||||
SaveColumnToCards(input, relativeToCollection);
|
||||
|
Loading…
x
Reference in New Issue
Block a user