优化部分功能逻辑:元数据信息漂移
优化部分体验问题,包含动画、界面层级等
This commit is contained in:
@@ -3,6 +3,7 @@ import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:media_kit/media_kit.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'playback_service.dart';
|
||||
import '../metadata/metadata_service.dart';
|
||||
@@ -60,6 +61,9 @@ class AudioService extends ChangeNotifier {
|
||||
|
||||
bool _isUserSeeking = false;
|
||||
|
||||
// ⭐ 播放代数:每次切歌递增,用于校验异步任务是否过期
|
||||
int _playbackGeneration = 0;
|
||||
|
||||
// ---- Getter ----
|
||||
Song? get currentSong => _currentSong;
|
||||
bool get isPlaying => _isPlaying;
|
||||
@@ -144,6 +148,9 @@ class AudioService extends ChangeNotifier {
|
||||
return;
|
||||
}
|
||||
|
||||
_playbackGeneration++;
|
||||
final generation = _playbackGeneration;
|
||||
|
||||
final song = _queue[_currentIndex];
|
||||
_currentSong = song;
|
||||
|
||||
@@ -158,7 +165,11 @@ class AudioService extends ChangeNotifier {
|
||||
|
||||
_syncPlayerStateDelayed();
|
||||
|
||||
_loadMetadataForCurrentSong();
|
||||
// ⭐ 立即推送基本信息(无 artwork)
|
||||
_onSongChanged?.call(song);
|
||||
|
||||
// ⭐ 异步加载完整 metadata(含 artwork)
|
||||
_loadMetadataForCurrentSong(generation);
|
||||
}
|
||||
|
||||
String _generateSongKey(String url, int fileSize, int modifiedTime) {
|
||||
@@ -166,10 +177,21 @@ class AudioService extends ChangeNotifier {
|
||||
return raw.hashCode.toString();
|
||||
}
|
||||
|
||||
Future<void> _loadMetadataForCurrentSong() async {
|
||||
// ⭐ 核心:带 generation 校验的 metadata 加载
|
||||
// lib/services/audio_service.dart
|
||||
|
||||
Future<void> _loadMetadataForCurrentSong(int generation) async {
|
||||
if (_currentIndex < 0 || _currentIndex >= _queue.length) return;
|
||||
final song = _queue[_currentIndex];
|
||||
if (song.url == null || song.url!.isEmpty) return;
|
||||
|
||||
final currentIndex = _currentIndex;
|
||||
final song = _queue[currentIndex];
|
||||
final songId = song.id;
|
||||
|
||||
if (song.url == null || song.url!.isEmpty) {
|
||||
// 没有 URL,直接推送 fallback
|
||||
_onSongChanged?.call(song);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
final metadata = await MetadataService().getMetadata(
|
||||
@@ -178,23 +200,41 @@ class AudioService extends ChangeNotifier {
|
||||
fileId: song.id,
|
||||
);
|
||||
|
||||
if (metadata.isNotEmpty) {
|
||||
final updatedSong = Song(
|
||||
id: song.id,
|
||||
title: metadata.title.isNotEmpty ? metadata.title : song.title,
|
||||
artist: metadata.artist.isNotEmpty ? metadata.artist : song.artist,
|
||||
url: song.url,
|
||||
artwork: metadata.artwork, // ✅ 已有
|
||||
);
|
||||
_queue[_currentIndex] = updatedSong;
|
||||
_currentSong = updatedSong;
|
||||
notifyListeners();
|
||||
|
||||
// ⭐ 传递完整的 updatedSong(包含 artwork)
|
||||
_onSongChanged?.call(updatedSong);
|
||||
// generation 校验
|
||||
if (_playbackGeneration != generation) {
|
||||
debugPrint('⚠️ [AudioService] metadata stale (generation), ignoring');
|
||||
return;
|
||||
}
|
||||
if (_currentIndex != currentIndex) {
|
||||
debugPrint(
|
||||
'⚠️ [AudioService] metadata stale (index changed), ignoring');
|
||||
return;
|
||||
}
|
||||
if (currentIndex >= _queue.length || _queue[currentIndex].id != songId) {
|
||||
debugPrint('⚠️ [AudioService] metadata stale (song changed), ignoring');
|
||||
return;
|
||||
}
|
||||
|
||||
// 更新 Song
|
||||
final updatedSong = Song(
|
||||
id: song.id,
|
||||
title: metadata.title.isNotEmpty ? metadata.title : song.title,
|
||||
artist: metadata.artist.isNotEmpty ? metadata.artist : song.artist,
|
||||
url: song.url,
|
||||
artwork: metadata.artwork,
|
||||
);
|
||||
_queue[_currentIndex] = updatedSong;
|
||||
_currentSong = updatedSong;
|
||||
notifyListeners();
|
||||
|
||||
// ⭐ 一次性推送完整数据(含 artwork)
|
||||
_onSongChanged?.call(updatedSong);
|
||||
debugPrint(
|
||||
'✅ [AudioService] metadata updated: ${updatedSong.title} - ${updatedSong.artist} (generation $generation)');
|
||||
} catch (e) {
|
||||
debugPrint('⚠️ [AudioService] metadata load failed: $e');
|
||||
debugPrint('⚠️ [AudioService] metadata load failed: $e, using fallback');
|
||||
// 异常时推送 fallback(无 artwork)
|
||||
_onSongChanged?.call(song);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,10 +247,8 @@ class AudioService extends ChangeNotifier {
|
||||
|
||||
debugPrint('🗑️ [AudioService] clearing cache for: ${song.title}');
|
||||
|
||||
// 1. 获取当前索引
|
||||
final currentIndex = _currentIndex;
|
||||
|
||||
// 2. 尝试获取文件信息生成 song_key
|
||||
String songKey;
|
||||
try {
|
||||
final provider = MetadataService().getProviderForUrl(url);
|
||||
@@ -226,17 +264,14 @@ class AudioService extends ChangeNotifier {
|
||||
songKey = url.hashCode.toString();
|
||||
}
|
||||
|
||||
// 3. 清除 SQLite 记录
|
||||
final db = SongDatabase();
|
||||
await db.deleteSong(songKey);
|
||||
await db.deleteCache(songKey);
|
||||
debugPrint('🗑️ [AudioService] SQLite records deleted: $songKey');
|
||||
|
||||
// 4. 删除封面图
|
||||
await ArtworkHelper.deleteArtwork(songKey);
|
||||
debugPrint('🗑️ [AudioService] artwork deleted');
|
||||
|
||||
// 5. 删除 metadata 临时缓存文件
|
||||
try {
|
||||
final cacheDir = await getTemporaryDirectory();
|
||||
final cachePath = '${cacheDir.path}/metadata_${url.hashCode}.tmp';
|
||||
@@ -249,14 +284,11 @@ class AudioService extends ChangeNotifier {
|
||||
// 忽略
|
||||
}
|
||||
|
||||
// 6. 清除内存缓存
|
||||
await MetadataService().clearCache(song.id);
|
||||
debugPrint('🗑️ [AudioService] memory cache cleared');
|
||||
|
||||
// 7. 停止并重新播放
|
||||
if (currentIndex >= 0 && currentIndex < _queue.length) {
|
||||
stopPlay();
|
||||
// 确保重新播放同一首歌
|
||||
_playCurrent();
|
||||
debugPrint('🔄 [AudioService] song reloaded');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user