// lib/database/song_database.dart import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path_provider/path_provider.dart'; class SongDatabase { static final SongDatabase _instance = SongDatabase._internal(); factory SongDatabase() => _instance; SongDatabase._internal(); static Database? _database; Future get database async { if (_database != null) return _database!; _database = await _initDatabase(); return _database!; } Future _initDatabase() async { final dir = await getApplicationDocumentsDirectory(); final path = join(dir.path, 'qingting_songs.db'); return await openDatabase( path, version: 1, onCreate: _onCreate, ); } Future _onCreate(Database db, int version) async { await db.execute(''' CREATE TABLE songs ( song_key TEXT PRIMARY KEY, remote_path TEXT, file_size INTEGER, modified_time INTEGER, etag TEXT, title TEXT, artist TEXT, album TEXT, genre TEXT, artwork_path TEXT, confidence REAL DEFAULT 0.0, validation_count INTEGER DEFAULT 0, first_scan INTEGER, last_scan INTEGER, metadata_status TEXT DEFAULT 'pending' ) '''); await db.execute(''' CREATE TABLE metadata_cache ( song_key TEXT PRIMARY KEY, cache_path TEXT, cache_created_at INTEGER, cache_size INTEGER, FOREIGN KEY (song_key) REFERENCES songs(song_key) ON DELETE CASCADE ) '''); await db.execute('CREATE INDEX idx_songs_artist ON songs(artist)'); await db.execute('CREATE INDEX idx_songs_title ON songs(title)'); } // ---- 查询 ---- Future?> getSong(String songKey) async { final db = await database; final result = await db.query('songs', where: 'song_key = ?', whereArgs: [songKey]); return result.isNotEmpty ? result.first : null; } Future>> getSongsByArtist(String artist, {int limit = 20}) async { if (artist.isEmpty) return []; final db = await database; return await db.query( 'songs', where: 'artist = ?', whereArgs: [artist], limit: limit, ); } // ---- 写入 ---- Future insertSong(Map song) async { final db = await database; await db.insert('songs', song, conflictAlgorithm: ConflictAlgorithm.replace); } Future updateSong(String songKey, Map updates) async { final db = await database; await db.update( 'songs', updates, where: 'song_key = ?', whereArgs: [songKey], ); } // ---- 缓存 ---- Future insertCache(Map cache) async { final db = await database; await db.insert('metadata_cache', cache, conflictAlgorithm: ConflictAlgorithm.replace); } Future?> getCache(String songKey) async { final db = await database; final result = await db .query('metadata_cache', where: 'song_key = ?', whereArgs: [songKey]); return result.isNotEmpty ? result.first : null; } Future close() async { final db = await database; await db.close(); _database = null; } }