一堆乱七八糟的修改

播放页面增加桌面版
This commit is contained in:
rang 2025-11-28 17:05:35 +08:00
parent aee1fbde88
commit 3ba35b31b8
116 changed files with 1238 additions and 2592 deletions

View file

@ -1,71 +1,112 @@
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:logging/logging.dart';
import 'package:audio_service/audio_service.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:shelfsdk/audiobookshelf_api.dart' as shelfsdk;
import 'package:shelfsdk/audiobookshelf_api.dart' as core;
import 'package:vaani/api/api_provider.dart';
import 'package:vaani/features/player/core/audiobook_player.dart' as core;
import 'package:vaani/api/library_item_provider.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/audiobook_player.dart';
import 'package:vaani/features/player/providers/player_status_provider.dart';
import 'package:vaani/features/settings/app_settings_provider.dart';
import 'package:vaani/shared/extensions/model_conversions.dart';
import 'package:vaani/shared/utils/helper.dart';
part 'audiobook_player.g.dart';
final _logger = Logger('AudiobookPlayerProvider');
const playerId = 'audiobook_player';
/// Simple because it doesn't rebuild when the player state changes
/// it only rebuilds when the token changes
@Riverpod(keepAlive: true)
class SimpleAudiobookPlayer extends _$SimpleAudiobookPlayer {
Future<AbsAudioHandler> audioHandlerInit(Ref ref) async {
if (Helper.isWindows() || Helper.isLinux()) {
// JustAudioMediaKit.ensureInitialized(windows: false);
JustAudioMediaKit.ensureInitialized();
}
final audioService = await AudioService.init(
builder: () => AbsAudioHandler(ref),
config: const AudioServiceConfig(
androidNotificationChannelId: 'dr.blank.vaani.channel.audio',
androidNotificationChannelName: 'ABSPlayback',
androidNotificationChannelDescription:
'Needed to control audio from lock screen',
androidNotificationOngoing: false,
androidStopForegroundOnPause: false,
androidNotificationIcon: 'drawable/ic_stat_logo',
preloadArtwork: true,
),
);
return audioService;
}
@Riverpod(keepAlive: true)
class Player extends _$Player {
@override
core.AudiobookPlayer build() {
final api = ref.watch(authenticatedApiProvider);
final player = core.AudiobookPlayer(
api.token!,
api.baseUrl,
);
ref.onDispose(player.dispose);
_logger.finer('created simple player');
return player;
AbsAudioHandler build() {
return ref.watch(audioHandlerInitProvider).requireValue;
}
}
@Riverpod(keepAlive: true)
class AudiobookPlayer extends _$AudiobookPlayer {
class Session extends _$Session {
@override
core.AudiobookPlayer build() {
final player = ref.watch(simpleAudiobookPlayerProvider);
ref.onDispose(player.dispose);
// bind notify listeners to the player
// player.playerStateStream.listen((_) {
// ref.notifyListeners();
// });
_logger.finer('created player');
return player;
core.PlaybackSessionExpanded? build() {
return null;
}
Future<void> setSpeed(double speed) async {
await state.setSpeed(speed);
ref.notifyListeners();
}
Future<void> load(String id, String? episodeId) async {
final audioService = ref.read(playerProvider);
await audioService.pause();
ref.read(playerStatusProvider.notifier).setLoading(id);
final api = ref.read(authenticatedApiProvider);
final playBack = await ref.watch(playBackSessionProvider(id).future);
if (playBack == null) {
return;
}
state = playBack.asExpanded;
final downloadManager = ref.read(simpleDownloadManagerProvider);
final libItem =
await ref.read(libraryItemProvider(state!.libraryItemId).future);
final downloadedUris = await downloadManager.getDownloadedFilesUri(libItem);
Future<void> setSourceAudiobook({
required shelfsdk.BookExpanded book,
shelfsdk.MediaProgress? userMediaProgress,
}) async {
ref.notifyListeners();
var bookPlayerSettings =
ref.read(bookSettingsProvider(state!.libraryItemId)).playerSettings;
var appPlayerSettings = ref.read(appSettingsProvider).playerSettings;
var configurePlayerForEveryBook =
appPlayerSettings.configurePlayerForEveryBook;
await Future.wait([
audioService.setSourceAudiobook(
state!.asExpanded,
baseUrl: api.baseUrl,
token: api.token!,
downloadedUris: downloadedUris,
),
// set the volume
audioService.setVolume(
configurePlayerForEveryBook
? bookPlayerSettings.preferredDefaultVolume ??
appPlayerSettings.preferredDefaultVolume
: appPlayerSettings.preferredDefaultVolume,
),
// set the speed
audioService.setSpeed(
configurePlayerForEveryBook
? bookPlayerSettings.preferredDefaultSpeed ??
appPlayerSettings.preferredDefaultSpeed
: appPlayerSettings.preferredDefaultSpeed,
),
]);
}
}
@riverpod
bool isPlayerPlaying(
Ref ref,
) {
final player = ref.watch(audiobookPlayerProvider);
print("playing: ${player.playing}");
return player.playing;
class PlaybackSyncError implements Exception {
String message;
PlaybackSyncError([this.message = 'Error syncing playback']);
@override
String toString() {
return 'PlaybackSyncError: $message';
}
}