중간 저장
This commit is contained in:
@@ -10,8 +10,9 @@ public sealed class KarismaSceneVariableCatalog
|
||||
{
|
||||
private static readonly string[] PreferredReportNames =
|
||||
[
|
||||
"TSCN_VARIABLE_DISCOVERY_ELECT2026_NORMAL.md",
|
||||
"TSCN_VARIABLE_DISCOVERY_E_DRIVE.md",
|
||||
"TSCN_VARIABLE_DISCOVERY_ELECT2026_NORMAL.md",
|
||||
"TSCN_VARIABLE_DISCOVERY_ONE.md",
|
||||
"TSCN_VARIABLE_DISCOVERY.md"
|
||||
];
|
||||
|
||||
@@ -28,8 +29,8 @@ public sealed class KarismaSceneVariableCatalog
|
||||
|
||||
public static KarismaSceneVariableCatalog Load(LogService logService)
|
||||
{
|
||||
var reportPath = FindDiscoveryReportPath();
|
||||
if (string.IsNullOrWhiteSpace(reportPath) || !File.Exists(reportPath))
|
||||
var reportPaths = FindDiscoveryReportPaths().ToArray();
|
||||
if (reportPaths.Length == 0)
|
||||
{
|
||||
logService.Warning("Karisma scene variable catalog report was not found. Falling back to runtime value heuristics.");
|
||||
return new KarismaSceneVariableCatalog(
|
||||
@@ -38,8 +39,17 @@ public sealed class KarismaSceneVariableCatalog
|
||||
|
||||
try
|
||||
{
|
||||
var scenes = ParseReport(reportPath);
|
||||
logService.Info($"Karisma scene variable catalog loaded: scenes={scenes.Count} source='{reportPath}'.");
|
||||
var mergedScenes = new Dictionary<string, Dictionary<string, KarismaSceneVariableDefinition>>(StringComparer.OrdinalIgnoreCase);
|
||||
foreach (var reportPath in reportPaths)
|
||||
{
|
||||
MergeScenes(mergedScenes, ParseReport(reportPath));
|
||||
}
|
||||
|
||||
var scenes = mergedScenes.ToDictionary(
|
||||
pair => pair.Key,
|
||||
pair => (IReadOnlyDictionary<string, KarismaSceneVariableDefinition>)pair.Value,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
logService.Info($"Karisma scene variable catalog loaded: scenes={scenes.Count} sources={reportPaths.Length}.");
|
||||
return new KarismaSceneVariableCatalog(scenes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -60,22 +70,45 @@ public sealed class KarismaSceneVariableCatalog
|
||||
}
|
||||
|
||||
var relativePath = NormalizeRelativePath(Path.GetRelativePath(t3CutPath, scenePath));
|
||||
return _scenes.TryGetValue(relativePath, out var variables)
|
||||
? variables
|
||||
: EmptySceneVariables;
|
||||
if (_scenes.TryGetValue(relativePath, out var variables))
|
||||
{
|
||||
return variables;
|
||||
}
|
||||
|
||||
var fileName = Path.GetFileName(relativePath);
|
||||
if (!string.IsNullOrWhiteSpace(fileName))
|
||||
{
|
||||
var fileNameMatches = _scenes
|
||||
.Where(pair => string.Equals(Path.GetFileName(pair.Key), fileName, StringComparison.OrdinalIgnoreCase))
|
||||
.Take(2)
|
||||
.ToArray();
|
||||
if (fileNameMatches.Length == 1)
|
||||
{
|
||||
return fileNameMatches[0].Value;
|
||||
}
|
||||
}
|
||||
|
||||
return EmptySceneVariables;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>> ParseReport(string reportPath)
|
||||
{
|
||||
var scenes = new Dictionary<string, Dictionary<string, KarismaSceneVariableDefinition>>(StringComparer.OrdinalIgnoreCase);
|
||||
string? currentScene = null;
|
||||
string? reportRootRelativePath = null;
|
||||
|
||||
foreach (var rawLine in File.ReadLines(reportPath, Encoding.UTF8))
|
||||
{
|
||||
var line = rawLine.Trim();
|
||||
if (TryParseReportRoot(line, out var reportRoot))
|
||||
{
|
||||
reportRootRelativePath = NormalizeReportRootRelativePath(reportRoot);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (TryParseSceneHeader(line, out var sceneRelativePath))
|
||||
{
|
||||
currentScene = NormalizeRelativePath(sceneRelativePath);
|
||||
currentScene = NormalizeSceneKey(reportRootRelativePath, sceneRelativePath);
|
||||
if (!scenes.ContainsKey(currentScene))
|
||||
{
|
||||
scenes[currentScene] = new Dictionary<string, KarismaSceneVariableDefinition>(StringComparer.OrdinalIgnoreCase);
|
||||
@@ -124,6 +157,25 @@ public sealed class KarismaSceneVariableCatalog
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static void MergeScenes(
|
||||
IDictionary<string, Dictionary<string, KarismaSceneVariableDefinition>> target,
|
||||
IReadOnlyDictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>> source)
|
||||
{
|
||||
foreach (var (scenePath, variables) in source)
|
||||
{
|
||||
if (!target.TryGetValue(scenePath, out var mergedVariables))
|
||||
{
|
||||
mergedVariables = new Dictionary<string, KarismaSceneVariableDefinition>(StringComparer.OrdinalIgnoreCase);
|
||||
target[scenePath] = mergedVariables;
|
||||
}
|
||||
|
||||
foreach (var (variableName, definition) in variables)
|
||||
{
|
||||
mergedVariables[variableName] = definition;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static bool TryParseSceneHeader(string line, out string sceneRelativePath)
|
||||
{
|
||||
sceneRelativePath = string.Empty;
|
||||
@@ -136,6 +188,19 @@ public sealed class KarismaSceneVariableCatalog
|
||||
return !string.IsNullOrWhiteSpace(sceneRelativePath);
|
||||
}
|
||||
|
||||
private static bool TryParseReportRoot(string line, out string reportRoot)
|
||||
{
|
||||
reportRoot = string.Empty;
|
||||
const string prefix = "- Root: `";
|
||||
if (!line.StartsWith(prefix, StringComparison.Ordinal) || !line.EndsWith('`'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
reportRoot = line.Substring(prefix.Length, line.Length - prefix.Length - 1);
|
||||
return !string.IsNullOrWhiteSpace(reportRoot);
|
||||
}
|
||||
|
||||
private static List<string> SplitMarkdownRow(string line)
|
||||
{
|
||||
var cells = line.Split('|');
|
||||
@@ -158,6 +223,11 @@ public sealed class KarismaSceneVariableCatalog
|
||||
return KarismaSceneVariableKind.Counter;
|
||||
}
|
||||
|
||||
if (IsLikelyCounterVariableName(variableName))
|
||||
{
|
||||
return KarismaSceneVariableKind.Counter;
|
||||
}
|
||||
|
||||
if (variableName.StartsWith("\uC720\uD655\uB2F9", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KarismaSceneVariableKind.VideoResource;
|
||||
@@ -179,8 +249,18 @@ public sealed class KarismaSceneVariableCatalog
|
||||
return KarismaSceneVariableKind.Text;
|
||||
}
|
||||
|
||||
private static string? FindDiscoveryReportPath()
|
||||
private static bool IsLikelyCounterVariableName(string variableName)
|
||||
{
|
||||
return variableName.StartsWith("득표율", StringComparison.Ordinal) ||
|
||||
variableName.StartsWith("투표율", StringComparison.Ordinal) ||
|
||||
variableName.StartsWith("전국투표율", StringComparison.Ordinal);
|
||||
}
|
||||
|
||||
private static IEnumerable<string> FindDiscoveryReportPaths()
|
||||
{
|
||||
var seenPaths = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var reportPaths = new List<string>();
|
||||
|
||||
foreach (var startPath in EnumerateSearchRoots())
|
||||
{
|
||||
var current = startPath;
|
||||
@@ -189,23 +269,25 @@ public sealed class KarismaSceneVariableCatalog
|
||||
foreach (var reportName in PreferredReportNames)
|
||||
{
|
||||
var candidate = Path.Combine(current, reportName);
|
||||
if (File.Exists(candidate))
|
||||
if (File.Exists(candidate) && seenPaths.Add(candidate))
|
||||
{
|
||||
return candidate;
|
||||
reportPaths.Add(candidate);
|
||||
}
|
||||
}
|
||||
|
||||
var wildcardCandidate = TryFindLatestDiscoveryReport(current);
|
||||
if (!string.IsNullOrWhiteSpace(wildcardCandidate))
|
||||
foreach (var wildcardCandidate in TryFindDiscoveryReports(current))
|
||||
{
|
||||
return wildcardCandidate;
|
||||
if (seenPaths.Add(wildcardCandidate))
|
||||
{
|
||||
reportPaths.Add(wildcardCandidate);
|
||||
}
|
||||
}
|
||||
|
||||
current = Path.GetDirectoryName(current);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return reportPaths;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> EnumerateSearchRoots()
|
||||
@@ -222,7 +304,7 @@ public sealed class KarismaSceneVariableCatalog
|
||||
return roots;
|
||||
}
|
||||
|
||||
private static string? TryFindLatestDiscoveryReport(string directoryPath)
|
||||
private static IEnumerable<string> TryFindDiscoveryReports(string directoryPath)
|
||||
{
|
||||
try
|
||||
{
|
||||
@@ -230,12 +312,51 @@ public sealed class KarismaSceneVariableCatalog
|
||||
.Where(path => !Path.GetFileName(path).Contains("SAMPLE", StringComparison.OrdinalIgnoreCase))
|
||||
.OrderByDescending(path => File.GetLastWriteTimeUtc(path))
|
||||
.ThenBy(path => path, StringComparer.OrdinalIgnoreCase)
|
||||
.FirstOrDefault();
|
||||
.ToArray();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
private static string NormalizeSceneKey(string? reportRootRelativePath, string sceneRelativePath)
|
||||
{
|
||||
var normalizedScenePath = NormalizeRelativePath(sceneRelativePath);
|
||||
if (string.IsNullOrWhiteSpace(reportRootRelativePath) ||
|
||||
string.IsNullOrWhiteSpace(normalizedScenePath) ||
|
||||
normalizedScenePath.Contains('\\'))
|
||||
{
|
||||
return normalizedScenePath;
|
||||
}
|
||||
|
||||
return NormalizeRelativePath(Path.Combine(reportRootRelativePath, normalizedScenePath));
|
||||
}
|
||||
|
||||
private static string? NormalizeReportRootRelativePath(string reportRootPath)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(reportRootPath))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
var normalized = reportRootPath.Replace('/', '\\').Trim().TrimEnd('\\');
|
||||
if (normalized.EndsWith("\\T3_Cut", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
const string marker = "\\T3_Cut\\";
|
||||
var markerIndex = normalized.IndexOf(marker, StringComparison.OrdinalIgnoreCase);
|
||||
if (markerIndex >= 0)
|
||||
{
|
||||
return NormalizeRelativePath(normalized[(markerIndex + marker.Length)..]);
|
||||
}
|
||||
|
||||
var leafFolder = Path.GetFileName(normalized);
|
||||
return string.IsNullOrWhiteSpace(leafFolder)
|
||||
? null
|
||||
: NormalizeRelativePath(leafFolder);
|
||||
}
|
||||
|
||||
private static string NormalizeRelativePath(string relativePath)
|
||||
|
||||
Reference in New Issue
Block a user