Files
Resonance/src/Core/Database.cs
T
2026-05-12 19:19:46 +08:00

240 lines
9.3 KiB
C#
Executable File

using System.Data;
using System.Data.SQLite;
using Dapper;
namespace OCES.Resonance.Core;
public static class Database
{
static readonly string DefaultConnectionString = "Data Source=default.rdb;Version=3;";
/// <summary>
/// 获取数据库连接
/// </summary>
/// <param name="dbName">数据库名称(不含扩展名)</param>
/// <returns>数据库连接</returns>
public static IDbConnection GetConnection(string dbName = "default")
{
string connectionString = $"Data Source={dbName}.rdb;Version=3;";
return new SQLiteConnection(connectionString);
}
/// <summary>
/// 初始化数据库表结构
/// </summary>
public static void InitializeDatabase()
{
using var connection = GetConnection();
connection.Open();
const string sql = @"
CREATE TABLE IF NOT EXISTS audio_files (
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);
}
/// <summary>
/// 添加单条音频记录
/// </summary>
/// <param name="meta">音频元数据</param>
/// <returns>是否添加成功</returns>
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, @BwfCodingHistory, @Microphone,
@MicPerspective, @User1, @User2, @User3, @User4, @User5, @User6, @User7, @User8
);
";
connection.Execute(sql, meta);
return true;
}
catch (Exception)
{
return false;
}
}
/// <summary>
/// 批量添加音频记录
/// </summary>
/// <param name="entries">音频元数据列表</param>
/// <returns>成功添加的记录数</returns>
public static int AddEntries(IEnumerable<AudioFileMeta> 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, @BwfCodingHistory, @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;
}
/// <summary>
/// 检查记录是否已存在
/// </summary>
/// <param name="md5">文件 MD5 值</param>
/// <param name="filePath">文件路径</param>
/// <returns>是否存在</returns>
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<int>(sql, new { Md5 = md5, Path = filePath });
return count > 0;
}
}