using System.Data; using System.Data.SQLite; using Dapper; namespace OCES.Resonance.Core; public static class Database { static readonly string DefaultConnectionString = "Data Source=default.db;Version=3;"; /// /// 获取数据库连接 /// /// 数据库名称(不含扩展名) /// 数据库连接 public static IDbConnection GetConnection(string dbName = "default") { string connectionString = $"Data Source={dbName}.db;Version=3;"; return new SQLiteConnection(connectionString); } /// /// 初始化数据库表结构 /// public static void InitializeDatabase() { using var connection = GetConnection(); connection.Open(); const string sql = @" CREATE TABLE IF NOT EXISTS sounds ( id INTEGER PRIMARY KEY AUTOINCREMENT, unique_id TEXT NOT NULL UNIQUE, short_id TEXT, md5 TEXT NOT NULL, path TEXT NOT NULL, filename TEXT NOT NULL, folder TEXT NOT NULL, directory TEXT NOT NULL, duration REAL NOT NULL, total_samples INTEGER NOT NULL, bit_depth INTEGER NOT NULL, channels INTEGER NOT NULL, sample_rate INTEGER NOT NULL, type TEXT NOT NULL, date_added TEXT NOT NULL, original_modification_date TEXT NOT NULL, origination_time TEXT NOT NULL, bpm REAL, frame_rate TEXT, timecode INTEGER, description TEXT, category TEXT, subcategory TEXT, cat_id TEXT, category_full TEXT, genre TEXT, style TEXT, mood TEXT, keywords TEXT, rating INTEGER, artist TEXT, composer TEXT, designer TEXT, recordist TEXT, publisher TEXT, manufacturer TEXT, originator TEXT, originator_ref TEXT, project_name TEXT, library TEXT, cd_title TEXT, track_title TEXT, episode TEXT, scene TEXT, take TEXT, tape TEXT, cue_number INTEGER, sync_point INTEGER, release_date TEXT, track_year TEXT, is_edited INTEGER, is_split INTEGER, location TEXT, [group] TEXT, markers TEXT, comments TEXT, notes TEXT, copyright TEXT, coding_history TEXT, microphone TEXT, mic_perspective TEXT, user1 TEXT, user2 TEXT, user3 TEXT, user4 TEXT, user5 TEXT, user6 TEXT, user7 TEXT, user8 TEXT, INDEX idx_md5 (md5), INDEX idx_path (path), INDEX idx_unique_id (unique_id) ); "; connection.Execute(sql); } /// /// 添加单条音频记录 /// /// 音频元数据 /// 是否添加成功 public static bool AddEntry(AudioFileMeta meta) { try { using var connection = GetConnection(); connection.Open(); const string sql = @" INSERT INTO audio_files ( unique_id, short_id, md5, path, filename, folder, directory, duration, total_samples, bit_depth, channels, sample_rate, type, date_added, original_modification_date, origination_time, bpm, frame_rate, timecode, description, category, subcategory, cat_id, category_full, genre, style, mood, keywords, rating, artist, composer, designer, recordist, publisher, manufacturer, originator, originator_ref, project_name, library, cd_title, track_title, episode, scene, take, tape, cue_number, sync_point, release_date, track_year, is_edited, is_split, location, [group], markers, comments, notes, copyright, coding_history, microphone, mic_perspective, user1, user2, user3, user4, user5, user6, user7, user8 ) VALUES ( @UniqueId, @ShortId, @Md5, @Path, @Filename, @Folder, @Directory, @Duration, @TotalSamples, @BitDepth, @Channels, @SampleRate, @Type, @DateAdded, @OriginalModificationDate, @OriginationTime, @Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory, @CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating, @Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer, @BwfOriginator, @BwfOriginatorRef, @ProjectName, @Library, @CdTitle, @TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint, @ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group, @Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone, @MicPerspective, @User1, @User2, @User3, @User4, @User5, @User6, @User7, @User8 ); "; connection.Execute(sql, meta); return true; } catch (Exception) { return false; } } /// /// 批量添加音频记录 /// /// 音频元数据列表 /// 成功添加的记录数 public static int AddEntries(IEnumerable entries) { var count = 0; using var connection = GetConnection(); connection.Open(); using var transaction = connection.BeginTransaction(); try { const string sql = @" INSERT INTO audio_files ( unique_id, short_id, md5, path, filename, folder, directory, duration, total_samples, bit_depth, channels, sample_rate, type, date_added, original_modification_date, origination_time, bpm, frame_rate, timecode, description, category, subcategory, cat_id, category_full, genre, style, mood, keywords, rating, artist, composer, designer, recordist, publisher, manufacturer, originator, originator_ref, project_name, library, cd_title, track_title, episode, scene, take, tape, cue_number, sync_point, release_date, track_year, is_edited, is_split, location, [group], markers, comments, notes, copyright, coding_history, microphone, mic_perspective, user1, user2, user3, user4, user5, user6, user7, user8 ) VALUES ( @UniqueId, @ShortId, @Md5, @Path, @Filename, @Folder, @Directory, @Duration, @TotalSamples, @BitDepth, @Channels, @SampleRate, @Type, @DateAdded, @OriginalModificationDate, @OriginationTime, @Bpm, @FrameRate, @Timecode, @Description, @Category, @Subcategory, @CatId, @CategoryFull, @Genre, @Style, @Mood, @Keywords, @Rating, @Artist, @Composer, @Designer, @Recordist, @Publisher, @Manufacturer, @BwfOriginator, @BwfOriginatorRef, @ProjectName, @Library, @CdTitle, @TrackTitle, @Episode, @Scene, @Take, @Tape, @CueNumber, @SyncPoint, @ReleaseDate, @TrackYear, @IsEdited, @IsSplit, @Location, @Group, @Markers, @Comments, @Notes, @Copyright, @CodingHistory, @Microphone, @MicPerspective, @User1, @User2, @User3, @User4, @User5, @User6, @User7, @User8 ); "; foreach (var entry in entries) { connection.Execute(sql, entry, transaction); count++; } transaction.Commit(); } catch (Exception) { transaction.Rollback(); throw; } return count; } /// /// 检查记录是否已存在 /// /// 文件 MD5 值 /// 文件路径 /// 是否存在 public static bool EntryExists(string md5, string filePath) { using var connection = GetConnection(); connection.Open(); const string sql = @" SELECT COUNT(*) FROM audio_files WHERE md5 = @Md5 OR path = @Path; "; var count = connection.ExecuteScalar(sql, new { Md5 = md5, Path = filePath }); return count > 0; } }