From 97fa42742bc309a71c31803877904781712b6091 Mon Sep 17 00:00:00 2001 From: VaDiM Date: Fri, 9 May 2025 23:55:24 +0300 Subject: [PATCH] [CLI] Add flag to allow filtering assets using regex. Close #45 - Added --filter-with-regex flag --- AssetStudioCLI/Options/CLIOptions.cs | 36 +++++++++++++++++++------ AssetStudioCLI/Studio.cs | 39 +++++++++++++++++++++++++++- 2 files changed, 66 insertions(+), 9 deletions(-) diff --git a/AssetStudioCLI/Options/CLIOptions.cs b/AssetStudioCLI/Options/CLIOptions.cs index 70bfec7..99325de 100644 --- a/AssetStudioCLI/Options/CLIOptions.cs +++ b/AssetStudioCLI/Options/CLIOptions.cs @@ -108,6 +108,7 @@ namespace AssetStudioCLI.Options public static Option> o_filterByContainer; public static Option> o_filterByPathID; public static Option> o_filterByText; + public static Option f_filterWithRegex; //advanced public static Option o_bundleBlockInfoCompression; public static Option o_bundleBlockCompression; @@ -384,7 +385,7 @@ namespace AssetStudioCLI.Options ( optionDefaultValue: new List(), optionName: "--filter-by-name ", - optionDescription: "Specify the name by which assets should be filtered\n" + + optionDescription: "Specify the name or regexp by which assets should be filtered\n" + "*To specify multiple names write them separated by ',' or ';' without spaces\n", optionExample: "Example: \"--filter-by-name char\" or \"--filter-by-name char,bg\"\n", optionHelpGroup: HelpGroups.Filter @@ -393,7 +394,7 @@ namespace AssetStudioCLI.Options ( optionDefaultValue: new List(), optionName: "--filter-by-container ", - optionDescription: "Specify the container by which assets should be filtered\n" + + optionDescription: "Specify the container or regexp by which assets should be filtered\n" + "*To specify multiple containers write them separated by ',' or ';' without spaces\n", optionExample: "Example: \"--filter-by-container arts\" or \"--filter-by-container arts,icons\"\n", optionHelpGroup: HelpGroups.Filter @@ -411,12 +412,22 @@ namespace AssetStudioCLI.Options ( optionDefaultValue: new List(), optionName: "--filter-by-text ", - optionDescription: "Specify the text by which assets should be filtered\n" + + optionDescription: "Specify the text or regexp by which assets should be filtered\n" + "Looks for assets that contain the specified text in their names or containers\n" + "*To specify multiple values write them separated by ',' or ';' without spaces\n", - optionExample: "Example: \"--filter-by-text portrait\" or \"--filter-by-text portrait,art\"", + optionExample: "Example: \"--filter-by-text portrait\" or \"--filter-by-text portrait,art\"\n", optionHelpGroup: HelpGroups.Filter ); + f_filterWithRegex = new GroupedOption + ( + optionDefaultValue: false, + optionName: "--filter-with-regex", + optionDescription: "(Flag) If specified, the filter options will handle the specified text\n" + + "as a regular expression (doesn't apply to --filter-by-pathid)", + optionExample: "", + optionHelpGroup: HelpGroups.Filter, + isFlag: true + ); #endregion #region Init Advanced Options @@ -662,6 +673,10 @@ namespace AssetStudioCLI.Options f_fbxUvsAsDiffuseMaps.Value = true; resplittedArgs.RemoveAt(i); break; + case "--filter-with-regex": + f_filterWithRegex.Value = true; + resplittedArgs.RemoveAt(i); + break; case "--not-restore-extension": f_notRestoreExtensionName.Value = true; resplittedArgs.RemoveAt(i); @@ -1077,11 +1092,11 @@ namespace AssetStudioCLI.Options } break; case "--filter-by-name": - o_filterByName.Value.AddRange(ValueSplitter(value)); + o_filterByName.Value.AddRange(ValueSplitter(value, isRegex: f_filterWithRegex.Value)); filterBy = filterBy == FilterBy.None ? FilterBy.Name : filterBy == FilterBy.Container ? FilterBy.NameAndContainer : filterBy; break; case "--filter-by-container": - o_filterByContainer.Value.AddRange(ValueSplitter(value)); + o_filterByContainer.Value.AddRange(ValueSplitter(value, isRegex: f_filterWithRegex.Value)); filterBy = filterBy == FilterBy.None ? FilterBy.Container : filterBy == FilterBy.Name ? FilterBy.NameAndContainer : filterBy; break; case "--filter-by-pathid": @@ -1089,7 +1104,7 @@ namespace AssetStudioCLI.Options filterBy = FilterBy.PathID; break; case "--filter-by-text": - o_filterByText.Value.AddRange(ValueSplitter(value)); + o_filterByText.Value.AddRange(ValueSplitter(value, isRegex: f_filterWithRegex.Value)); filterBy = FilterBy.NameOrContainer; break; case "--assembly-folder": @@ -1172,8 +1187,11 @@ namespace AssetStudioCLI.Options isParsed = true; } - private static string[] ValueSplitter(string value) + private static string[] ValueSplitter(string value, bool isRegex = false) { + if (isRegex) + return new[] {value}; + var separator = value.Contains(';') ? ';' : ','; return value.Split(separator); } @@ -1314,6 +1332,7 @@ namespace AssetStudioCLI.Options sb.AppendLine($"# Log Output: {o_logOutput}"); sb.AppendLine($"# Export Asset List: {o_exportAssetList}"); sb.AppendLine(ShowCurrentFilter()); + sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); sb.AppendLine($"# Assembly Path: \"{o_assemblyPath}\""); sb.AppendLine($"# Unity Version: {unityVer}"); if (o_workMode.Value == WorkMode.Export) @@ -1329,6 +1348,7 @@ namespace AssetStudioCLI.Options sb.AppendLine($"# Log Output: {o_logOutput}"); sb.AppendLine($"# Export Asset List: {o_exportAssetList}"); sb.AppendLine(ShowCurrentFilter()); + sb.AppendLine($"# Filter With Regex: {f_filterWithRegex}"); sb.AppendLine($"# Unity Version: {unityVer}"); break; case WorkMode.Live2D: diff --git a/AssetStudioCLI/Studio.cs b/AssetStudioCLI/Studio.cs index 9ee08c2..70a0b9a 100644 --- a/AssetStudioCLI/Studio.cs +++ b/AssetStudioCLI/Studio.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using System.Collections.Specialized; using System.IO; using System.Linq; +using System.Text.RegularExpressions; using System.Threading; using System.Threading.Tasks; using System.Xml.Linq; @@ -534,9 +535,19 @@ namespace AssetStudioCLI { var assetsCount = parsedAssetsList.Count; var filteredAssets = new List(); + var regexMode = CLIOptions.f_filterWithRegex.Value; + Regex regex; switch(CLIOptions.filterBy) { + case FilterBy.Name when regexMode: + regex = new Regex(CLIOptions.o_filterByName.Value[0]); + filteredAssets = parsedAssetsList.FindAll(x => regex.IsMatch(x.Text)); + Logger.Info( + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + + $"which Names match {regex.ToString().Color(Ansi.BrightYellow)} regexp." + ); + break; case FilterBy.Name: filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByName.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)); Logger.Info( @@ -544,6 +555,14 @@ namespace AssetStudioCLI $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByName.Value)}\"".Color(Ansi.BrightYellow)} in their Names." ); break; + case FilterBy.Container when regexMode: + regex = new Regex(CLIOptions.o_filterByContainer.Value[0]); + filteredAssets = parsedAssetsList.FindAll(x => regex.IsMatch(x.Container)); + Logger.Info( + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + + $"which Containers match {regex.ToString().Color(Ansi.BrightYellow)} regexp." + ); + break; case FilterBy.Container: filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByContainer.Value.Any(y => x.Container.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0)); Logger.Info( @@ -558,6 +577,14 @@ namespace AssetStudioCLI $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByPathID.Value)}\"".Color(Ansi.BrightYellow)} in their PathIDs." ); break; + case FilterBy.NameOrContainer when regexMode: + regex = new Regex(CLIOptions.o_filterByText.Value[0]); + filteredAssets = parsedAssetsList.FindAll(x => regex.IsMatch(x.Text) || regex.IsMatch(x.Container)); + Logger.Info( + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + + $"which Names or Containers match {regex.ToString().Color(Ansi.BrightYellow)} regexp." + ); + break; case FilterBy.NameOrContainer: filteredAssets = parsedAssetsList.FindAll(x => CLIOptions.o_filterByText.Value.Any(y => x.Text.IndexOf(y, StringComparison.OrdinalIgnoreCase) >= 0) || @@ -565,7 +592,17 @@ namespace AssetStudioCLI ); Logger.Info( $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + - $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Contaniers." + $"that contain {$"\"{string.Join("\", \"", CLIOptions.o_filterByText.Value)}\"".Color(Ansi.BrightYellow)} in their Names or Containers." + ); + break; + case FilterBy.NameAndContainer when regexMode: + var nameRegex = new Regex(CLIOptions.o_filterByName.Value[0]); + var containerRegex = new Regex(CLIOptions.o_filterByContainer.Value[0]); + filteredAssets = parsedAssetsList.FindAll(x => nameRegex.IsMatch(x.Text) && containerRegex.IsMatch(x.Container)); + Logger.Info( + $"Found [{filteredAssets.Count}/{assetsCount}] asset(s) " + + $"which Containers match {containerRegex.ToString().Color(Ansi.BrightYellow)} regexp " + + $"and which Names match {nameRegex.ToString().Color(Ansi.BrightYellow)} regexp." ); break; case FilterBy.NameAndContainer: