fix(metadata): 元数据回退到文件名时,在 80% 处重试一次

云服日志显示:对 /dav/.../*.flac 的 Range GET 在 10.3s 后返回 502,
是反代等待上游首包超时(清远源站响应慢),与我方 15s 超时无关。
影响仅限该曲的标签/封面,播放不受影响,但会一直回退文件名。

- _loadMetadataForCurrentSong: source == 'filename' 时置 _metadataNeedsRetry
- 播放到 80% 且该曲未重试过 → 再抓一次(每首歌最多一次)
- 因"播放未稳定"被跳过抓取的情况也标记为待重试
- 换歌时清空标记
This commit is contained in:
2026-10-23 23:11:39 +08:00
parent 2d571eaae4
commit af895c18e1
+35
View File
@@ -109,6 +109,10 @@ class AudioService extends ChangeNotifier {
DateTime? _trackStartAt;
DateTime? _playReadyAt;
int _prefetchedGeneration = -1;
/// 元数据回退到文件名时置位,播到 80% 再试一次
bool _metadataNeedsRetry = false;
int _metadataRetryGeneration = -1;
bool _firstAudioReported = false;
/// 最近一次播放失败的原因,供 UI 提示;成功播放后自动清空。
@@ -319,6 +323,7 @@ class AudioService extends ChangeNotifier {
_trackStartAt = DateTime.now();
_playReadyAt = null;
_firstAudioReported = false;
_metadataNeedsRetry = false;
await _playWithHeaders(song.url!);
_playReadyAt = DateTime.now();
} catch (e) {
@@ -411,6 +416,7 @@ class AudioService extends ChangeNotifier {
final settled = await _waitForPlaybackSettled(epoch);
if (!settled || epoch != _switchEpoch) {
debugPrint('⏸️ [AudioService] 播放未稳定,跳过本次元数据抓取(避免抢带宽)');
_metadataNeedsRetry = true; // 留到 80% 再试
return;
}
await _loadMetadataForCurrentSong(generation);
@@ -420,6 +426,25 @@ class AudioService extends ChangeNotifier {
}();
}
/// 播到 80% 时,对"元数据回退到文件名"的歌再抓一次。
///
/// 原因:反代在等上游首包超时时会直接回 502(实测 10.3s),
/// 起播阶段抓取很容易撞上;到 80% 时链路通常已经热了,重试成功率更高。
/// 每首歌最多重试一次。
void _maybeRetryMetadata(Duration position) {
if (!_metadataNeedsRetry) return;
final duration = durationNotifier.value;
if (duration.inMilliseconds <= 0) return;
if (position.inMilliseconds < duration.inMilliseconds * 0.8) return;
if (_metadataRetryGeneration == _playbackGeneration) return;
_metadataRetryGeneration = _playbackGeneration;
_metadataNeedsRetry = false;
debugPrint('🔁 [AudioService] 播放到 80%,重试一次元数据抓取');
_loadMetadataForCurrentSong(_playbackGeneration);
}
/// 播到 60% 时预热下一首(HEAD + Range 0-0,不下载正文)。
///
/// 日志实测起播延迟 2~3s 都在"等首批数据",提前完成 DNS/TLS/反代握手
@@ -654,6 +679,15 @@ class AudioService extends ChangeNotifier {
}
if (metadata.isNotEmpty) {
// 来源是文件名 = 元数据没读到(常见于反代 502 / 超时)
// 记下来,播到 80% 时再试一次,避免这首歌永远只有文件名
if (metadata.source == 'filename') {
_metadataNeedsRetry = true;
debugPrint('⚠️ [AudioService] 元数据回退到文件名,将在 80% 处重试一次');
} else {
_metadataNeedsRetry = false;
}
final updatedSong = Song(
id: song.id,
title: metadata.title.isNotEmpty ? metadata.title : song.title,
@@ -896,6 +930,7 @@ class AudioService extends ChangeNotifier {
_playReadyAt = null;
}
}
_maybeRetryMetadata(position);
_maybePrefetchNext(position);
positionNotifier.value = position;
}),