diff --git a/ios/Podfile.lock b/ios/Podfile.lock index 22ff5ac..0f49283 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -8,48 +8,12 @@ PODS: - Flutter - device_info_plus (0.0.1): - Flutter - - DKImagePickerController/Core (4.3.9): - - DKImagePickerController/ImageDataManager - - DKImagePickerController/Resource - - DKImagePickerController/ImageDataManager (4.3.9) - - DKImagePickerController/PhotoGallery (4.3.9): - - DKImagePickerController/Core - - DKPhotoGallery - - DKImagePickerController/Resource (4.3.9) - - DKPhotoGallery (0.0.19): - - DKPhotoGallery/Core (= 0.0.19) - - DKPhotoGallery/Model (= 0.0.19) - - DKPhotoGallery/Preview (= 0.0.19) - - DKPhotoGallery/Resource (= 0.0.19) - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Core (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Preview - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Model (0.0.19): - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Preview (0.0.19): - - DKPhotoGallery/Model - - DKPhotoGallery/Resource - - SDWebImage - - SwiftyGif - - DKPhotoGallery/Resource (0.0.19): - - SDWebImage - - SwiftyGif - - file_picker (0.0.1): - - DKImagePickerController/PhotoGallery - - Flutter - Flutter (1.0.0) - isar_flutter_libs (1.0.0): - Flutter - just_audio (0.0.1): - Flutter - FlutterMacOS - - media_kit_libs_ios_audio (1.0.4): - - Flutter - package_info_plus (0.4.5): - Flutter - path_provider_foundation (0.0.1): @@ -57,9 +21,6 @@ PODS: - FlutterMacOS - permission_handler_apple (9.3.0): - Flutter - - SDWebImage (5.21.3): - - SDWebImage/Core (= 5.21.3) - - SDWebImage/Core (5.21.3) - sensors_plus (0.0.1): - Flutter - share_plus (0.0.1): @@ -67,7 +28,6 @@ PODS: - sqflite_darwin (0.0.4): - Flutter - FlutterMacOS - - SwiftyGif (5.4.5) - url_launcher_ios (0.0.1): - Flutter - vibration (3.0.0): @@ -78,11 +38,9 @@ DEPENDENCIES: - audio_session (from `.symlinks/plugins/audio_session/ios`) - background_downloader (from `.symlinks/plugins/background_downloader/ios`) - device_info_plus (from `.symlinks/plugins/device_info_plus/ios`) - - file_picker (from `.symlinks/plugins/file_picker/ios`) - Flutter (from `Flutter`) - isar_flutter_libs (from `.symlinks/plugins/isar_flutter_libs/ios`) - just_audio (from `.symlinks/plugins/just_audio/darwin`) - - media_kit_libs_ios_audio (from `.symlinks/plugins/media_kit_libs_ios_audio/ios`) - package_info_plus (from `.symlinks/plugins/package_info_plus/ios`) - path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/darwin`) - permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`) @@ -92,13 +50,6 @@ DEPENDENCIES: - url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`) - vibration (from `.symlinks/plugins/vibration/ios`) -SPEC REPOS: - trunk: - - DKImagePickerController - - DKPhotoGallery - - SDWebImage - - SwiftyGif - EXTERNAL SOURCES: audio_service: :path: ".symlinks/plugins/audio_service/darwin" @@ -108,16 +59,12 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/background_downloader/ios" device_info_plus: :path: ".symlinks/plugins/device_info_plus/ios" - file_picker: - :path: ".symlinks/plugins/file_picker/ios" Flutter: :path: Flutter isar_flutter_libs: :path: ".symlinks/plugins/isar_flutter_libs/ios" just_audio: :path: ".symlinks/plugins/just_audio/darwin" - media_kit_libs_ios_audio: - :path: ".symlinks/plugins/media_kit_libs_ios_audio/ios" package_info_plus: :path: ".symlinks/plugins/package_info_plus/ios" path_provider_foundation: @@ -140,21 +87,15 @@ SPEC CHECKSUMS: audio_session: 19e9480dbdd4e5f6c4543826b2e8b0e4ab6145fe background_downloader: a05c77d32a0d70615b9c04577aa203535fc924ff device_info_plus: bf2e3232933866d73fe290f2942f2156cdd10342 - DKImagePickerController: 946cec48c7873164274ecc4624d19e3da4c1ef3c - DKPhotoGallery: b3834fecb755ee09a593d7c9e389d8b5d6deed60 - file_picker: b159e0c068aef54932bb15dc9fd1571818edaf49 Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7 isar_flutter_libs: b69f437aeab9c521821c3f376198c4371fa21073 just_audio: a42c63806f16995daf5b219ae1d679deb76e6a79 - media_kit_libs_ios_audio: 8f39d96a9c630685dfb844c289bd1d114c486fb3 package_info_plus: c0502532a26c7662a62a356cebe2692ec5fe4ec4 path_provider_foundation: 2b6b4c569c0fb62ec74538f866245ac84301af46 permission_handler_apple: 9878588469a2b0d0fc1e048d9f43605f92e6cec2 - SDWebImage: 16309af6d214ba3f77a7c6f6fdda888cb313a50a sensors_plus: 7229095999f30740798f0eeef5cd120357a8f4f2 share_plus: 8b6f8b3447e494cca5317c8c3073de39b3600d1f sqflite_darwin: 5a7236e3b501866c1c9befc6771dfd73ffb8702d - SwiftyGif: 706c60cf65fa2bc5ee0313beece843c8eb8194d4 url_launcher_ios: 5334b05cef931de560670eeae103fd3e431ac3fe vibration: 3797858f8cbf53d841e189ef8bd533d96e4ca93c diff --git a/lib/features/player/core/abs_audio_player.dart b/lib/features/player/core/abs_audio_player.dart index c619336..9ffc142 100644 --- a/lib/features/player/core/abs_audio_player.dart +++ b/lib/features/player/core/abs_audio_player.dart @@ -26,6 +26,7 @@ abstract class AbsAudioPlayer { final chapterStreamController = BehaviorSubject.seeded(null); BookExpanded? get book => _bookStreamController.nvalue; + AudioTrack? get currentTrack => book?.tracks[currentIndex]; BookChapter? get currentChapter => chapterStreamController.nvalue; AbsPlayerState get playerState => playerStateSubject.value; Stream get mediaItemStream => _mediaItemController.stream; @@ -68,8 +69,8 @@ abstract class AbsAudioPlayer { _mediaItemController.sink.add(item); final playlist = book.tracks .map( - (track) => _getUri(currentTrack, downloadedUris, - baseUrl: baseUrl, token: token), + (track) => + _getUri(track, downloadedUris, baseUrl: baseUrl, token: token), ) .toList(); await setPlayList(playlist, index: indexTrack, position: positionInTrack); diff --git a/lib/features/player/core/abs_audio_player_platform.dart b/lib/features/player/core/abs_audio_player_platform.dart index e9fc341..5233b4f 100644 --- a/lib/features/player/core/abs_audio_player_platform.dart +++ b/lib/features/player/core/abs_audio_player_platform.dart @@ -26,9 +26,13 @@ class AbsPlatformAudioPlayer extends AbsAudioPlayer { ); }); player.positionStream.distinct().listen((position) { - final chapter = book?.findChapterAtTime(positionInBook); - if (chapter != currentChapter) { - chapterStreamController.add(chapter); + final chapter = currentChapter; + if (positionInBook <= (chapter?.start ?? Duration.zero) || + positionInBook <= (chapter?.end ?? Duration.zero)) { + final chapter = book?.findChapterAtTime(positionInBook); + if (chapter != currentChapter) { + chapterStreamController.add(chapter); + } } }); } @@ -103,4 +107,10 @@ class AbsPlatformAudioPlayer extends AbsAudioPlayer { @override double get speed => player.speed; + + @override + void dispose() { + super.dispose(); + player.dispose(); + } } diff --git a/lib/features/player/core/init.dart b/lib/features/player/core/init.dart index bac1d2c..121a80e 100644 --- a/lib/features/player/core/init.dart +++ b/lib/features/player/core/init.dart @@ -1,32 +1,34 @@ -import 'package:audio_service/audio_service.dart'; -import 'package:audio_session/audio_session.dart'; -import 'package:vaani/features/player/core/abs_audio_handler.dart' as core; -import 'package:vaani/features/player/core/abs_audio_player.dart'; -import 'package:vaani/globals.dart'; +// import 'package:audio_service/audio_service.dart'; +// import 'package:audio_session/audio_session.dart'; +// import 'package:riverpod_annotation/riverpod_annotation.dart'; +// import 'package:vaani/features/player/core/abs_audio_handler.dart' as core; +// import 'package:vaani/features/player/core/abs_audio_player.dart'; +// import 'package:vaani/globals.dart'; -/// 音频播放器 配置 -Future configurePlayer(AbsAudioPlayer player) async { - // for playing audio on windows, linux +// /// 音频播放器 配置 +// @Riverpod(keepAlive: true) +// Future configurePlayer(AbsAudioPlayer player) async { +// // for playing audio on windows, linux - // for configuring how this app will interact with other audio apps - final session = await AudioSession.instance; - await session.configure(const AudioSessionConfiguration.speech()); +// // for configuring how this app will interact with other audio apps +// final session = await AudioSession.instance; +// await session.configure(const AudioSessionConfiguration.speech()); - await AudioService.init( - builder: () => core.AbsAudioHandler(player), - 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, - // fastForwardInterval: Duration(seconds: 20), - // rewindInterval: Duration(seconds: 20), - ), - ); +// await AudioService.init( +// builder: () => core.AbsAudioHandler(player), +// 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, +// // fastForwardInterval: Duration(seconds: 20), +// // rewindInterval: Duration(seconds: 20), +// ), +// ); - appLogger.finer('created simple player'); -} +// appLogger.finer('created simple player'); +// } diff --git a/lib/features/player/providers/abs_provider.dart b/lib/features/player/providers/abs_provider.dart index e6c648a..e385d71 100644 --- a/lib/features/player/providers/abs_provider.dart +++ b/lib/features/player/providers/abs_provider.dart @@ -1,13 +1,48 @@ +import 'package:audio_service/audio_service.dart'; +import 'package:audio_session/audio_session.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/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'; part 'abs_provider.g.dart'; -// final _logger = Logger('AbsPlayerProvider'); +final _logger = Logger('AbsPlayerProvider'); + +/// 音频播放器 配置 +@Riverpod(keepAlive: true) +Future configurePlayer(Ref ref) async { + final player = ref.read(audioPlayerProvider); + // for playing audio on windows, linux + + // for configuring how this app will interact with other audio apps + final session = await AudioSession.instance; + await session.configure(const AudioSessionConfiguration.speech()); + + final audioService = await AudioService.init( + builder: () => AbsAudioHandler(player), + 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, + // fastForwardInterval: Duration(seconds: 20), + // rewindInterval: Duration(seconds: 20), + ), + ); + + _logger.finer('created simple player'); + return audioService; +} + /// 音频播放器 riverpod状态 @Riverpod(keepAlive: true) class AudioPlayer extends _$AudioPlayer { @@ -15,6 +50,7 @@ class AudioPlayer extends _$AudioPlayer { core.AbsAudioPlayer build() { // final player = AbsMpvAudioPlayer(); final player = AbsPlatformAudioPlayer(); + ref.onDispose(player.dispose); return player; } diff --git a/lib/features/player/providers/abs_provider.g.dart b/lib/features/player/providers/abs_provider.g.dart index 7a07880..dacc6ae 100644 --- a/lib/features/player/providers/abs_provider.g.dart +++ b/lib/features/player/providers/abs_provider.g.dart @@ -6,6 +6,25 @@ part of 'abs_provider.dart'; // RiverpodGenerator // ************************************************************************** +String _$configurePlayerHash() => r'7e7003c815e7d240a67cd581931839cc60346707'; + +/// 音频播放器 配置 +/// +/// Copied from [configurePlayer]. +@ProviderFor(configurePlayer) +final configurePlayerProvider = FutureProvider.internal( + configurePlayer, + name: r'configurePlayerProvider', + debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product') + ? null + : _$configurePlayerHash, + dependencies: null, + allTransitiveDependencies: null, +); + +@Deprecated('Will be removed in 3.0. Use Ref instead') +// ignore: unused_element +typedef ConfigurePlayerRef = FutureProviderRef; String _$isPlayerActiveHash() => r'71a24418ecf6c1a2d8160b0d0c8fc523d5679e76'; /// See also [isPlayerActive]. @@ -58,7 +77,7 @@ final currentChaptersProvider = @Deprecated('Will be removed in 3.0. Use Ref instead') // ignore: unused_element typedef CurrentChaptersRef = AutoDisposeProviderRef>; -String _$audioPlayerHash() => r'26387ece7f0d0c0cc21dc7641853e643866726f6'; +String _$audioPlayerHash() => r'e0efa20f340adf3312a76e5ca9e0c8ab0273a22a'; /// 音频播放器 riverpod状态 /// diff --git a/lib/features/skip_start_end/core/skip_start_end.dart b/lib/features/skip_start_end/core/skip_start_end.dart index 7cc7d5c..3b60f84 100644 --- a/lib/features/skip_start_end/core/skip_start_end.dart +++ b/lib/features/skip_start_end/core/skip_start_end.dart @@ -23,10 +23,13 @@ class SkipStartEnd { player.chapterStream.listen((chapter) { if (chapter != null && player.positionInChapter < Duration(seconds: 1)) { - Future.microtask( - () => throttlerStart - .call(() => player.seekInBook(chapter.start + start)), - ); + // player.pause(); + player.seekInBook(chapter.start + start); + // player.play(); + // Future.microtask( + // () => throttlerStart + // .call(() => player.seekInBook(chapter.start + start)), + // ); } }), ); diff --git a/lib/framework.dart b/lib/framework.dart index adb88d0..2eb8d1f 100644 --- a/lib/framework.dart +++ b/lib/framework.dart @@ -21,7 +21,7 @@ class Framework extends ConsumerWidget { ref.watch(simpleDownloadManagerProvider); if (Helper.isAndroid()) ref.watch(shakeDetectorProvider); ref.watch(sleepTimerProvider); - // ref.watch(skipStartEndProvider); + ref.watch(skipStartEndProvider); ref.watch(playbackReporterProvider); } catch (e) { debugPrintStack(stackTrace: StackTrace.current, label: e.toString()); diff --git a/lib/main.dart b/lib/main.dart index 2d1256c..ca51d17 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -8,7 +8,6 @@ import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:vaani/api/server_provider.dart'; import 'package:vaani/db/storage.dart'; import 'package:vaani/features/logging/core/logger.dart'; -import 'package:vaani/features/player/core/init.dart'; import 'package:vaani/features/player/providers/abs_provider.dart'; import 'package:vaani/features/settings/api_settings_provider.dart'; import 'package:vaani/features/settings/app_settings_provider.dart'; @@ -38,8 +37,7 @@ void main() async { // initialize audio player // await configurePlayer(); - final player = container.read(audioPlayerProvider); - await configurePlayer(player); + await container.read(configurePlayerProvider.future); // run the app runApp( UncontrolledProviderScope(