Files
PiliPlus/lib/services/audio_handler.dart
bggRGjQaUbCoE f0e2a63d11 opt pgc
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-08-02 18:00:17 +08:00

235 lines
6.8 KiB
Dart

import 'package:PiliPlus/models_new/live/live_room_info_h5/data.dart';
import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart';
import 'package:PiliPlus/models_new/video/video_detail/data.dart';
import 'package:PiliPlus/plugin/pl_player/controller.dart';
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:audio_service/audio_service.dart';
import 'package:get/get_utils/get_utils.dart';
Future<VideoPlayerServiceHandler> initAudioService() async {
return AudioService.init(
builder: () => VideoPlayerServiceHandler(),
config: const AudioServiceConfig(
androidNotificationChannelId: 'com.example.piliplus.audio',
androidNotificationChannelName: 'Audio Service PiliPlus',
androidNotificationOngoing: true,
androidStopForegroundOnPause: true,
fastForwardInterval: Duration(seconds: 10),
rewindInterval: Duration(seconds: 10),
androidNotificationChannelDescription: 'Media notification channel',
androidNotificationIcon: 'drawable/ic_notification_icon',
),
);
}
class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
static final List<MediaItem> _item = [];
bool enableBackgroundPlay = Pref.enableBackgroundPlay;
@override
Future<void> play() async {
PlPlayerController.playIfExists();
// player.play();
}
@override
Future<void> pause() async {
await PlPlayerController.pauseIfExists();
// player.pause();
}
@override
Future<void> seek(Duration position) async {
playbackState.add(
playbackState.value.copyWith(
updatePosition: position,
),
);
await PlPlayerController.seekToIfExists(position, isSeek: false);
// await player.seekTo(position);
}
Future<void> setMediaItem(MediaItem newMediaItem) async {
if (!enableBackgroundPlay) return;
// if (kDebugMode) {
// debugPrint("此时调用栈为:");
// debugPrint(newMediaItem);
// debugPrint(newMediaItem.title);
// debugPrint(StackTrace.current.toString());
// }
if (!mediaItem.isClosed) mediaItem.add(newMediaItem);
}
Future<void> setPlaybackState(
PlayerStatus status,
bool isBuffering,
bool isLive,
) async {
if (!enableBackgroundPlay ||
_item.isEmpty ||
!PlPlayerController.instanceExists()) {
return;
}
final AudioProcessingState processingState;
final playing = status == PlayerStatus.playing;
if (status == PlayerStatus.completed) {
processingState = AudioProcessingState.completed;
} else if (isBuffering) {
processingState = AudioProcessingState.buffering;
} else {
processingState = AudioProcessingState.ready;
}
playbackState.add(
playbackState.value.copyWith(
processingState: isBuffering
? AudioProcessingState.buffering
: processingState,
controls: [
if (!isLive)
MediaControl.rewind.copyWith(
androidIcon: 'drawable/ic_baseline_replay_10_24',
),
if (playing) MediaControl.pause else MediaControl.play,
if (!isLive)
MediaControl.fastForward.copyWith(
androidIcon: 'drawable/ic_baseline_forward_10_24',
),
],
playing: playing,
systemActions: const {
MediaAction.seek,
},
),
);
}
void onStatusChange(PlayerStatus status, bool isBuffering, isLive) {
if (!enableBackgroundPlay) return;
if (_item.isEmpty) return;
setPlaybackState(status, isBuffering, isLive);
}
void onVideoDetailChange(
dynamic data,
int cid,
String herotag, {
String? artist,
}) {
if (!enableBackgroundPlay) return;
// if (kDebugMode) {
// debugPrint('当前调用栈为:');
// debugPrint(StackTrace.current);
// }
if (!PlPlayerController.instanceExists()) return;
if (data == null) return;
late final id = '$cid$herotag';
MediaItem? mediaItem;
if (data is VideoDetailData) {
if ((data.pages?.length ?? 0) > 1) {
final current = data.pages?.firstWhereOrNull(
(element) => element.cid == cid,
);
mediaItem = MediaItem(
id: id,
title: current?.pagePart ?? '',
artist: data.owner?.name,
duration: Duration(seconds: current?.duration ?? 0),
artUri: Uri.parse(data.pic ?? ''),
);
} else {
mediaItem = MediaItem(
id: id,
title: data.title ?? '',
artist: data.owner?.name,
duration: Duration(seconds: data.duration ?? 0),
artUri: Uri.parse(data.pic ?? ''),
);
}
} else if (data is EpisodeItem) {
mediaItem = MediaItem(
id: id,
title: data.showTitle ?? data.title ?? '',
artist: artist,
duration: Duration(milliseconds: data.duration ?? 0),
artUri: Uri.parse(data.cover ?? ''),
);
} else if (data is RoomInfoH5Data) {
mediaItem = MediaItem(
id: id,
title: data.roomInfo?.title ?? '',
artist: data.anchorInfo?.baseInfo?.uname,
artUri: Uri.parse(data.roomInfo?.cover ?? ''),
isLive: true,
);
}
if (mediaItem == null) return;
// if (kDebugMode) debugPrint("exist: ${PlPlayerController.instanceExists()}");
if (!PlPlayerController.instanceExists()) return;
_item.add(mediaItem);
setMediaItem(mediaItem);
}
void onVideoDetailDispose(String herotag) {
if (!enableBackgroundPlay) return;
if (_item.isNotEmpty) {
_item.removeWhere((item) => item.id.endsWith(herotag));
}
if (_item.isNotEmpty) {
playbackState.add(
playbackState.value.copyWith(
processingState: AudioProcessingState.idle,
playing: false,
),
);
setMediaItem(_item.last);
stop();
}
}
void clear() {
if (!enableBackgroundPlay) return;
mediaItem.add(null);
_item.clear();
/**
* if (playbackState.processingState == AudioProcessingState.idle &&
previousState?.processingState != AudioProcessingState.idle) {
await AudioService._stop();
}
*/
if (playbackState.value.processingState == AudioProcessingState.idle) {
playbackState.add(
PlaybackState(
processingState: AudioProcessingState.completed,
playing: false,
),
);
}
playbackState.add(
PlaybackState(
processingState: AudioProcessingState.idle,
playing: false,
),
);
}
void onPositionChange(Duration position) {
if (!enableBackgroundPlay ||
_item.isEmpty ||
!PlPlayerController.instanceExists()) {
return;
}
playbackState.add(
playbackState.value.copyWith(
updatePosition: position,
),
);
}
}