mirror of
https://github.com/zarzet/SpotiFLAC-Mobile.git
synced 2026-09-30 13:19:44 +02:00
fix(player): retain duration probing after queue edits during loading
This commit is contained in:
1 parent
da5a0522ca
commit
fa4a03c754
2 files changed
+27
-8
No files matched your search
@@ -1273,7 +1273,6 @@ class MusicPlayerHandler extends BaseAudioHandler
|
|||||||
await _player.stop();
|
await _player.stop();
|
||||||
if (!_isCurrentPlayRequest(generation, media)) return;
|
if (!_isCurrentPlayRequest(generation, media)) return;
|
||||||
await _loadIndex(
|
await _loadIndex(
|
||||||
index,
|
|
||||||
generation,
|
generation,
|
||||||
media,
|
media,
|
||||||
recordHistory: recordHistory,
|
recordHistory: recordHistory,
|
||||||
@@ -1312,7 +1311,6 @@ class MusicPlayerHandler extends BaseAudioHandler
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _loadIndex(
|
Future<void> _loadIndex(
|
||||||
int index,
|
|
||||||
int generation,
|
int generation,
|
||||||
PlayableMedia media, {
|
PlayableMedia media, {
|
||||||
required bool recordHistory,
|
required bool recordHistory,
|
||||||
@@ -1322,7 +1320,7 @@ class MusicPlayerHandler extends BaseAudioHandler
|
|||||||
_interruptionActive = false;
|
_interruptionActive = false;
|
||||||
_userPaused = false;
|
_userPaused = false;
|
||||||
|
|
||||||
if (recordHistory) _recordPlayHistory(index);
|
if (recordHistory) _recordPlayHistory(_index);
|
||||||
|
|
||||||
final effectiveStartPosition = normalizedPlaybackResumePosition(
|
final effectiveStartPosition = normalizedPlaybackResumePosition(
|
||||||
startPosition,
|
startPosition,
|
||||||
@@ -1454,7 +1452,7 @@ class MusicPlayerHandler extends BaseAudioHandler
|
|||||||
unawaited(_persistSession(position: effectiveStartPosition));
|
unawaited(_persistSession(position: effectiveStartPosition));
|
||||||
// Some files do not emit onDurationChanged reliably (stuck at 0:00);
|
// Some files do not emit onDurationChanged reliably (stuck at 0:00);
|
||||||
// poll the engine for the real duration as a fallback.
|
// poll the engine for the real duration as a fallback.
|
||||||
unawaited(_ensureDurationKnown(index, generation));
|
unawaited(_ensureDurationKnown(media, generation));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
if (!_isCurrentPlayRequest(generation, media)) return;
|
if (!_isCurrentPlayRequest(generation, media)) return;
|
||||||
_sourceReady = false;
|
_sourceReady = false;
|
||||||
@@ -1473,16 +1471,16 @@ class MusicPlayerHandler extends BaseAudioHandler
|
|||||||
/// Resolves the real track duration when the initial metadata had none and
|
/// Resolves the real track duration when the initial metadata had none and
|
||||||
/// the duration-changed event did not fire, so the seek bar and total time
|
/// the duration-changed event did not fire, so the seek bar and total time
|
||||||
/// do not get stuck at 0:00.
|
/// do not get stuck at 0:00.
|
||||||
Future<void> _ensureDurationKnown(int index, int generation) async {
|
Future<void> _ensureDurationKnown(PlayableMedia media, int generation) async {
|
||||||
for (var attempt = 0; attempt < 15; attempt++) {
|
for (var attempt = 0; attempt < 15; attempt++) {
|
||||||
if (_index != index || generation != _playRequestGeneration) return;
|
if (!_isCurrentPlayRequest(generation, media)) return;
|
||||||
final current = mediaItem.value;
|
final current = mediaItem.value;
|
||||||
final existing = current?.duration;
|
final existing = current?.duration;
|
||||||
if (existing != null && existing > Duration.zero) return;
|
if (existing != null && existing > Duration.zero) return;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final d = await _player.getDuration();
|
final d = await _player.getDuration();
|
||||||
if (_index != index || generation != _playRequestGeneration) return;
|
if (!_isCurrentPlayRequest(generation, media)) return;
|
||||||
if (d != null && d > Duration.zero) {
|
if (d != null && d > Duration.zero) {
|
||||||
final item = mediaItem.value;
|
final item = mediaItem.value;
|
||||||
if (item != null) {
|
if (item != null) {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ class _AudioNative {
|
|||||||
final sources = <String, String>{};
|
final sources = <String, String>{};
|
||||||
final sourceGates = <String, Completer<void>>{};
|
final sourceGates = <String, Completer<void>>{};
|
||||||
final resumedSources = <String>[];
|
final resumedSources = <String>[];
|
||||||
|
bool emitsDuration = true;
|
||||||
|
|
||||||
void install() {
|
void install() {
|
||||||
for (final name in [
|
for (final name in [
|
||||||
@@ -71,7 +72,7 @@ class _AudioNative {
|
|||||||
await sourceGates[source]?.future;
|
await sourceGates[source]?.future;
|
||||||
sources[id] = source;
|
sources[id] = source;
|
||||||
unawaited(event(id, 'audio.onPrepared', true));
|
unawaited(event(id, 'audio.onPrepared', true));
|
||||||
unawaited(event(id, 'audio.onDuration', 60000));
|
if (emitsDuration) unawaited(event(id, 'audio.onDuration', 60000));
|
||||||
case 'seek':
|
case 'seek':
|
||||||
positions[id] = args['position']! as int;
|
positions[id] = args['position']! as int;
|
||||||
unawaited(event(id, 'audio.onSeekComplete'));
|
unawaited(event(id, 'audio.onSeekComplete'));
|
||||||
@@ -406,6 +407,26 @@ void main() {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
test(
|
||||||
|
'removing an earlier row during preparation preserves duration probing',
|
||||||
|
() async {
|
||||||
|
native.emitsDuration = false;
|
||||||
|
final gate = Completer<void>();
|
||||||
|
native.sourceGates['/three.flac'] = gate;
|
||||||
|
final loading = handler.setQueueAndPlay(_tracks, initialIndex: 2);
|
||||||
|
await _until(() => native.calls.any((call) => call.$2 == 'setSourceUrl'));
|
||||||
|
handler.removeQueuedItem(handler.queue.value.first);
|
||||||
|
gate.complete();
|
||||||
|
await loading;
|
||||||
|
await _until(
|
||||||
|
() => handler.mediaItem.value?.duration == const Duration(seconds: 60),
|
||||||
|
);
|
||||||
|
expect(handler.playbackState.value.queueIndex, 1);
|
||||||
|
expect(handler.mediaItem.value?.id, 'three');
|
||||||
|
expect(native.resumedSources, ['/three.flac']);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
test('restored shuffle can return to the saved original order', () async {
|
test('restored shuffle can return to the saved original order', () async {
|
||||||
await handler.restoreSession(
|
await handler.restoreSession(
|
||||||
items: [_tracks[1], _tracks[2], _tracks[0]],
|
items: [_tracks[1], _tracks[2], _tracks[0]],
|
||||||
|
|||||||
Reference in new issue
Block a user