This commit is contained in:
rang 2025-12-24 18:02:24 +08:00
parent 04fe06d1ac
commit bd9e985697
13 changed files with 1036 additions and 878 deletions

View file

@ -1,17 +1,22 @@
import 'package:audio_service/audio_service.dart';
import 'package:audio_session/audio_session.dart';
import 'package:collection/collection.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
import 'package:shelfsdk/audiobookshelf_api.dart' as api;
import 'package:vaani/api/api_provider.dart';
import 'package:vaani/api/library_item_provider.dart';
import 'package:vaani/db/available_boxes.dart';
import 'package:vaani/db/cache/cache_key.dart';
import 'package:vaani/features/downloads/providers/download_manager.dart';
import 'package:vaani/features/per_book_settings/providers/book_settings_provider.dart';
import 'package:vaani/features/player/core/abs_audio_handler.dart';
import 'package:vaani/features/player/core/abs_audio_player.dart' as core;
import 'package:vaani/features/player/core/abs_audio_player_platform.dart';
import 'package:vaani/features/settings/app_settings_provider.dart';
import 'package:vaani/shared/extensions/box.dart';
import 'package:vaani/shared/extensions/model_conversions.dart';
part 'abs_provider.g.dart';
@ -48,34 +53,33 @@ Future<AudioHandler> configurePlayer(Ref ref) async {
}
// just_audio
// @Riverpod(keepAlive: true)
// AudioPlayer audioPlayer(Ref ref) {
// //
// // prefetch-playlist=yes
// JustAudioMediaKit.prefetchPlaylist = true;
// // merge-files=yes
// // cache=yes
// // cache-pause-wait=60
@Riverpod(keepAlive: true)
core.AbsAudioPlayer audioPlayer(Ref ref) {
final player = AbsPlatformAudioPlayer();
// final player = AbsMpvAudioPlayer();
ref.onDispose(player.dispose);
return player;
}
// JustAudioMediaKit.ensureInitialized();
// return AudioPlayer();
// }
//
@riverpod
bool playerActive(Ref ref) {
return false;
}
/// riverpod状态
@Riverpod(keepAlive: true)
class AbsPlayer extends _$AbsPlayer {
@override
core.AbsAudioPlayer build() {
// final audioPlayer = ref.watch(audioPlayerProvider);
// final player = AbsMpvAudioPlayer();
final player = AbsPlatformAudioPlayer();
ref.onDispose(player.dispose);
return player;
final audioPlayer = ref.watch(audioPlayerProvider);
return audioPlayer;
}
Future<void> load(
api.BookExpanded book, {
Duration? initialPosition,
bool play = true,
}) async {
if (state.book == book || state.book?.libraryItemId == book.libraryItemId) {
state.playOrPause();
@ -88,14 +92,13 @@ class AbsPlayer extends _$AbsPlayer {
await ref.read(libraryItemProvider(book.libraryItemId).future);
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
var bookPlayerSettings =
ref.read(bookSettingsProvider(book.libraryItemId)).playerSettings;
final bookSettings = ref.read(bookSettingsProvider(book.libraryItemId));
var bookPlayerSettings = bookSettings.playerSettings;
var appPlayerSettings = ref.read(appSettingsProvider).playerSettings;
var configurePlayerForEveryBook =
appPlayerSettings.configurePlayerForEveryBook;
final bookSettings = ref.watch(bookSettingsProvider(book.libraryItemId));
await state.load(
book,
baseUrl: api.baseUrl,
@ -119,7 +122,7 @@ class AbsPlayer extends _$AbsPlayer {
appPlayerSettings.preferredDefaultSpeed
: appPlayerSettings.preferredDefaultSpeed,
);
await state.play();
if (play) await state.play();
}
}
@ -149,26 +152,57 @@ class PlayerState extends _$PlayerState {
}
@riverpod
class CurrentBook extends _$CurrentBook {
@override
api.BookExpanded? build() {
final player = ref.read(absPlayerProvider);
player.bookStream.listen((book) {
if (book != state) {
state = book;
}
});
return player.book;
}
Duration? currentTime(Ref ref, String libraryItemId) {
final me = ref.watch(meProvider);
final userProgress = me.valueOrNull?.mediaProgress
?.firstWhereOrNull((element) => element.libraryItemId == libraryItemId);
return userProgress?.currentTime;
}
@riverpod
bool isPlayerActive(Ref ref) {
final player = ref.read(absPlayerProvider);
player.bookStream.listen((book) {
ref.invalidateSelf();
});
return player.book != null;
class CurrentBook extends _$CurrentBook {
@override
api.BookExpanded? build() {
listenSelf((previous, next) {
if (previous == null) {
final activeLibraryItemId = AvailableHiveBoxes.basicBox
.getAs<String>(CacheKey.activeLibraryItemId);
if (activeLibraryItemId != null) {
update(activeLibraryItemId, play: false);
}
}
});
return null;
}
// @override
// api.BookExpanded? build() {
// final player = ref.read(absPlayerProvider);
// player.bookStream.listen((book) {
// if (book != state) {
// state = book;
// }
// });
// return player.book;
// }
Future<void> update(String libraryItemId, {bool play = true}) async {
if (state?.libraryItemId == libraryItemId) {
ref.read(audioPlayerProvider).playOrPause();
return;
}
final book = await ref.read(libraryItemProvider(libraryItemId).future);
state = book.media.asBookExpanded;
final currentTime = ref.read(currentTimeProvider(libraryItemId));
await ref
.read(absPlayerProvider.notifier)
.load(state!, initialPosition: currentTime, play: play);
if (play) {
AvailableHiveBoxes.basicBox.put(
CacheKey.activeLibraryItemId,
libraryItemId,
);
}
}
}
@riverpod

View file

@ -25,23 +25,189 @@ final configurePlayerProvider = FutureProvider<AudioHandler>.internal(
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef ConfigurePlayerRef = FutureProviderRef<AudioHandler>;
String _$isPlayerActiveHash() => r'4fca4af53a17dbcd7c8a98ce115bc11fa39b4cf9';
String _$audioPlayerHash() => r'156f85effafdcd287db88e455e8f4f4d33c41a0e';
/// See also [isPlayerActive].
@ProviderFor(isPlayerActive)
final isPlayerActiveProvider = AutoDisposeProvider<bool>.internal(
isPlayerActive,
name: r'isPlayerActiveProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$isPlayerActiveHash,
/// See also [audioPlayer].
@ProviderFor(audioPlayer)
final audioPlayerProvider = Provider<core.AbsAudioPlayer>.internal(
audioPlayer,
name: r'audioPlayerProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$audioPlayerHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef IsPlayerActiveRef = AutoDisposeProviderRef<bool>;
typedef AudioPlayerRef = ProviderRef<core.AbsAudioPlayer>;
String _$playerActiveHash() => r'86831758035aa69d74f42ebde0a19bf7ef830910';
/// See also [playerActive].
@ProviderFor(playerActive)
final playerActiveProvider = AutoDisposeProvider<bool>.internal(
playerActive,
name: r'playerActiveProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product') ? null : _$playerActiveHash,
dependencies: null,
allTransitiveDependencies: null,
);
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef PlayerActiveRef = AutoDisposeProviderRef<bool>;
String _$currentTimeHash() => r'079945f118884b57d2e038117c7a7a5b873bc7d1';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
/// See also [currentTime].
@ProviderFor(currentTime)
const currentTimeProvider = CurrentTimeFamily();
/// See also [currentTime].
class CurrentTimeFamily extends Family<Duration?> {
/// See also [currentTime].
const CurrentTimeFamily();
/// See also [currentTime].
CurrentTimeProvider call(
String libraryItemId,
) {
return CurrentTimeProvider(
libraryItemId,
);
}
@override
CurrentTimeProvider getProviderOverride(
covariant CurrentTimeProvider provider,
) {
return call(
provider.libraryItemId,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'currentTimeProvider';
}
/// See also [currentTime].
class CurrentTimeProvider extends AutoDisposeProvider<Duration?> {
/// See also [currentTime].
CurrentTimeProvider(
String libraryItemId,
) : this._internal(
(ref) => currentTime(
ref as CurrentTimeRef,
libraryItemId,
),
from: currentTimeProvider,
name: r'currentTimeProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$currentTimeHash,
dependencies: CurrentTimeFamily._dependencies,
allTransitiveDependencies:
CurrentTimeFamily._allTransitiveDependencies,
libraryItemId: libraryItemId,
);
CurrentTimeProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.libraryItemId,
}) : super.internal();
final String libraryItemId;
@override
Override overrideWith(
Duration? Function(CurrentTimeRef provider) create,
) {
return ProviderOverride(
origin: this,
override: CurrentTimeProvider._internal(
(ref) => create(ref as CurrentTimeRef),
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
libraryItemId: libraryItemId,
),
);
}
@override
AutoDisposeProviderElement<Duration?> createElement() {
return _CurrentTimeProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is CurrentTimeProvider && other.libraryItemId == libraryItemId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, libraryItemId.hashCode);
return _SystemHash.finish(hash);
}
}
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
mixin CurrentTimeRef on AutoDisposeProviderRef<Duration?> {
/// The parameter `libraryItemId` of this provider.
String get libraryItemId;
}
class _CurrentTimeProviderElement extends AutoDisposeProviderElement<Duration?>
with CurrentTimeRef {
_CurrentTimeProviderElement(super.provider);
@override
String get libraryItemId => (origin as CurrentTimeProvider).libraryItemId;
}
String _$positionChapterHash() => r'ac6148e92363fad849713c07045503653dcaa7e8';
/// See also [positionChapter].
@ -77,7 +243,7 @@ final currentChaptersProvider =
@Deprecated('Will be removed in 3.0. Use Ref instead')
// ignore: unused_element
typedef CurrentChaptersRef = AutoDisposeProviderRef<List<api.BookChapter>>;
String _$absPlayerHash() => r'dfb4a8e9778d44143ec7589a99c6295c32c64c4a';
String _$absPlayerHash() => r'74a59dbf0f9396fef6bb60363fb186f5e4619a63';
/// riverpod状态
///
@ -109,7 +275,7 @@ final playerStateProvider =
);
typedef _$PlayerState = AutoDisposeNotifier<core.AbsPlayerState>;
String _$currentBookHash() => r'f511c6f16c17696e41c6384c5195646a419deae3';
String _$currentBookHash() => r'eed66894cb003d9d8ebd7b128d6ebb4efd5cda1b';
/// See also [CurrentBook].
@ProviderFor(CurrentBook)