diff --git a/lib/controllers/playback_controller.dart b/lib/controllers/playback_controller.dart index 1605de0..c4962af 100644 --- a/lib/controllers/playback_controller.dart +++ b/lib/controllers/playback_controller.dart @@ -92,6 +92,17 @@ class PlaybackController { // ════════════════════════════════════════════════════════════ // 单曲播放(fallback) // ════════════════════════════════════════════════════════════ + /// 播放路径/文件名是百分号编码的,展示前必须解码 + String _displayName(String pathOrName) { + final raw = pathOrName.split('/').last; + String decoded; + try { + decoded = Uri.decodeComponent(raw); + } catch (_) { + decoded = raw; + } + return decoded.replaceAll(RegExp(r'\.[^.]*$'), ''); + } Future _playSingleSong(String songPath) async { debugPrint('🎯 [PlaybackController] _playSingleSong: $songPath'); final url = WebDAVService.instance.getFileUrl(songPath); @@ -99,8 +110,9 @@ class PlaybackController { final song = Song( id: songPath, artworkPath: dbSong?['artwork_path'] as String?, - title: dbSong?['title'] as String? ?? - songPath.split('/').last.replaceAll(RegExp(r'\.[^.]*$'), ''), + title: (dbSong?['title'] as String?)?.trim().isNotEmpty == true + ? dbSong!['title'] as String + : _displayName(songPath), artist: dbSong?['artist'] as String? ?? '未知艺术家', url: url, ); @@ -119,15 +131,16 @@ class PlaybackController { queue.add(Song( id: item.path, artworkPath: dbSong['artwork_path'] as String?, - title: dbSong['title'] as String? ?? - item.name.replaceAll(RegExp(r'\.[^.]*$'), ''), + title: (dbSong['title'] as String?)?.trim().isNotEmpty == true + ? dbSong['title'] as String + : _displayName(item.path), artist: dbSong['artist'] as String? ?? '未知艺术家', url: url, )); } else { queue.add(Song( id: item.path, - title: item.name.replaceAll(RegExp(r'\.[^.]*$'), ''), + title: _displayName(item.path), artist: '未知艺术家', url: url, )); diff --git a/lib/services/audio_service.dart b/lib/services/audio_service.dart index e591648..41d2d74 100644 --- a/lib/services/audio_service.dart +++ b/lib/services/audio_service.dart @@ -300,23 +300,29 @@ class AudioService extends ChangeNotifier { final songs = []; for (final id in songIds) { final dbSong = await _db.getSongByPath(id); - if (dbSong != null) { - final path = dbSong['remote_path'] as String; - songs.add(Song( - id: path, - artworkPath: dbSong['artwork_path'] as String?, - title: dbSong['title'] as String? ?? '', - artist: dbSong['artist'] as String? ?? '未知艺术家', - url: WebDAVService.instance.getFileUrl(path), - )); - } else { - songs.add(Song( - id: id, - title: id.split('/').last.replaceAll(RegExp(r'\.[^.]*$'), ''), - artist: '未知艺术家', - url: WebDAVService.instance.getFileUrl(id), - )); + final path = (dbSong?['remote_path'] as String?) ?? id; + + // 没有标签时回退文件名,必须解码:id 是百分号编码的播放路径, + // 直接展示会变成 "%E6%9C%AA..." 这种不可读串。 + final rawName = path.split('/').last; + String displayName; + try { + displayName = Uri.decodeComponent(rawName); + } catch (_) { + displayName = rawName; } + displayName = displayName.replaceAll(RegExp(r'\.[^.]*$'), ''); + + final dbTitle = (dbSong?['title'] as String?)?.trim() ?? ''; + final dbArtist = (dbSong?['artist'] as String?)?.trim() ?? ''; + + songs.add(Song( + id: path, + artworkPath: dbSong?['artwork_path'] as String?, + title: dbTitle.isNotEmpty ? dbTitle : displayName, + artist: dbArtist.isNotEmpty ? dbArtist : '未知艺术家', + url: WebDAVService.instance.getFileUrl(path), + )); } if (songs.isNotEmpty) {