컷별 데이터 연계
This commit is contained in:
229
Tornado3_2026Election/Services/KarismaSceneVariableCatalog.cs
Normal file
229
Tornado3_2026Election/Services/KarismaSceneVariableCatalog.cs
Normal file
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace Tornado3_2026Election.Services;
|
||||
|
||||
public sealed class KarismaSceneVariableCatalog
|
||||
{
|
||||
private static readonly IReadOnlyDictionary<string, KarismaSceneVariableDefinition> EmptySceneVariables =
|
||||
new Dictionary<string, KarismaSceneVariableDefinition>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
private readonly IReadOnlyDictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>> _scenes;
|
||||
|
||||
private KarismaSceneVariableCatalog(
|
||||
IReadOnlyDictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>> scenes)
|
||||
{
|
||||
_scenes = scenes;
|
||||
}
|
||||
|
||||
public static KarismaSceneVariableCatalog Load(LogService logService)
|
||||
{
|
||||
var reportPath = FindDiscoveryReportPath();
|
||||
if (string.IsNullOrWhiteSpace(reportPath) || !File.Exists(reportPath))
|
||||
{
|
||||
logService.Warning("Karisma scene variable catalog report was not found. Falling back to runtime value heuristics.");
|
||||
return new KarismaSceneVariableCatalog(
|
||||
new Dictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>>(StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var scenes = ParseReport(reportPath);
|
||||
logService.Info($"Karisma scene variable catalog loaded: scenes={scenes.Count} source='{reportPath}'.");
|
||||
return new KarismaSceneVariableCatalog(scenes);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logService.Warning($"Failed to load Karisma scene variable catalog: {ex.Message}");
|
||||
return new KarismaSceneVariableCatalog(
|
||||
new Dictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>>(StringComparer.OrdinalIgnoreCase));
|
||||
}
|
||||
}
|
||||
|
||||
public IReadOnlyDictionary<string, KarismaSceneVariableDefinition> GetSceneVariables(string t3CutPath, string scenePath)
|
||||
{
|
||||
if (_scenes.Count == 0 ||
|
||||
string.IsNullOrWhiteSpace(t3CutPath) ||
|
||||
string.IsNullOrWhiteSpace(scenePath))
|
||||
{
|
||||
return EmptySceneVariables;
|
||||
}
|
||||
|
||||
var relativePath = NormalizeRelativePath(Path.GetRelativePath(t3CutPath, scenePath));
|
||||
return _scenes.TryGetValue(relativePath, out var variables)
|
||||
? variables
|
||||
: EmptySceneVariables;
|
||||
}
|
||||
|
||||
private static IReadOnlyDictionary<string, IReadOnlyDictionary<string, KarismaSceneVariableDefinition>> ParseReport(string reportPath)
|
||||
{
|
||||
var scenes = new Dictionary<string, Dictionary<string, KarismaSceneVariableDefinition>>(StringComparer.OrdinalIgnoreCase);
|
||||
string? currentScene = null;
|
||||
|
||||
foreach (var rawLine in File.ReadLines(reportPath, Encoding.UTF8))
|
||||
{
|
||||
var line = rawLine.Trim();
|
||||
if (TryParseSceneHeader(line, out var sceneRelativePath))
|
||||
{
|
||||
currentScene = NormalizeRelativePath(sceneRelativePath);
|
||||
if (!scenes.ContainsKey(currentScene))
|
||||
{
|
||||
scenes[currentScene] = new Dictionary<string, KarismaSceneVariableDefinition>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(currentScene) || !line.StartsWith('|'))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var cells = SplitMarkdownRow(line);
|
||||
if (cells.Count < 4 ||
|
||||
string.Equals(cells[0], "Variable", StringComparison.OrdinalIgnoreCase) ||
|
||||
string.Equals(cells[0], "---", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var variableName = cells[0];
|
||||
if (string.IsNullOrWhiteSpace(variableName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var method = cells[1];
|
||||
var payload = cells[2];
|
||||
var result = cells[3];
|
||||
if (!string.Equals(result, "RESULT_SUCCESS", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
scenes[currentScene][variableName] = new KarismaSceneVariableDefinition(
|
||||
variableName,
|
||||
ResolveKind(variableName, method, payload),
|
||||
method,
|
||||
payload);
|
||||
}
|
||||
|
||||
return scenes.ToDictionary(
|
||||
pair => pair.Key,
|
||||
pair => (IReadOnlyDictionary<string, KarismaSceneVariableDefinition>)pair.Value,
|
||||
StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private static bool TryParseSceneHeader(string line, out string sceneRelativePath)
|
||||
{
|
||||
sceneRelativePath = string.Empty;
|
||||
if (!line.StartsWith("### `", StringComparison.Ordinal) || !line.EndsWith('`'))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
sceneRelativePath = line.Substring(5, line.Length - 6);
|
||||
return !string.IsNullOrWhiteSpace(sceneRelativePath);
|
||||
}
|
||||
|
||||
private static List<string> SplitMarkdownRow(string line)
|
||||
{
|
||||
var cells = line.Split('|');
|
||||
if (cells.Length <= 2)
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
return cells
|
||||
.Skip(1)
|
||||
.Take(cells.Length - 2)
|
||||
.Select(cell => cell.Trim())
|
||||
.ToList();
|
||||
}
|
||||
|
||||
private static KarismaSceneVariableKind ResolveKind(string variableName, string method, string payload)
|
||||
{
|
||||
if (string.Equals(method, "SetCounterNumberKey", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KarismaSceneVariableKind.Counter;
|
||||
}
|
||||
|
||||
if (variableName.StartsWith("\uC720\uD655\uB2F9", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KarismaSceneVariableKind.VideoResource;
|
||||
}
|
||||
|
||||
if (payload.EndsWith(".vrv", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KarismaSceneVariableKind.VideoResource;
|
||||
}
|
||||
|
||||
if (payload.EndsWith(".png", StringComparison.OrdinalIgnoreCase) ||
|
||||
payload.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase) ||
|
||||
payload.EndsWith(".jpeg", StringComparison.OrdinalIgnoreCase) ||
|
||||
payload.EndsWith(".webp", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return KarismaSceneVariableKind.Image;
|
||||
}
|
||||
|
||||
return KarismaSceneVariableKind.Text;
|
||||
}
|
||||
|
||||
private static string? FindDiscoveryReportPath()
|
||||
{
|
||||
foreach (var startPath in EnumerateSearchRoots())
|
||||
{
|
||||
var current = startPath;
|
||||
for (var depth = 0; depth < 8 && !string.IsNullOrWhiteSpace(current); depth++)
|
||||
{
|
||||
var candidate = Path.Combine(current, "TSCN_VARIABLE_DISCOVERY_E_DRIVE.md");
|
||||
if (File.Exists(candidate))
|
||||
{
|
||||
return candidate;
|
||||
}
|
||||
|
||||
current = Path.GetDirectoryName(current);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> EnumerateSearchRoots()
|
||||
{
|
||||
var roots = new List<string> { AppContext.BaseDirectory };
|
||||
try
|
||||
{
|
||||
roots.Add(Directory.GetCurrentDirectory());
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
return roots;
|
||||
}
|
||||
|
||||
private static string NormalizeRelativePath(string relativePath)
|
||||
{
|
||||
return relativePath
|
||||
.Replace('/', '\\')
|
||||
.Trim();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed record KarismaSceneVariableDefinition(
|
||||
string Name,
|
||||
KarismaSceneVariableKind Kind,
|
||||
string Method,
|
||||
string Payload);
|
||||
|
||||
public enum KarismaSceneVariableKind
|
||||
{
|
||||
Text,
|
||||
Image,
|
||||
VideoResource,
|
||||
Counter
|
||||
}
|
||||
Reference in New Issue
Block a user