From 971896cacb46d51181a5f3d8a6020926e8daac19 Mon Sep 17 00:00:00 2001 From: timerix Date: Wed, 8 Feb 2023 04:38:33 +0600 Subject: [PATCH] finally it is working fine --- Clear.cs | 71 -------------------- Diff.cs | 20 +++--- Localisation.cs | 10 +-- Merge.cs | 8 +-- Program.cs | 15 +++-- Workshop.cs | 136 ++++++++++++++++++++++++++++++++++++++ paradox-mod-merger.csproj | 5 +- paradox-mod-merger.sln | 6 ++ 8 files changed, 175 insertions(+), 96 deletions(-) delete mode 100644 Clear.cs create mode 100644 Workshop.cs diff --git a/Clear.cs b/Clear.cs deleted file mode 100644 index 963114a..0000000 --- a/Clear.cs +++ /dev/null @@ -1,71 +0,0 @@ -namespace ParadoxModMerger; - -static class Clear -{ - - static ConsoleLogger logger = new($"logs", "clear"); - static void Log(params string[] msg) => logger.Log(msg); - - public static void ClearWorkshop(string workshopDir, string outDir) - { - string[] moddirs = Directory.GetDirectories(workshopDir); - Log("b", $"found {moddirs.Length} mod dirs"); - for (int i = 0; i < moddirs.Length; i++) - { - string modarch = ""; - if (Directory.GetFiles(moddirs[i], "*.zip").Length != 0) - modarch = Directory.GetFiles(moddirs[i], "*.zip")[0]; - if (modarch.Length != 0) - { - Log("y", $"archive found: {modarch}"); - var pr = new Process(); - pr.StartInfo.CreateNoWindow = true; - pr.StartInfo.UseShellExecute = false; - pr.StartInfo.FileName = Path.Concat("7z", "7z.exe"); - pr.StartInfo.Arguments = $"x -y -o _UNZIP \"{modarch}\""; - pr.Start(); - pr.WaitForExit(); - moddirs[i] = "_UNZIP"; - Log("g", "\tfiles extracted"); - } - - string modname = File.ReadAllText(Path.Concat(moddirs[i], "descriptor.mod")); - modname = modname.Remove(0, modname.IndexOf("name=\"", StringComparison.Ordinal) + 6); - modname = Path.CorrectString(modname.Remove(modname.IndexOf("\"", StringComparison.Ordinal))); - Log("b", $"[{i + 1}/{moddirs.Length}] copying mod ", "c", $"{modname}"); - string[] subdirs = Directory.GetDirectories(moddirs[i]); - for (sbyte n = 0; n < subdirs.Length; n++) - { - subdirs[n] = subdirs[n].Remove(0, subdirs[n].LastIndexOf(Path.Sep) + 1); - switch (subdirs[n]) - { - // stellaris - case "common": - case "events": - case "flags": - case "fonts": - case "gfx": - case "interface": - case "localisation": - case "localisation_synced": - case "map": - case "music": - case "prescripted_countries": - case "sound": - // hoi4 - case "history": - case "portraits": - { - Directory.Copy(Path.Concat(moddirs[i], subdirs[n]), - Path.Concat(outDir, modname, subdirs[n]), - out List _conflicts, true); - Program.LogConflicts(_conflicts); - break; - } - } - } - - if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP"); - } - } -} \ No newline at end of file diff --git a/Diff.cs b/Diff.cs index 9fd665c..54df3ac 100644 --- a/Diff.cs +++ b/Diff.cs @@ -11,17 +11,17 @@ static class Diff DiffMods(split[0], split[1]); } - public static void DiffMods(string moddir0, string moddir1) + public static void DiffMods(IOPath moddir0, IOPath moddir1) { var hasher = new Hasher(); - var diff = new Dictionary(); + var diff = new Dictionary(); // добавление файлов из первой папки - List files = Directory.GetAllFiles(moddir0); - var mods = new List(); + List files = Directory.GetAllFiles(moddir0); + var mods = new List(); for (short i = 0; i < files.Count; i++) { byte[] hash = hasher.HashFile(files[i]); - files[i] = files[i].Replace(moddir0, ""); + files[i] = files[i].ReplaceBase(moddir0, ""); diff.Add(files[i], hash); AddMod(files[i]); } @@ -31,17 +31,17 @@ static class Diff for (short i = 0; i < files.Count; i++) { byte[] hash = hasher.HashFile(files[i]); - files[i] = files[i].Replace(moddir1, ""); + files[i] = files[i].RemoveBase(moddir1); if (diff.ContainsKey(files[i]) && diff[files[i]].HashToString() == hash.HashToString()) diff.Remove(files[i]); else { - diff.Add(moddir1 + files[i], hash); + diff.Add(Path.Concat(moddir1,files[i]), hash); AddMod(files[i]); } } - void AddMod(string mod) + void AddMod(IOPath mod) { mod = mod.Remove(0, 1); mod = mod.Remove(mod.IndexOf(Path.Sep)); @@ -51,10 +51,10 @@ static class Diff // вывод результата StringBuilder output = new StringBuilder(); output.Append($"[{DateTime.Now}]\n\n"); - foreach (string mod in mods) + foreach (var mod in mods) { output.Append('\n').Append(mod).Append("\n{\n"); - foreach (string file in diff.Keys) + foreach (var file in diff.Keys) { if (file.Contains(mod)) { diff --git a/Localisation.cs b/Localisation.cs index b76de27..513bbf7 100644 --- a/Localisation.cs +++ b/Localisation.cs @@ -5,13 +5,13 @@ static class Localisation static ConsoleLogger logger = new($"logs", "autoloc"); static void Log(params string[] msg) => logger.Log(msg); - public static void GenerateRussian(string engDir, string rusDir) + public static void GenerateRussian(IOPath engDir, IOPath rusDir) { - foreach (string enfFileName in Directory.GetAllFiles(engDir)) + foreach (var enfFileName in Directory.GetAllFiles(engDir)) { - string rusFileName = enfFileName - .Replace(engDir, rusDir) - .Replace("l_english", "l_russian"); + IOPath rusFileName = enfFileName + .ReplaceBase(engDir, rusDir) + .ReplaceAnywhere("l_english", "l_russian"); if (!File.Exists(rusFileName)) { string text = File.ReadAllText(enfFileName) diff --git a/Merge.cs b/Merge.cs index d9d5f33..e5ee8e1 100644 --- a/Merge.cs +++ b/Merge.cs @@ -5,20 +5,20 @@ static class Merge static ConsoleLogger logger = new($"logs", "merge"); static void Log(params string[] msg) => logger.Log(msg); - public static void MergeAll(string[] moddirs, string outDir) + public static void MergeAll(IOPath[] moddirs, IOPath outDir) { Log("b", $"found {moddirs.Length} mod dirs"); for (short i = 0; i < moddirs.Length; i++) { Log("b", $"[{i + 1}/{moddirs.Length}] merging mod ", "c", $"{moddirs[i]}"); - Directory.Copy(moddirs[i], outDir, out List _conflicts, true); + Directory.Copy(moddirs[i], outDir, true, out var _conflicts); Program.LogConflicts(_conflicts); } } - public static void MergeSingle(string moddir, string outDir) + public static void MergeSingle(IOPath moddir, IOPath outDir) { - Directory.Copy(moddir, outDir, out List _conflicts, true); + Directory.Copy(moddir, outDir, true, out var _conflicts); Program.LogConflicts(_conflicts); } } \ No newline at end of file diff --git a/Program.cs b/Program.cs index c957f22..28dbc1c 100644 --- a/Program.cs +++ b/Program.cs @@ -19,6 +19,9 @@ public static class Program { try { + Console.OutputEncoding=Encoding.UTF8; + Console.InputEncoding=Encoding.UTF8; + string outPath = "" ; new LaunchArgumentParser( @@ -29,7 +32,7 @@ public static class Program 0), new LaunchArgument(new []{"clear"}, "Clear mod files and put them into separate dirs in output dir. Requires -o", - wdir=>Clear.ClearWorkshop(wdir, outPath), + wdir=>Workshop.ClearWorkshop(wdir, outPath), "workshop_dir", 1), new LaunchArgument(new []{"diff"}, @@ -49,7 +52,10 @@ public static class Program new LaunchArgument(new []{"gen-rus-locale"}, "Creates l_russian copy of english locale in output directory. Requires -o", eng=>Localisation.GenerateRussian(eng, outPath), - "english_locale_path", 1) + "english_locale_path", 1), + new LaunchArgument(new []{"desc"}, + "Downloads mod description from steam to new file in outDir. Requires -o", + id=>Workshop.CreateDescFile(id, outPath), "mod_id") ).ParseAndHandle(args); } catch (LaunchArgumentParser.ExitAfterHelpException) @@ -63,10 +69,9 @@ public static class Program // вывод конфликтующих файлов при -merge и -clear если такие есть - public static void LogConflicts(List conflicts) + public static void LogConflicts(List conflicts) { - Log("w", $"found {conflicts.Count}"); if(conflicts.Count>0) - Log("w","conflicts:\n", "m", conflicts.MergeToString("\n")); + Log("y", $"conflicts found: {conflicts.Count}\n{conflicts.MergeToString("\n")}"); } } \ No newline at end of file diff --git a/Workshop.cs b/Workshop.cs new file mode 100644 index 0000000..a47b67b --- /dev/null +++ b/Workshop.cs @@ -0,0 +1,136 @@ +using System.Linq; +using System.Net.Http; +using System.Threading.Tasks; +using DTLib.Ben.Demystifier; +using HtmlAgilityPack; + +namespace ParadoxModMerger; +using Fizzler.Systems.HtmlAgilityPack; + +static class Workshop +{ + + static ConsoleLogger logger = new($"logs", "clear"); + static void Log(params string[] msg) => logger.Log(msg); + + public static void ClearWorkshop(IOPath workshopDir, IOPath outDir) + { + var moddirs = Directory.GetDirectories(workshopDir); + Log("b", $"found {moddirs.Length} mod dirs"); + for (int i = 0; i < moddirs.Length; i++) + { + string modId = moddirs[i].LastName().ToString(); + IOPath modZip=""; + if (Directory.GetFiles(moddirs[i], "*.zip").Length != 0) + modZip = Directory.GetFiles(moddirs[i], "*.zip")[0]; + if (modZip.Length != 0) + { + Log("y", $"archive found: {modZip}"); + if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP"); + var pr = new Process(); + pr.StartInfo.CreateNoWindow = true; + pr.StartInfo.UseShellExecute = false; + pr.StartInfo.FileName = Path.Concat("7z", "7z.exe").Str; + pr.StartInfo.Arguments = $"x -y -o_UNZIP \"{modZip}\""; + Log("h",$"{pr.StartInfo.WorkingDirectory}$: {pr.StartInfo.FileName} {pr.StartInfo.Arguments}"); + pr.Start(); + pr.WaitForExit(); + moddirs[i] = "_UNZIP"; + Log("g", "\tfiles extracted"); + } + + var descriptorPath = Path.Concat(moddirs[i], "descriptor.mod"); + string descriptor = File.ReadAllText(descriptorPath); + string modname = descriptor.Substring(descriptor.IndexOf("name=\"", StringComparison.Ordinal) + 6); + modname = modname.Remove(modname.IndexOf("\"", StringComparison.Ordinal)); + Log("b", $"[{i + 1}/{moddirs.Length}] copying mod ", "c", $"({modId}) {modname}"); + + IOPath outModDir=Path.Concat(outDir, Path.ReplaceRestrictedChars(modname)); + File.Copy(descriptorPath, Path.Concat(outModDir, "descriptor.mod"), true); + + CreateDescFile(modId, outModDir); + + + + var subdirs = Directory.GetDirectories(moddirs[i]); + for (sbyte n = 0; n < subdirs.Length; n++) + { + subdirs[n] = subdirs[n].Remove(0, subdirs[n].LastIndexOf(Path.Sep) + 1); + switch (subdirs[n].Str) + { + // stellaris + case "common": + case "events": + case "flags": + case "fonts": + case "gfx": + case "interface": + case "localisation": + case "localisation_synced": + case "map": + case "music": + case "prescripted_countries": + case "sound": + // hoi4 + case "history": + case "portraits": + { + Directory.Copy(Path.Concat(moddirs[i], subdirs[n]), + Path.Concat(outModDir, subdirs[n]), + true, out var _conflicts); + Program.LogConflicts(_conflicts); + break; + } + } + } + + if (Directory.Exists("_UNZIP")) Directory.Delete("_UNZIP"); + } + } + + private static HttpClient http = new HttpClient(); + + public static async void CreateDescFile(string workshopId, IOPath outDir) + { + try + { + string desc = await DownloadModDescription(workshopId); + var file = Path.Concat(outDir, $"desc_{workshopId}.txt"); + File.WriteAllText(file, desc); + Log("g", $"downloaded {workshopId} description to {file}"); + } + catch (Exception e) + { + Log("r", $"mod {workshopId} error: \n"+ e.ToStringDemystified()); + } + } + public static async Task DownloadModDescription(string workshopId) + { + string url = "https://steamcommunity.com/sharedfiles/filedetails/?id=" + workshopId; + var b = new StringBuilder(url); + b.Append("\n\n"); + string pageText = await http.GetStringAsync(url); + var page = new HtmlDocument(); + page.LoadHtml(pageText); + var descNode=page.DocumentNode.QuerySelectorAll(".workshopItemDescription").FirstOrDefault(); + if (descNode is null) + Log("y", $"no description found for mod {workshopId}"); + else processNodes(descNode.ChildNodes); + + return b.ToString().Replace(""","\""); + + void processNodes(IEnumerable nodes) + { + foreach (var node in nodes) + { + b.Append( + node.Name switch + { + "br" => '\n', + "a" => $"{node.InnerText} ({node.GetAttributeValue("href", "NULL_ATTRIBUTE")}) ", + _ => node.InnerText + }); + } + } + } +} \ No newline at end of file diff --git a/paradox-mod-merger.csproj b/paradox-mod-merger.csproj index 28aa5b0..57fda96 100644 --- a/paradox-mod-merger.csproj +++ b/paradox-mod-merger.csproj @@ -13,7 +13,10 @@ - + + + + \ No newline at end of file diff --git a/paradox-mod-merger.sln b/paradox-mod-merger.sln index a1c6954..2fa85db 100644 --- a/paradox-mod-merger.sln +++ b/paradox-mod-merger.sln @@ -11,6 +11,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "solution_files", "solution_ nuget.config = nuget.config EndProjectSection EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DTLib", "..\DTLib\DTLib\DTLib.csproj", "{67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Release|Any CPU = Release|Any CPU @@ -21,6 +23,10 @@ Global {076BFCFF-1D3E-44FB-B434-73716B79A135}.Release|Any CPU.Build.0 = Release|Any CPU {076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {076BFCFF-1D3E-44FB-B434-73716B79A135}.Debug|Any CPU.Build.0 = Debug|Any CPU + {67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Release|Any CPU.Build.0 = Release|Any CPU + {67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {67E226B7-F04B-4FB1-A9AA-E4AE3A5A8A3F}.Debug|Any CPU.Build.0 = Debug|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE