WIP: metadata class rework
This commit is contained in:
@@ -54,6 +54,9 @@ public class AudioFileMeta
|
||||
|
||||
#endregion
|
||||
|
||||
///<summary>声道配置</summary>
|
||||
public string? ChannelLayout { get; set; }
|
||||
|
||||
/// <summary>短ID,便于人工识别或显示的简短标识</summary>
|
||||
public string? ShortId { get; set; }
|
||||
|
||||
@@ -114,10 +117,14 @@ public class AudioFileMeta
|
||||
public string? Manufacturer { get; set; }
|
||||
|
||||
/// <summary>来源方,原始创建者或来源机构</summary>
|
||||
public string? Originator { get; set; }
|
||||
public string? BwfOriginator { get; set; }
|
||||
|
||||
/// <summary>来源引用,原始来源的参考编号</summary>
|
||||
public string? OriginatorRef { get; set; }
|
||||
public string? BwfOriginatorRef { get; set; }
|
||||
|
||||
public DateTime? BwfDate { get; set; }
|
||||
|
||||
public string? BwfDescription { get; set; }
|
||||
|
||||
/// <summary>项目名称,所属制作项目</summary>
|
||||
public string? ProjectName { get; set; }
|
||||
|
||||
@@ -32,7 +32,6 @@ public class AudioFileMetaValidator
|
||||
|
||||
// 验证数值字段
|
||||
ValidatePositiveValue(meta.Duration, "Duration", errors);
|
||||
ValidatePositiveValue(meta.TotalSamples, "TotalSamples", errors);
|
||||
ValidatePositiveValue(meta.BitDepth, "BitDepth", errors);
|
||||
ValidatePositiveValue(meta.Channels, "Channels", errors);
|
||||
ValidatePositiveValue(meta.SampleRate, "SampleRate", errors);
|
||||
|
||||
@@ -1,125 +0,0 @@
|
||||
using System.Security.Cryptography;
|
||||
|
||||
namespace OCES.Resonance.Core;
|
||||
|
||||
/// <summary>
|
||||
/// 音频库管理服务,协调扫描、读取和入库的完整流程
|
||||
/// </summary>
|
||||
public class AudioLibraryService
|
||||
{
|
||||
readonly AudioFileScanner _scanner = new();
|
||||
readonly AudioMetadataReader _metadataReader = new();
|
||||
|
||||
/// <summary>
|
||||
/// 扫描目录并将结果添加到数据库
|
||||
/// </summary>
|
||||
/// <param name="directoryPath">要扫描的目录路径</param>
|
||||
/// <param name="databaseName">数据库名称(不含扩展名)</param>
|
||||
/// <param name="skipExisting">是否跳过已存在的文件</param>
|
||||
/// <returns>扫描结果统计</returns>
|
||||
public async Task<ScanResult> ScanAndImportToLibrary(
|
||||
string directoryPath,
|
||||
string databaseName = "default",
|
||||
bool skipExisting = true)
|
||||
{
|
||||
var result = new ScanResult
|
||||
{
|
||||
TotalFiles = 0,
|
||||
SuccessCount = 0,
|
||||
SkipCount = 0,
|
||||
ErrorCount = 0,
|
||||
Errors = [],
|
||||
};
|
||||
|
||||
// 初始化数据库
|
||||
Database.InitializeDatabase();
|
||||
|
||||
// 扫描所有音频文件
|
||||
List<string> audioFiles = this._scanner.ScanDirectory(directoryPath).ToList();
|
||||
result.TotalFiles = audioFiles.Count;
|
||||
|
||||
if (audioFiles.Count == 0)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
List<AudioFileMeta> metadataList = [];
|
||||
|
||||
// 读取每个文件的元数据
|
||||
foreach (string filePath in audioFiles)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 计算 MD5 用于查重
|
||||
string md5 = CalculateMd5ForFile(filePath);
|
||||
|
||||
// 读取元数据
|
||||
AudioFileMeta metadata = this._metadataReader.ReadMetadata(filePath);
|
||||
metadataList.Add(metadata);
|
||||
result.SuccessCount++;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.ErrorCount++;
|
||||
result.Errors.Add($"读取失败 {filePath}: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 批量入库
|
||||
if (metadataList.Count <= 0)
|
||||
return await Task.FromResult(result);
|
||||
{
|
||||
try
|
||||
{
|
||||
Database.AddEntries(metadataList);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
result.Errors.Add($"批量入库失败:{ex.Message}");
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
return await Task.FromResult(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算文件 MD5(用于查重,不创建完整 AudioFileMeta 对象)
|
||||
/// </summary>
|
||||
private static string CalculateMd5ForFile(string filePath)
|
||||
{
|
||||
using MD5 md5 = MD5.Create();
|
||||
using FileStream stream = File.OpenRead(filePath);
|
||||
byte[] hash = md5.ComputeHash(stream);
|
||||
return Convert.ToHexString(hash);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 扫描结果统计
|
||||
/// </summary>
|
||||
public class ScanResult
|
||||
{
|
||||
/// <summary>扫描到的文件总数</summary>
|
||||
public int TotalFiles { get; set; }
|
||||
|
||||
/// <summary>成功入库的文件数</summary>
|
||||
public int SuccessCount { get; set; }
|
||||
|
||||
/// <summary>跳过的文件数(已存在)</summary>
|
||||
public int SkipCount { get; set; }
|
||||
|
||||
/// <summary>读取失败的文件数</summary>
|
||||
public int ErrorCount { get; set; }
|
||||
|
||||
/// <summary>错误详情列表</summary>
|
||||
public List<string> Errors { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// 获取人类可读的统计报告
|
||||
/// </summary>
|
||||
public string GetSummary()
|
||||
{
|
||||
return $"扫描完成:共 {TotalFiles} 个文件,成功 {SuccessCount} 个,跳过 {SkipCount} 个,失败 {ErrorCount} 个";
|
||||
}
|
||||
}
|
||||
@@ -62,8 +62,8 @@ public class AudioMetadataReader
|
||||
|
||||
// BWF 特定字段 (通过附加数据获取)
|
||||
CodingHistory = GetBwfField(track, "CodingHistory"),
|
||||
Originator = GetBwfField(track, "Originator"),
|
||||
OriginatorRef = GetBwfField(track, "OriginatorRef"),
|
||||
BwfOriginator = GetBwfField(track, "BwfOriginator"),
|
||||
BwfOriginatorRef = GetBwfField(track, "BwfOriginatorRef"),
|
||||
};
|
||||
|
||||
return meta;
|
||||
|
||||
@@ -141,7 +141,7 @@ public static class Database
|
||||
@Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory,
|
||||
@CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating,
|
||||
@Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer,
|
||||
@Originator, @OriginatorRef, @ProjectName, @Library, @CdTitle,
|
||||
@BwfOriginator, @BwfOriginatorRef, @ProjectName, @Library, @CdTitle,
|
||||
@TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint,
|
||||
@ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group,
|
||||
@Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone,
|
||||
@@ -192,7 +192,7 @@ public static class Database
|
||||
@Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory,
|
||||
@CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating,
|
||||
@Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer,
|
||||
@Originator, @OriginatorRef, @ProjectName, @Library, @CdTitle,
|
||||
@BwfOriginator, @BwfOriginatorRef, @ProjectName, @Library, @CdTitle,
|
||||
@TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint,
|
||||
@ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group,
|
||||
@Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone,
|
||||
|
||||
Reference in New Issue
Block a user