diff --git a/CHANGELIST.md b/CHANGELIST.md
index d185b402..9677ffc4 100644
--- a/CHANGELIST.md
+++ b/CHANGELIST.md
@@ -12,6 +12,7 @@
- Update RedumpLib to 1.10.2
- Fix name conflict
- Sync with Redump wiki
+- Add BD protection info, fix Cover ID setting
### 3.7.1 (2026-03-30)
diff --git a/MPF.Frontend/Tools/PhysicalTool.cs b/MPF.Frontend/Tools/PhysicalTool.cs
index 31c916c8..b05e283f 100644
--- a/MPF.Frontend/Tools/PhysicalTool.cs
+++ b/MPF.Frontend/Tools/PhysicalTool.cs
@@ -6,6 +6,7 @@ using System.Text;
using System.Text.RegularExpressions;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
+using SabreTools.Hashing;
using SabreTools.IO;
using SabreTools.RedumpLib.Data;
@@ -106,6 +107,47 @@ namespace MPF.Frontend.Tools
#region BD-Video
+ ///
+ /// Get Blu-ray protection information
+ ///
+ /// Drive to extract information from
+ /// Formatted string representing the protection on success, null otherwise
+ public static string? GetBluRayProtection(Drive? drive)
+ {
+ // If there's no drive path, we can't get information
+ if (string.IsNullOrEmpty(drive?.Name))
+ return null;
+
+ // If the folder no longer exists, we can't get information
+ if (!Directory.Exists(drive!.Name))
+ return null;
+
+ // Generate unit key file hash
+ string? unitKeyFileHash = null;
+#if NET20 || NET35
+ string unitKeyPath = Path.Combine(Path.Combine(drive.Name, "AACS"), "Unit_Key_RO.inf ");
+#else
+ string unitKeyPath = Path.Combine(drive.Name, "AACS", "Unit_Key_RO.inf ");
+#endif
+ if (File.Exists(unitKeyPath))
+ unitKeyFileHash = HashTool.GetFileHash(unitKeyPath, HashType.SHA1)?.ToUpperInvariant();
+
+ // Determine if BEE is set
+ bool busEncryptionEnabled = GetBusEncryptionEnabled(drive);
+
+ // Generate the output strings
+ var sb = new StringBuilder();
+
+ sb.AppendLine($"Media Key: (OPTIONAL)");
+ sb.AppendLine($"Volume ID: (OPTIONAL)");
+ sb.AppendLine($"Volume Unique Key: (OPTIONAL)");
+ sb.AppendLine($"Unit Key File Hash (DiscID): {unitKeyFileHash ?? "(OPTIONAL)"}");
+ if (busEncryptionEnabled)
+ sb.AppendLine("Bus encryption enabled flag set");
+
+ return sb.ToString();
+ }
+
///
/// Get if the Bus Encryption Enabled (BEE) flag is set in a path
///
@@ -117,7 +159,7 @@ namespace MPF.Frontend.Tools
if (string.IsNullOrEmpty(drive?.Name))
return false;
- // If the folder no longer exists, we can't get exe name
+ // If the folder no longer exists, we can't get BEE flag
if (!Directory.Exists(drive!.Name))
return false;
diff --git a/MPF.Frontend/Tools/SubmissionGenerator.cs b/MPF.Frontend/Tools/SubmissionGenerator.cs
index e3c351fd..2015057f 100644
--- a/MPF.Frontend/Tools/SubmissionGenerator.cs
+++ b/MPF.Frontend/Tools/SubmissionGenerator.cs
@@ -834,11 +834,11 @@ namespace MPF.Frontend.Tools
case RedumpSystem.BDVideo:
info.CommonDiscInfo.Category ??= DiscCategory.Video;
- bool bee = PhysicalTool.GetBusEncryptionEnabled(drive);
- if (bee && string.IsNullOrEmpty(info.CopyProtection.Protection))
- info.CopyProtection.Protection = "Bus encryption enabled flag set";
- else if (bee)
- info.CopyProtection.Protection += "\nBus encryption enabled flag set";
+ string? bdProtection = PhysicalTool.GetBluRayProtection(drive);
+ if (bdProtection is not null && string.IsNullOrEmpty(info.CopyProtection.Protection))
+ info.CopyProtection.Protection = bdProtection;
+ else if (bdProtection is not null)
+ info.CopyProtection.Protection += $"\n{bdProtection}";
else
info.CopyProtection.Protection ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
@@ -942,17 +942,20 @@ namespace MPF.Frontend.Tools
case RedumpSystem.MicrosoftXbox:
case RedumpSystem.MicrosoftXbox360:
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
+ if (!info.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DiscHologramID))
+ info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] = addPlaceholders ? RequiredIfExistsValue : string.Empty;
break;
case RedumpSystem.MicrosoftXboxOne:
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
+ if (!info.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DiscHologramID))
+ info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] = addPlaceholders ? RequiredIfExistsValue : string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename] = PhysicalTool.GetXboxFilenames(drive) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.TitleID] = PhysicalTool.GetXboxTitleID(drive) ?? string.Empty;
break;
case RedumpSystem.MicrosoftXboxSeriesXS:
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] ??= addPlaceholders ? RequiredIfExistsValue : string.Empty;
+ if (!info.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.DiscHologramID))
+ info.CommonDiscInfo.CommentsSpecialFields[SiteCode.DiscHologramID] = addPlaceholders ? RequiredIfExistsValue : string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.Filename] = PhysicalTool.GetXboxFilenames(drive) ?? string.Empty;
info.CommonDiscInfo.CommentsSpecialFields[SiteCode.TitleID] = PhysicalTool.GetXboxTitleID(drive) ?? string.Empty;
break;
@@ -981,7 +984,9 @@ namespace MPF.Frontend.Tools
case RedumpSystem.NintendoGameCube:
case RedumpSystem.NintendoWii:
- info.CommonDiscInfo.CommentsSpecialFields[SiteCode.CoverID] ??= addPlaceholders ? RequiredValue : string.Empty;
+ if (!info.CommonDiscInfo.CommentsSpecialFields.ContainsKey(SiteCode.CoverID))
+ info.CommonDiscInfo.CommentsSpecialFields[SiteCode.CoverID] = addPlaceholders ? RequiredIfExistsValue : string.Empty;
+
break;
case RedumpSystem.SegaChihiro: