部分优化

This commit is contained in:
rang 2025-12-04 16:55:25 +08:00
parent f9a49f4473
commit 6b1edcb475
11 changed files with 876 additions and 1058 deletions

View file

@ -177,6 +177,14 @@ class PlaybackReporter {
deviceInfo: await _getDeviceInfo(),
forceDirectPlay: false,
forceTranscode: false,
supportedMimeTypes: [
"audio/flac",
"audio/mpeg",
"audio/mp4",
"audio/ogg",
"audio/aac",
"audio/webm",
],
),
responseErrorHandler: _responseErrorHandler,
);

View file

@ -8,7 +8,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:just_audio/just_audio.dart';
import 'package:logging/logging.dart';
import 'package:rxdart/rxdart.dart';
import 'package:shelfsdk/audiobookshelf_api.dart';
import 'package:shelfsdk/audiobookshelf_api.dart' hide NotificationSettings;
import 'package:vaani/features/player/core/player_status.dart' as core;
import 'package:vaani/features/player/providers/player_status_provider.dart';
import 'package:vaani/features/settings/app_settings_provider.dart';
@ -23,18 +23,20 @@ final _logger = Logger('AudiobookPlayer');
class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
final AudioPlayer _player = AudioPlayer();
// final List<AudioSource> _playlist = [];
final Ref ref;
BookExpanded? _book;
BookExpanded? get book => _book;
late NotificationSettings notificationSettings;
final _currentChapterObject = BehaviorSubject<BookChapter?>.seeded(null);
AbsAudioHandler(this.ref) {
_setupAudioPlayer();
}
void _setupAudioPlayer() {
ref.listen(appSettingsProvider, (a, b) {
if (a?.notificationSettings != b.notificationSettings) {
notificationSettings = b.notificationSettings;
}
});
final statusNotifier = ref.read(playerStatusProvider.notifier);
//
@ -49,6 +51,14 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
_player.positionStream.distinct().listen((position) {
final chapter = _book?.findChapterAtTime(positionInBook);
if (chapter != currentChapter) {
if (mediaItem.hasValue && chapter != null) {
updateMediaItem(
mediaItem.value!.copyWith(
duration: chapter.duration,
displayTitle: chapter.title,
),
);
}
_currentChapterObject.sink.add(chapter);
}
});
@ -75,6 +85,18 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
}
_book = book;
final trackToPlay = book.findTrackAtTime(initialPosition ?? Duration.zero);
final trackToChapter =
book.findChapterAtTime(initialPosition ?? Duration.zero);
final initialIndex = book.tracks.indexOf(trackToPlay);
final initialPositionInTrack = initialPosition != null
? initialPosition - trackToPlay.startOffset
: null;
final title = appSettings.notificationSettings.primaryTitle
.formatNotificationTitle(book);
final album = appSettings.notificationSettings.secondaryTitle
.formatNotificationTitle(book);
//
List<AudioSource> audioSources = book.tracks
.map(
@ -84,28 +106,18 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
)
.toList();
final title = appSettings.notificationSettings.primaryTitle
.formatNotificationTitle(book);
final album = appSettings.notificationSettings.secondaryTitle
.formatNotificationTitle(book);
playMediaItem(
MediaItem(
id: book.libraryItemId,
title: title,
album: album,
displayTitle: title,
displaySubtitle: album,
duration: book.duration,
artUri: Uri.parse(
'$baseUrl/api/items/${book.libraryItemId}/cover?token=$token',
),
final item = MediaItem(
id: book.libraryItemId,
title: title,
album: album,
displayTitle: title,
displaySubtitle: album,
duration: trackToChapter.duration,
artUri: Uri.parse(
'$baseUrl/api/items/${book.libraryItemId}/cover?token=$token',
),
);
final trackToPlay = book.findTrackAtTime(initialPosition ?? Duration.zero);
final initialIndex = book.tracks.indexOf(trackToPlay);
final initialPositionInTrack = initialPosition != null
? initialPosition - trackToPlay.startOffset
: null;
addQueueItem(item);
await _player
.setAudioSources(
audioSources,
@ -311,21 +323,35 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
PlaybackState _transformEvent(PlaybackEvent event) {
return PlaybackState(
controls: [
if (kIsWeb || !Platform.isAndroid) MediaControl.skipToPrevious,
MediaControl.rewind,
if ((kIsWeb || !Platform.isAndroid) &&
notificationSettings.mediaControls
.contains(NotificationMediaControl.skipToPreviousChapter))
MediaControl.skipToPrevious,
if (notificationSettings.mediaControls
.contains(NotificationMediaControl.rewind))
MediaControl.rewind,
if (_player.playing) MediaControl.pause else MediaControl.play,
MediaControl.stop,
MediaControl.fastForward,
if (kIsWeb || !Platform.isAndroid) MediaControl.skipToNext,
if (notificationSettings.mediaControls
.contains(NotificationMediaControl.fastForward))
MediaControl.fastForward,
if ((kIsWeb || !Platform.isAndroid) &&
notificationSettings.mediaControls
.contains(NotificationMediaControl.skipToNextChapter))
MediaControl.skipToNext,
if (notificationSettings.mediaControls
.contains(NotificationMediaControl.stop))
MediaControl.stop,
],
systemActions: {
if (kIsWeb || !Platform.isAndroid) MediaAction.skipToPrevious,
MediaAction.rewind,
// if (kIsWeb || !Platform.isAndroid) MediaAction.skipToPrevious,
// MediaAction.rewind,
MediaAction.seek,
MediaAction.fastForward,
MediaAction.stop,
MediaAction.setSpeed,
if (kIsWeb || !Platform.isAndroid) MediaAction.skipToNext,
MediaAction.seekForward,
MediaAction.seekBackward,
// MediaAction.fastForward,
// MediaAction.stop,
// MediaAction.setSpeed,
// if (kIsWeb || !Platform.isAndroid) MediaAction.skipToNext,
},
androidCompactActionIndices: const [1, 2, 3],
processingState: const {
@ -337,8 +363,8 @@ class AbsAudioHandler extends BaseAudioHandler with QueueHandler, SeekHandler {
}[_player.processingState] ??
AudioProcessingState.idle,
playing: _player.playing,
updatePosition: _player.position,
bufferedPosition: event.bufferedPosition,
updatePosition: positionInChapter,
bufferedPosition: _player.bufferedPosition,
speed: _player.speed,
queueIndex: event.currentIndex,
captioningEnabled: false,

View file

@ -1,20 +1,22 @@
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:just_audio_media_kit/just_audio_media_kit.dart';
import 'package:riverpod/riverpod.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:vaani/features/player/core/audiobook_player.dart';
import 'package:vaani/shared/utils/helper.dart';
part 'audiobook_player.g.dart';
@Riverpod(keepAlive: true)
Future<AbsAudioHandler> audioHandlerInit(Ref ref) async {
if (Helper.isWindows() || Helper.isLinux()) {
// JustAudioMediaKit.ensureInitialized(windows: false);
JustAudioMediaKit.ensureInitialized();
}
// for playing audio on windows, linux
JustAudioMediaKit.ensureInitialized();
final audioService = await AudioService.init(
// for configuring how this app will interact with other audio apps
final session = await AudioSession.instance;
await session.configure(const AudioSessionConfiguration.speech());
final audioService = AudioService.init(
builder: () => AbsAudioHandler(ref),
config: const AudioServiceConfig(
androidNotificationChannelId: 'dr.blank.vaani.channel.audio',

View file

@ -6,7 +6,7 @@ part of 'audiobook_player.dart';
// RiverpodGenerator
// **************************************************************************
String _$audioHandlerInitHash() => r'6e4662a45c1c6e84aa16436f71ffcfecc3d4bdab';
String _$audioHandlerInitHash() => r'13b9d56c8dfde3a40736432ea069c899ef35ae75';
/// See also [audioHandlerInit].
@ProviderFor(audioHandlerInit)