From 2a29e30940dcfe4da2fb4d46387ebb8cfa10c493 Mon Sep 17 00:00:00 2001 From: lxh2875931338 Date: Thu, 27 Aug 2026 22:32:38 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E8=A1=A8=E5=86=99=E5=85=A5?= =?UTF-8?q?=E9=97=AE=E9=A2=98=EF=BC=8C=E5=90=8C=E6=97=B6=E5=A2=9E=E5=8A=A0?= =?UTF-8?q?=E5=AF=B9=E8=AF=BB=E5=BA=93=E5=8A=A8=E4=BD=9C=E7=9A=84log?= =?UTF-8?q?=E5=8F=AF=E8=A7=86=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/database/song_database.dart | 154 ++++++++++++++++++++++++++------ 1 file changed, 127 insertions(+), 27 deletions(-) diff --git a/lib/database/song_database.dart b/lib/database/song_database.dart index 7fb2ea4..fc6f959 100644 --- a/lib/database/song_database.dart +++ b/lib/database/song_database.dart @@ -1,4 +1,5 @@ // lib/database/song_database.dart +import 'package:flutter/foundation.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; import 'package:path_provider/path_provider.dart'; @@ -10,6 +11,9 @@ class SongDatabase { static Database? _database; + // ⭐ 开启/关闭日志(开发阶段开启) + static bool enableLog = true; + Future get database async { if (_database != null) return _database!; _database = await _initDatabase(); @@ -19,15 +23,34 @@ class SongDatabase { Future _initDatabase() async { final dir = await getApplicationDocumentsDirectory(); final path = join(dir.path, 'qingting_songs.db'); + _log('📂 数据库路径: $path'); return await openDatabase( path, - version: 2, + version: 3, onCreate: _onCreate, onUpgrade: _onUpgrade, ); } - // ⭐ 新增:检查表是否存在 + // ════════════════════════════════════════════════════════════ + // 日志工具 + // ════════════════════════════════════════════════════════════ + void _log(String message) { + if (enableLog) { + debugPrint('📦 [DB] $message'); + } + } + + void _logQuery(String table, String operation, {Map? args}) { + if (enableLog) { + final argsStr = args != null && args.isNotEmpty ? ' $args' : ''; + debugPrint('📦 [DB] $table → $operation$argsStr'); + } + } + + // ════════════════════════════════════════════════════════════ + // 辅助方法 + // ════════════════════════════════════════════════════════════ Future _tableExists(Database db, String tableName) async { final result = await db.query( 'sqlite_master', @@ -37,33 +60,24 @@ class SongDatabase { return result.isNotEmpty; } + Future _columnExists( + Database db, String tableName, String columnName) async { + final result = await db.rawQuery('PRAGMA table_info($tableName)'); + return result.any((col) => col['name'] == columnName); + } + + // ════════════════════════════════════════════════════════════ + // 创建表 + // ════════════════════════════════════════════════════════════ Future _onCreate(Database db, int version) async { + _log('🆕 创建数据库 (version $version)'); await _createSongsTable(db); await _createMetadataCacheTable(db); await _createPlaylistsTable(db); await _createPlaylistSongsTable(db); await _createFavoritesTable(db); await _createIndexes(db); - } - - // ⭐ 升级逻辑(从版本 1 升级到 2) - Future _onUpgrade(Database db, int oldVersion, int newVersion) async { - if (oldVersion < 2) { - // 检查 playlists 表是否存在 - final playlistsExists = await _tableExists(db, 'playlists'); - - if (!playlistsExists) { - // 表不存在 → 创建所有新表 - await _createPlaylistsTable(db); - await _createPlaylistSongsTable(db); - await _createFavoritesTable(db); - await _createIndexes(db); - } else { - // 表已存在 → 只添加新字段 - await db.execute( - 'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"'); - } - } + _log('✅ 数据库创建完成'); } Future _createSongsTable(Database db) async { @@ -87,6 +101,7 @@ class SongDatabase { metadata_status TEXT DEFAULT 'pending' ) '''); + _log('📋 表创建: songs'); } Future _createMetadataCacheTable(Database db) async { @@ -99,6 +114,7 @@ class SongDatabase { FOREIGN KEY (song_key) REFERENCES songs(song_key) ON DELETE CASCADE ) '''); + _log('📋 表创建: metadata_cache'); } Future _createPlaylistsTable(Database db) async { @@ -111,6 +127,7 @@ class SongDatabase { updated_at INTEGER ) '''); + _log('📋 表创建: playlists'); } Future _createPlaylistSongsTable(Database db) async { @@ -124,6 +141,7 @@ class SongDatabase { FOREIGN KEY (playlist_id) REFERENCES playlists(id) ON DELETE CASCADE ) '''); + _log('📋 表创建: playlist_songs'); } Future _createFavoritesTable(Database db) async { @@ -134,6 +152,7 @@ class SongDatabase { FOREIGN KEY (song_id) REFERENCES songs(remote_path) ON DELETE CASCADE ) '''); + _log('📋 表创建: favorites'); } Future _createIndexes(Database db) async { @@ -147,12 +166,65 @@ class SongDatabase { 'CREATE INDEX IF NOT EXISTS idx_playlist_songs_playlist ON playlist_songs(playlist_id)'); await db.execute( 'CREATE INDEX IF NOT EXISTS idx_playlist_songs_order ON playlist_songs(order_index)'); + _log('📋 索引创建完成'); } // ════════════════════════════════════════════════════════════ - // 查询方法(保持不变) + // 升级逻辑 + // ════════════════════════════════════════════════════════════ + Future _onUpgrade(Database db, int oldVersion, int newVersion) async { + _log('⬆️ 数据库升级: $oldVersion → $newVersion'); + + if (oldVersion < 2) { + if (!await _columnExists(db, 'songs', 'content_hash')) { + await db.execute('ALTER TABLE songs ADD COLUMN content_hash TEXT'); + _log('🔧 添加列: songs.content_hash'); + } + + final playlistsExists = await _tableExists(db, 'playlists'); + if (!playlistsExists) { + await _createPlaylistsTable(db); + await _createPlaylistSongsTable(db); + await _createFavoritesTable(db); + } else { + if (!await _columnExists(db, 'playlists', 'play_mode')) { + await db.execute( + 'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"'); + _log('🔧 添加列: playlists.play_mode'); + } + } + await _createIndexes(db); + } + + if (oldVersion < 3) { + if (!await _columnExists(db, 'songs', 'content_hash')) { + await db.execute('ALTER TABLE songs ADD COLUMN content_hash TEXT'); + _log('🔧 添加列: songs.content_hash'); + } + + final playlistsExists = await _tableExists(db, 'playlists'); + if (!playlistsExists) { + await _createPlaylistsTable(db); + await _createPlaylistSongsTable(db); + await _createFavoritesTable(db); + } else { + if (!await _columnExists(db, 'playlists', 'play_mode')) { + await db.execute( + 'ALTER TABLE playlists ADD COLUMN play_mode TEXT DEFAULT "sequential"'); + _log('🔧 添加列: playlists.play_mode'); + } + } + await _createIndexes(db); + } + + _log('✅ 数据库升级完成'); + } + + // ════════════════════════════════════════════════════════════ + // 查询方法(带日志) // ════════════════════════════════════════════════════════════ Future?> getSong(String songKey) async { + _logQuery('songs', 'get', args: {'song_key': songKey}); final db = await database; final result = await db.query('songs', where: 'song_key = ?', whereArgs: [songKey]); @@ -160,6 +232,7 @@ class SongDatabase { } Future?> getSongByPath(String remotePath) async { + _logQuery('songs', 'getByPath', args: {'remote_path': remotePath}); final db = await database; final result = await db .query('songs', where: 'remote_path = ?', whereArgs: [remotePath]); @@ -167,6 +240,7 @@ class SongDatabase { } Future?> getSongByHash(String contentHash) async { + _logQuery('songs', 'getByHash', args: {'content_hash': contentHash}); final db = await database; final result = await db .query('songs', where: 'content_hash = ?', whereArgs: [contentHash]); @@ -175,6 +249,7 @@ class SongDatabase { Future>> getSongsByArtist(String artist, {int limit = 20}) async { + _logQuery('songs', 'getByArtist', args: {'artist': artist, 'limit': limit}); if (artist.isEmpty) return []; final db = await database; return await db.query( @@ -186,14 +261,16 @@ class SongDatabase { } // ════════════════════════════════════════════════════════════ - // 播放列表 CRUD(保持不变) + // 播放列表 CRUD(带日志) // ════════════════════════════════════════════════════════════ Future>> getAllPlaylists() async { + _logQuery('playlists', 'getAll'); final db = await database; return await db.query('playlists', orderBy: 'created_at DESC'); } Future?> getPlaylist(String id) async { + _logQuery('playlists', 'get', args: {'id': id}); final db = await database; final result = await db.query('playlists', where: 'id = ?', whereArgs: [id]); @@ -201,25 +278,30 @@ class SongDatabase { } Future insertPlaylist(Map playlist) async { + _logQuery('playlists', 'insert', args: {'name': playlist['name']}); final db = await database; await db.insert('playlists', playlist, conflictAlgorithm: ConflictAlgorithm.replace); } Future updatePlaylist(String id, Map updates) async { + _logQuery('playlists', 'update', + args: {'id': id, 'updates': updates.keys.join(',')}); final db = await database; await db.update('playlists', updates, where: 'id = ?', whereArgs: [id]); } Future deletePlaylist(String id) async { + _logQuery('playlists', 'delete', args: {'id': id}); final db = await database; await db.delete('playlists', where: 'id = ?', whereArgs: [id]); } // ════════════════════════════════════════════════════════════ - // 播放列表歌曲操作(保持不变) + // 播放列表歌曲(带日志) // ════════════════════════════════════════════════════════════ Future>> getPlaylistSongs(String playlistId) async { + _logQuery('playlist_songs', 'get', args: {'playlist_id': playlistId}); final db = await database; return await db.query( 'playlist_songs', @@ -231,6 +313,8 @@ class SongDatabase { Future addSongToPlaylist(String playlistId, String songId, {int? orderIndex}) async { + _logQuery('playlist_songs', 'add', + args: {'playlist_id': playlistId, 'song_id': songId}); final db = await database; int finalOrder = orderIndex ?? 0; if (orderIndex == null) { @@ -257,6 +341,8 @@ class SongDatabase { } Future removeSongFromPlaylist(String playlistId, String songId) async { + _logQuery('playlist_songs', 'remove', + args: {'playlist_id': playlistId, 'song_id': songId}); final db = await database; await db.delete( 'playlist_songs', @@ -266,20 +352,23 @@ class SongDatabase { } Future clearPlaylist(String playlistId) async { + _logQuery('playlist_songs', 'clear', args: {'playlist_id': playlistId}); final db = await database; await db.delete('playlist_songs', where: 'playlist_id = ?', whereArgs: [playlistId]); } // ════════════════════════════════════════════════════════════ - // 收藏操作(保持不变) + // 收藏(带日志) // ════════════════════════════════════════════════════════════ Future>> getFavorites() async { + _logQuery('favorites', 'getAll'); final db = await database; return await db.query('favorites', orderBy: 'favorited_at DESC'); } Future isFavorite(String songId) async { + _logQuery('favorites', 'isFavorite', args: {'song_id': songId}); final db = await database; final result = await db.query('favorites', where: 'song_id = ?', whereArgs: [songId]); @@ -287,6 +376,7 @@ class SongDatabase { } Future addFavorite(String songId) async { + _logQuery('favorites', 'add', args: {'song_id': songId}); final db = await database; await db.insert( 'favorites', @@ -299,6 +389,7 @@ class SongDatabase { } Future removeFavorite(String songId) async { + _logQuery('favorites', 'remove', args: {'song_id': songId}); final db = await database; await db.delete('favorites', where: 'song_id = ?', whereArgs: [songId]); } @@ -312,38 +403,46 @@ class SongDatabase { } // ════════════════════════════════════════════════════════════ - // 原有写入/删除方法(保持不变) + // 原有方法(带日志) // ════════════════════════════════════════════════════════════ Future insertSong(Map song) async { + _logQuery('songs', 'insert', args: {'title': song['title']}); final db = await database; await db.insert('songs', song, conflictAlgorithm: ConflictAlgorithm.replace); } Future updateSong(String songKey, Map updates) async { + _logQuery('songs', 'update', + args: {'song_key': songKey, 'fields': updates.keys.join(',')}); final db = await database; await db .update('songs', updates, where: 'song_key = ?', whereArgs: [songKey]); } Future deleteSong(String songKey) async { + _logQuery('songs', 'delete', args: {'song_key': songKey}); final db = await database; await db.delete('songs', where: 'song_key = ?', whereArgs: [songKey]); } Future deleteCache(String songKey) async { + _logQuery('metadata_cache', 'delete', args: {'song_key': songKey}); final db = await database; await db .delete('metadata_cache', where: 'song_key = ?', whereArgs: [songKey]); } Future insertCache(Map cache) async { + _logQuery('metadata_cache', 'insert', + args: {'song_key': cache['song_key']}); final db = await database; await db.insert('metadata_cache', cache, conflictAlgorithm: ConflictAlgorithm.replace); } Future?> getCache(String songKey) async { + _logQuery('metadata_cache', 'get', args: {'song_key': songKey}); final db = await database; final result = await db .query('metadata_cache', where: 'song_key = ?', whereArgs: [songKey]); @@ -351,6 +450,7 @@ class SongDatabase { } Future close() async { + _log('🔒 关闭数据库连接'); final db = await database; await db.close(); _database = null;