diff --git a/tools/ImportBuddy/source/ImportBuddy/ImportBuddy/Program.cs b/tools/ImportBuddy/source/ImportBuddy/ImportBuddy/Program.cs
index 07e682249..be03c655c 100644
--- a/tools/ImportBuddy/source/ImportBuddy/ImportBuddy/Program.cs
+++ b/tools/ImportBuddy/source/ImportBuddy/ImportBuddy/Program.cs
@@ -48,7 +48,7 @@ static IHostBuilder CreateHostBuilder(string[] args) =>
config.AddJsonFile("appsettings.json", optional: false);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
- config.AddJsonFile("appSettings.linux.json", optional: false);
+ config.AddJsonFile("appsettings.linux.json", optional: false);
}
})
.ConfigureLogging(logging =>
diff --git a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/CsvEnumerator.cs b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/CsvEnumerator.cs
new file mode 100644
index 000000000..2bd989964
--- /dev/null
+++ b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/CsvEnumerator.cs
@@ -0,0 +1,165 @@
+namespace MakeMkv;
+
+///
+/// Iterates over comma separated values in a single line of text.
+///
+public sealed class CsvEnumerator
+{
+ private readonly String _span;
+
+ private readonly Boolean _isInitialized;
+
+ private Int32 _currentStart;
+ private Int32 _currentEnd;
+
+ ///
+ public ReadOnlySpan Current => _span.AsSpan()[_currentStart.._currentEnd];
+
+ ///
+ /// Creates a new over a span of characters.
+ ///
+ public CsvEnumerator(String span)
+ {
+ _isInitialized = true;
+ _span = span;
+ _currentStart = 0;
+ _currentEnd = -1;
+ }
+
+ ///
+ public Boolean MoveNext()
+ {
+ Int32 start = _currentEnd + 1;
+ if (!_isInitialized || start > _span.Length)
+ {
+ return false;
+ }
+
+ var slice = _span[start..];
+ _currentStart = start;
+
+ Boolean quoted = false;
+ Boolean escaped = false;
+ Int32 i;
+ for (i = 0; i < slice.Length; i++)
+ {
+ Char curChar = slice[i];
+ if (curChar == '\\')
+ {
+ if (!escaped)
+ {
+ escaped = true;
+ continue;
+ }
+ }
+ else if (curChar == '"')
+ {
+ if (!escaped)
+ {
+ quoted = !quoted;
+ }
+ }
+ else if (curChar == ',')
+ {
+ if (!quoted)
+ {
+ break;
+ }
+ }
+
+ escaped = false;
+ }
+
+ Int32 elementLength = i;
+
+ _currentEnd = _currentStart + elementLength;
+ return true;
+ }
+
+ ///
+ /// Returns an enumerator suitable for use in foreach loops.
+ ///
+ public CsvEnumerator GetEnumerator() => this;
+
+ ///
+ /// Attempts to advance the enumerator and parse the value as an .
+ ///
+ /// The parsed value, or the value if enumeration or parsing failed.
+ public int TryParseInt()
+ {
+ if (MoveNext())
+ {
+ if (Int32.TryParse(Current, out int val))
+ {
+ return val;
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// Attempts to advance the enumerator and parse the value as a .
+ ///
+ /// The parsed value, or if enumeration or parsing failed.
+ public bool TryParseBoolean()
+ {
+ if (MoveNext())
+ {
+ if (Int32.TryParse(Current, out int val))
+ {
+ return val != 256 && val != 999 && val > 0;
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// Attempts to advance the enumerator and parse the value as a .
+ ///
+ /// The parsed value, or if enumeration or parsing failed.
+ public string? GetString()
+ {
+ if (MoveNext())
+ {
+ return Current.ToString().Replace("\"", string.Empty);
+ }
+
+ return default;
+ }
+
+ ///
+ /// Attempts to advance the enumerator and parse the value as a .
+ ///
+ /// The parsed value, or the value if enumeration or parsing failed.
+ public DateTime TryParseDateTime()
+ {
+ if (MoveNext())
+ {
+ if (DateTime.TryParse(Current, out DateTime val))
+ {
+ return val;
+ }
+ }
+
+ return default;
+ }
+
+ ///
+ /// Attempts to advance the enumerator and parse the value as a .
+ ///
+ /// The parsed value, or the value if enumeration or parsing failed.
+ public long TryParseLong()
+ {
+ if (MoveNext())
+ {
+ if (Int64.TryParse(Current, out long val))
+ {
+ return val;
+ }
+ }
+
+ return default;
+ }
+}
diff --git a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/LogLine.cs b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/LogLine.cs
index c9fc38904..f2499e1bf 100644
--- a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/LogLine.cs
+++ b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/LogLine.cs
@@ -28,7 +28,7 @@ protected static int TryParseInt(int index, string[] parts)
{
if (index < parts.Length)
{
- if(Int32.TryParse(parts[index], out int val))
+ if (Int32.TryParse(parts[index], out int val))
{
return val;
}
diff --git a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/MessageLogLine.cs b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/MessageLogLine.cs
index ca89011c9..41d38a5b6 100644
--- a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/MessageLogLine.cs
+++ b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/LogParser/LogLines/MessageLogLine.cs
@@ -18,25 +18,21 @@ public MessageLogLine() : base("MSG")
public static MessageLogLine Parse(string line)
{
- string[] parts = line.Substring(4).Split(',');
+ var enumerator = new CsvEnumerator(line[4..]);
var result = new MessageLogLine
{
- Code = GetString(0, parts),
- Flags = GetString(1, parts),
- ParamCount = TryParseInt(2, parts),
- Message = GetString(3, parts),
- MessageTemplate = GetString(4, parts),
+ Code = enumerator.GetString(),
+ Flags = enumerator.GetString(),
+ ParamCount = enumerator.TryParseInt(),
+ Message = enumerator.GetString(),
+ MessageTemplate = enumerator.GetString(),
OriginalLine = line
};
- for (int i = 5; i < parts.Length; i++)
+ while (enumerator.GetString() is { } val)
{
- string? val = GetString(i, parts);
- if (val != null)
- {
- result.Params.Add(val);
- }
+ result.Params.Add(val);
}
return result;
diff --git a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/MakeMkvHelper.cs b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/MakeMkvHelper.cs
index 8e55352fb..42d7b8d1a 100644
--- a/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/MakeMkvHelper.cs
+++ b/tools/ImportBuddy/source/ImportBuddy/TheDiscDb.MakeMkv/MakeMkvHelper.cs
@@ -1,4 +1,6 @@
-namespace TheDiscDb.Tools.MakeMkv
+using MakeMkv;
+
+namespace TheDiscDb.Tools.MakeMkv
{
using System;
using System.Collections.Generic;
@@ -42,7 +44,7 @@ public async Task WriteLogs(int driveIndex, string path, bool cleanLogs = true)
await Task.Delay(200); // wait for file handle to be released
try
{
- await CleanLogs(path);
+ await CleanLogs(driveIndex, path);
}
catch (IOException e)
{
@@ -51,19 +53,77 @@ public async Task WriteLogs(int driveIndex, string path, bool cleanLogs = true)
}
}
- public async Task CleanLogs(string path, CancellationToken cancellationToken = default)
+ public async Task CleanLogs(int driveIndex, string path, CancellationToken cancellationToken = default)
{
var output = new List();
var lines = await this.fileSystem.File.ReadAllLines(path, cancellationToken);
bool fileChanged = false;
- foreach (var line in lines)
+ foreach (var originalLine in lines)
{
- if (string.IsNullOrWhiteSpace(line) || line.StartsWith("MSG") || line.StartsWith("DRV"))
+ // Remove empty lines from the output
+ if (originalLine == string.Empty)
{
fileChanged = true;
continue;
}
+ string? line = null;
+ if (originalLine.StartsWith("MSG"))
+ {
+ var msgLine = MessageLogLine.Parse(originalLine);
+ var (toRedact, replacement) = msgLine.Code switch
+ {
+ // The debug file path is usually in the user's home directory
+ "1004" => (msgLine.Params[0], "***"),
+ // The drive name can sometimes contain a serial number
+ "2003" => (msgLine.Params[1], "***"),
+ // The .MakeMKV folder is usually in the user's home directory
+ "3338" => (msgLine.Params[1], "***"),
+ // No other messages are known to contain sensitive information
+ _ => (null, ""),
+ };
+
+ if (toRedact is not null)
+ {
+ line = originalLine.Replace(toRedact, replacement);
+ }
+ }
+ else if (originalLine.StartsWith("DRV"))
+ {
+ // DRV:1,2,999,12,"BD-ROM HL-DT-ST BDDVDRW UH12NS30 1.03","42","E:"
+ // becomes
+ // DRV:1,2,999,12,"redacted by ImportBuddy","42","/redacted/by/ImportBuddy"
+ var driveLine = DriveScanLogLine.Parse(originalLine);
+ if (!string.IsNullOrEmpty(driveLine.DriveName))
+ {
+ // Always redact the drive name, since it could contain a serial number
+ line = originalLine.Replace(driveLine.DriveName, "***");
+
+ // Only keep the disc name for the active drive
+ if (driveLine.Index != driveIndex && !string.IsNullOrEmpty(driveLine.DiscName))
+ {
+ line = line.Replace(driveLine.DiscName, "***");
+ }
+
+ // Always redact the drive letter or path
+ if (!string.IsNullOrEmpty(driveLine.DriveLetter))
+ {
+ line = line.Replace(driveLine.DriveLetter, "***");
+ }
+ }
+ }
+
+ if (line is null)
+ {
+ // This line wasn't modified, use the original line
+ line = originalLine;
+ }
+ else
+ {
+ // Something was changed, ensure the file is overwritten
+ fileChanged = true;
+ }
+
output.Add(line);
}