mirror of
https://github.com/Dr-Blank/Vaani.git
synced 2026-02-16 06:19:35 +00:00
修改播放列表,改为单章播放
This commit is contained in:
parent
e44144b229
commit
ab3d5f7e02
3 changed files with 109 additions and 62 deletions
|
|
@ -8,6 +8,7 @@ import 'package:just_audio/just_audio.dart';
|
||||||
import 'package:just_audio_background/just_audio_background.dart';
|
import 'package:just_audio_background/just_audio_background.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:shelfsdk/audiobookshelf_api.dart';
|
import 'package:shelfsdk/audiobookshelf_api.dart';
|
||||||
|
import 'package:vaani/features/per_book_settings/providers/book_settings_provider.dart';
|
||||||
import 'package:vaani/settings/app_settings_provider.dart';
|
import 'package:vaani/settings/app_settings_provider.dart';
|
||||||
import 'package:vaani/settings/models/app_settings.dart';
|
import 'package:vaani/settings/models/app_settings.dart';
|
||||||
import 'package:vaani/shared/extensions/model_conversions.dart';
|
import 'package:vaani/shared/extensions/model_conversions.dart';
|
||||||
|
|
@ -51,18 +52,7 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
AudiobookPlayer(this.token, this.baseUrl) : super() {
|
AudiobookPlayer(this.token, this.baseUrl) : super() {
|
||||||
// set the source of the player to the first track in the book
|
// set the source of the player to the first track in the book
|
||||||
_logger.config('Setting up audiobook player');
|
_logger.config('Setting up audiobook player');
|
||||||
// currentIndexStream.listen((index) {
|
|
||||||
// print('播放器已切换到第 $index 首曲目');
|
|
||||||
// skip = true;
|
|
||||||
// });
|
|
||||||
// positionStream.listen((position) {
|
|
||||||
// if (skip != null && skip! && position.inSeconds < 20) {
|
|
||||||
// super.seek(Duration(seconds: 20));
|
|
||||||
// print('播放 $position');
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
}
|
}
|
||||||
bool? skip;
|
|
||||||
|
|
||||||
/// the [BookExpanded] being played
|
/// the [BookExpanded] being played
|
||||||
BookExpanded? _book;
|
BookExpanded? _book;
|
||||||
|
|
@ -82,10 +72,11 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
final Uri baseUrl;
|
final Uri baseUrl;
|
||||||
|
|
||||||
// the current index of the audio file in the [book]
|
// the current index of the audio file in the [book]
|
||||||
// final int _currentIndex = 0;
|
int _currentIndex = 0;
|
||||||
|
|
||||||
// available audio tracks
|
// available audio tracks
|
||||||
int? get availableTracks => _book?.tracks.length;
|
int? get availableTracks => _book?.tracks.length;
|
||||||
|
List<Uri>? downloadedUris;
|
||||||
|
|
||||||
/// sets the current [AudioTrack] as the source of the player
|
/// sets the current [AudioTrack] as the source of the player
|
||||||
Future<void> setSourceAudiobook(
|
Future<void> setSourceAudiobook(
|
||||||
|
|
@ -99,7 +90,7 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
_logger.finer(
|
_logger.finer(
|
||||||
'Initial position: $initialPosition, Downloaded URIs: $downloadedUris',
|
'Initial position: $initialPosition, Downloaded URIs: $downloadedUris',
|
||||||
);
|
);
|
||||||
final appSettings = loadOrCreateAppSettings();
|
// final appSettings = loadOrCreateAppSettings();
|
||||||
if (book == null) {
|
if (book == null) {
|
||||||
_book = null;
|
_book = null;
|
||||||
_logger.info('Book is null, stopping player');
|
_logger.info('Book is null, stopping player');
|
||||||
|
|
@ -124,41 +115,75 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
// after subtracting the duration of all the previous tracks
|
// after subtracting the duration of all the previous tracks
|
||||||
// initialPosition ;
|
// initialPosition ;
|
||||||
final trackToPlay = getTrackToPlay(book, initialPosition ?? Duration.zero);
|
final trackToPlay = getTrackToPlay(book, initialPosition ?? Duration.zero);
|
||||||
|
|
||||||
final initialIndex = book.tracks.indexOf(trackToPlay);
|
final initialIndex = book.tracks.indexOf(trackToPlay);
|
||||||
final initialPositionInTrack =
|
final initialPositionInTrack =
|
||||||
initialPosition != null ? initialPosition - trackToPlay.startOffset : null;
|
initialPosition != null ? initialPosition - trackToPlay.startOffset : null;
|
||||||
|
await setAudioSourceTrack(initialIndex, initialPosition: initialPositionInTrack);
|
||||||
|
// _logger.finer('Setting audioSource');
|
||||||
|
// await setAudioSource(
|
||||||
|
// preload: preload,
|
||||||
|
// initialIndex: initialIndex,
|
||||||
|
// initialPosition: initialPositionInTrack,
|
||||||
|
// ConcatenatingAudioSource(
|
||||||
|
// useLazyPreparation: true,
|
||||||
|
// children: book.tracks.map((track) {
|
||||||
|
// final retrievedUri = _getUri(track, downloadedUris, baseUrl: baseUrl, token: token);
|
||||||
|
// _logger.fine(
|
||||||
|
// 'Setting source for track: ${track.title}, URI: ${retrievedUri.obfuscate()}',
|
||||||
|
// );
|
||||||
|
// return AudioSource.uri(
|
||||||
|
// retrievedUri,
|
||||||
|
// tag: MediaItem(
|
||||||
|
// // Specify a unique ID for each media item:
|
||||||
|
// id: book.libraryItemId + track.index.toString(),
|
||||||
|
// // Metadata to display in the notification:
|
||||||
|
// title: appSettings.notificationSettings.primaryTitle.formatNotificationTitle(book),
|
||||||
|
// album: appSettings.notificationSettings.secondaryTitle.formatNotificationTitle(book),
|
||||||
|
// artUri: artworkUri ??
|
||||||
|
// Uri.parse(
|
||||||
|
// '$baseUrl/api/items/${book.libraryItemId}/cover?token=$token&width=800',
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// }).toList(),
|
||||||
|
// ),
|
||||||
|
// ).catchError((error) {
|
||||||
|
// _logger.shout('Error in setting audio source: $error');
|
||||||
|
// });
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> setAudioSourceTrack(int index, {Duration? initialPosition}) async {
|
||||||
|
if (_book == null) {
|
||||||
|
return stop();
|
||||||
|
}
|
||||||
|
if (index == _currentIndex) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
AudioTrack track = _book!.tracks[index];
|
||||||
|
final appSettings = loadOrCreateAppSettings();
|
||||||
|
if (initialPosition == null || initialPosition <= Duration()) {
|
||||||
|
initialPosition = readFromBoxOrCreate(_book!.libraryItemId).playerSettings.skipChapterStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
final retrievedUri = _getUri(track, downloadedUris, baseUrl: baseUrl, token: token);
|
||||||
|
|
||||||
_logger.finer('Setting audioSource');
|
|
||||||
await setAudioSource(
|
await setAudioSource(
|
||||||
preload: preload,
|
initialPosition: initialPosition,
|
||||||
initialIndex: initialIndex,
|
AudioSource.uri(
|
||||||
initialPosition: initialPositionInTrack,
|
retrievedUri,
|
||||||
ConcatenatingAudioSource(
|
tag: MediaItem(
|
||||||
useLazyPreparation: true,
|
// Specify a unique ID for each media item:
|
||||||
children: book.tracks.map((track) {
|
id: '${book?.libraryItemId}${track.index}',
|
||||||
final retrievedUri = _getUri(track, downloadedUris, baseUrl: baseUrl, token: token);
|
// Metadata to display in the notification:
|
||||||
_logger.fine(
|
title: appSettings.notificationSettings.primaryTitle.formatNotificationTitle(book!),
|
||||||
'Setting source for track: ${track.title}, URI: ${retrievedUri.obfuscate()}',
|
album: appSettings.notificationSettings.secondaryTitle.formatNotificationTitle(book!),
|
||||||
);
|
artUri: Uri.parse(
|
||||||
return AudioSource.uri(
|
'$baseUrl/api/items/${book?.libraryItemId}/cover?token=$token&width=800',
|
||||||
retrievedUri,
|
),
|
||||||
tag: MediaItem(
|
),
|
||||||
// Specify a unique ID for each media item:
|
|
||||||
id: book.libraryItemId + track.index.toString(),
|
|
||||||
// Metadata to display in the notification:
|
|
||||||
title: appSettings.notificationSettings.primaryTitle.formatNotificationTitle(book),
|
|
||||||
album: appSettings.notificationSettings.secondaryTitle.formatNotificationTitle(book),
|
|
||||||
artUri: artworkUri ??
|
|
||||||
Uri.parse(
|
|
||||||
'$baseUrl/api/items/${book.libraryItemId}/cover?token=$token&width=800',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
).catchError((error) {
|
);
|
||||||
_logger.shout('Error in setting audio source: $error');
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// toggles the player between play and pause
|
/// toggles the player between play and pause
|
||||||
|
|
@ -235,6 +260,22 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> seekToNext() {
|
||||||
|
if (_currentIndex >= availableTracks!) {
|
||||||
|
return super.seek(duration);
|
||||||
|
}
|
||||||
|
return setAudioSourceTrack(_currentIndex++);
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> seekToPrevious() {
|
||||||
|
if (_currentIndex == 0) {
|
||||||
|
return super.seek(Duration());
|
||||||
|
}
|
||||||
|
return setAudioSourceTrack(_currentIndex--);
|
||||||
|
}
|
||||||
|
|
||||||
/// seek backward to the previous chapter or the start of the current chapter
|
/// seek backward to the previous chapter or the start of the current chapter
|
||||||
void seekBackward() {
|
void seekBackward() {
|
||||||
final currentPlayingChapterIndex = _book!.chapters.indexOf(currentChapter!);
|
final currentPlayingChapterIndex = _book!.chapters.indexOf(currentChapter!);
|
||||||
|
|
@ -256,7 +297,8 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
if (_book == null) {
|
if (_book == null) {
|
||||||
return Duration.zero;
|
return Duration.zero;
|
||||||
}
|
}
|
||||||
return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
return position + _book!.tracks[_currentIndex].startOffset;
|
||||||
|
// return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// a convenience method to get the buffered position in the book instead of the current track position
|
/// a convenience method to get the buffered position in the book instead of the current track position
|
||||||
|
|
@ -264,7 +306,8 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
if (_book == null) {
|
if (_book == null) {
|
||||||
return Duration.zero;
|
return Duration.zero;
|
||||||
}
|
}
|
||||||
return bufferedPosition + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
return bufferedPosition + _book!.tracks[_currentIndex].startOffset;
|
||||||
|
// return bufferedPosition + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// streams to override to suit the book instead of the current track
|
/// streams to override to suit the book instead of the current track
|
||||||
|
|
@ -277,7 +320,8 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
if (_book == null) {
|
if (_book == null) {
|
||||||
return Duration.zero;
|
return Duration.zero;
|
||||||
}
|
}
|
||||||
return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
return position + _book!.tracks[_currentIndex].startOffset;
|
||||||
|
// return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -286,7 +330,8 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
if (_book == null) {
|
if (_book == null) {
|
||||||
return Duration.zero;
|
return Duration.zero;
|
||||||
}
|
}
|
||||||
return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
return position + _book!.tracks[_currentIndex].startOffset;
|
||||||
|
// return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -302,7 +347,8 @@ class AudiobookPlayer extends AudioPlayer {
|
||||||
if (_book == null) {
|
if (_book == null) {
|
||||||
return Duration.zero;
|
return Duration.zero;
|
||||||
}
|
}
|
||||||
return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
return position + _book!.tracks[_currentIndex].startOffset;
|
||||||
|
// return position + _book!.tracks[sequenceState!.currentIndex].startOffset;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,18 +13,18 @@ class SkipStartEnd {
|
||||||
// StreamController<PlaybackEvent>.broadcast();
|
// StreamController<PlaybackEvent>.broadcast();
|
||||||
|
|
||||||
SkipStartEnd({required this.start, required this.end, required this.player}) : _index = 0 {
|
SkipStartEnd({required this.start, required this.end, required this.player}) : _index = 0 {
|
||||||
if (start > Duration()) {
|
// if (start > Duration()) {
|
||||||
_subscriptions.add(
|
// _subscriptions.add(
|
||||||
player.currentIndexStream.listen((index) {
|
// player.currentIndexStream.listen((index) {
|
||||||
if (_index != index && player.position.inMilliseconds < 500) {
|
// if (_index != index && player.position.inMilliseconds < 500) {
|
||||||
Future.microtask(() {
|
// Future.microtask(() {
|
||||||
player.seek(start);
|
// player.seek(start);
|
||||||
});
|
// });
|
||||||
_index = index!;
|
// _index = index!;
|
||||||
}
|
// }
|
||||||
}),
|
// }),
|
||||||
);
|
// );
|
||||||
}
|
// }
|
||||||
if (end > Duration()) {
|
if (end > Duration()) {
|
||||||
_subscriptions.add(
|
_subscriptions.add(
|
||||||
player.positionStream.distinct().listen((position) {
|
player.positionStream.distinct().listen((position) {
|
||||||
|
|
@ -33,8 +33,9 @@ class SkipStartEnd {
|
||||||
end.inMilliseconds) {
|
end.inMilliseconds) {
|
||||||
throttler.call(() {
|
throttler.call(() {
|
||||||
print('跳过片尾');
|
print('跳过片尾');
|
||||||
Future.microtask(() {
|
Future.microtask(() async {
|
||||||
throttler.call(player.seekToNext);
|
await player.stop();
|
||||||
|
player.seekToNext();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -173,7 +173,7 @@ class _EagerInitialization extends ConsumerWidget {
|
||||||
ref.watch(playbackReporterProvider);
|
ref.watch(playbackReporterProvider);
|
||||||
ref.watch(simpleDownloadManagerProvider);
|
ref.watch(simpleDownloadManagerProvider);
|
||||||
ref.watch(shakeDetectorProvider);
|
ref.watch(shakeDetectorProvider);
|
||||||
ref.watch(skipStartEndProvider);
|
// ref.watch(skipStartEndProvider);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrintStack(stackTrace: StackTrace.current, label: e.toString());
|
debugPrintStack(stackTrace: StackTrace.current, label: e.toString());
|
||||||
appLogger.severe(e.toString());
|
appLogger.severe(e.toString());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue