224 lines
6.2 KiB
Dart
224 lines
6.2 KiB
Dart
// Author: fengshengxiong
|
|
// Date: 2024/5/30
|
|
// Description: 音乐播放器控制器
|
|
|
|
import 'dart:async';
|
|
import 'dart:io';
|
|
|
|
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
|
|
import 'package:get/get.dart';
|
|
import 'package:just_audio/just_audio.dart';
|
|
import 'package:tone_snap/components/base_easyloading.dart';
|
|
import 'package:tone_snap/data/cache/music_cache_manager.dart';
|
|
import 'package:tone_snap/utils/audio_util.dart';
|
|
import 'package:tone_snap/utils/date_util.dart';
|
|
import 'package:tone_snap/utils/log_util.dart';
|
|
|
|
class MusicPlayerController extends GetxController {
|
|
static MusicPlayerController get to => Get.put(MusicPlayerController(), permanent: true);
|
|
final _player = AudioPlayer();
|
|
StreamSubscription<Duration>? _bufferedSubscription;
|
|
StreamSubscription<Duration?>? _durationSubscription;
|
|
StreamSubscription<Duration>? _positionSubscription;
|
|
StreamSubscription<PlayerState>? _playerStateSubscription;
|
|
|
|
/// 缓存管理器
|
|
// final cacheManager = DefaultCacheManager();
|
|
final cacheManager = MusicCacheManager.instance;
|
|
var cacheKey = '';
|
|
|
|
/// 是否正在从缓存播放中
|
|
var _isPlayingFromCache = false;
|
|
|
|
/// 当前播放的url
|
|
var currentUrl = '';
|
|
|
|
/// 是否正在播放
|
|
var isPlaying = false.obs;
|
|
|
|
/// 总时长、已播放的时长、缓冲时长
|
|
var totalDuration = Duration.zero.obs;
|
|
var positionDuration = Duration.zero.obs;
|
|
var bufferedDuration = Duration.zero.obs;
|
|
|
|
/// 记录进度条拖动前缓冲的位置
|
|
Duration? bufferedPosition;
|
|
|
|
/// 拖动前是否是播放状态
|
|
var seekFrontPlaying = true;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
AudioUtil.configAudioSession();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_cancelListening();
|
|
_player.dispose();
|
|
super.onClose();
|
|
}
|
|
|
|
/// 播放新的 url
|
|
Future<void> playNewUrl(String newUrl, String videoId) async {
|
|
await _initializePlayer(newUrl, videoId);
|
|
_player.play();
|
|
|
|
// 使用的 music_$videoId 作为唯一的 key
|
|
cacheKey = 'music_$videoId';
|
|
}
|
|
|
|
/// 设置 url 和监听器
|
|
Future<void> _initializePlayer(String url, String videoId) async {
|
|
try {
|
|
currentUrl = url;
|
|
// 检查是否有缓存
|
|
FileInfo? fileInfo = await cacheManager.getFileFromMemory(cacheKey);
|
|
if (fileInfo != null) {
|
|
LogUtil.d('有缓存,文件路径=${fileInfo.file.path}');
|
|
// 如果有缓存,使用缓存文件
|
|
await _player.setFilePath(fileInfo.file.path);
|
|
_isPlayingFromCache = true;
|
|
} else {
|
|
// 如果没有缓存,通过 url 加载音源并开始播放,同时启动缓存下载
|
|
await _player.setUrl(currentUrl);
|
|
_isPlayingFromCache = false;
|
|
|
|
// 下载并缓存文件
|
|
cacheManager.downloadFile(currentUrl, key: cacheKey).then((fileInfo) {
|
|
// 如果缓存下载完成且当前不是从缓存播放,切换到缓存文件
|
|
if (!_isPlayingFromCache) {
|
|
LogUtil.d('新歌曲缓存路径=${fileInfo.file.path}');
|
|
_player.setFilePath(fileInfo.file.path);
|
|
_isPlayingFromCache = true;
|
|
}
|
|
});
|
|
}
|
|
_player.setLoopMode(LoopMode.off);
|
|
_cancelListening();
|
|
_addListening();
|
|
} catch (e) {
|
|
LogUtil.e('Error initializing player: $e');
|
|
BaseEasyLoading.toast('Error initializing player');
|
|
}
|
|
}
|
|
|
|
/// 播放/暂停
|
|
Future<void> playPause() async {
|
|
if (_player.playing) {
|
|
_player.pause();
|
|
} else {
|
|
if (_player.processingState == ProcessingState.idle) {
|
|
BaseEasyLoading.loading();
|
|
await _player.load();
|
|
BaseEasyLoading.dismiss();
|
|
}
|
|
_player.play();
|
|
}
|
|
}
|
|
|
|
/// 停止播放
|
|
void stopPlay() {
|
|
_player.stop();
|
|
_player.seek(Duration.zero);
|
|
positionDuration.value = Duration.zero;
|
|
}
|
|
|
|
/// 将播放器的播放位置设置为指定的时间
|
|
void seekToPosition(double value) {
|
|
if (_player.processingState == ProcessingState.ready) {
|
|
positionDuration.value = Duration(seconds: value.toInt());
|
|
_player.seek(positionDuration.value);
|
|
}
|
|
}
|
|
|
|
/// 开始/结束拖动进度条
|
|
Future<void> seekStartEnd(int value) async {
|
|
bufferedPosition = _player.bufferedPosition;
|
|
if (_player.processingState == ProcessingState.ready) {
|
|
if (value == 0) {
|
|
seekFrontPlaying = _player.playing;
|
|
if (_player.playing) {
|
|
_player.pause();
|
|
}
|
|
} else {
|
|
// 拖动前如果是播放状态,拖动完成后恢复播放,否则相反
|
|
if (seekFrontPlaying) {
|
|
_player.play();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// 上一首
|
|
void seekToPrevious() {
|
|
_player.seekToPrevious();
|
|
}
|
|
|
|
/// 下一首
|
|
void seekToNext() {
|
|
_player.seekToNext();
|
|
}
|
|
|
|
/// 监听
|
|
void _addListening() {
|
|
_bufferedSubscription = _player.bufferedPositionStream.listen((bufferedPosition) {
|
|
bufferedDuration.value = bufferedPosition;
|
|
});
|
|
|
|
_durationSubscription = _player.durationStream.listen((duration) {
|
|
totalDuration.value = duration ?? Duration.zero;
|
|
});
|
|
|
|
_positionSubscription = _player.positionStream.listen((position) {
|
|
positionDuration.value = position;
|
|
});
|
|
|
|
_playerStateSubscription = _player.playerStateStream.listen((playerState) {
|
|
isPlaying.value = _player.playing;
|
|
switch (playerState.processingState) {
|
|
case ProcessingState.idle:
|
|
break;
|
|
case ProcessingState.loading:
|
|
break;
|
|
case ProcessingState.buffering:
|
|
break;
|
|
case ProcessingState.ready:
|
|
break;
|
|
case ProcessingState.completed:
|
|
stopPlay();
|
|
break;
|
|
}
|
|
});
|
|
}
|
|
|
|
/// 取消监听
|
|
void _cancelListening() {
|
|
_bufferedSubscription?.cancel();
|
|
_durationSubscription?.cancel();
|
|
_positionSubscription?.cancel();
|
|
_playerStateSubscription?.cancel();
|
|
}
|
|
|
|
/// 返回格式化后的总时长
|
|
String getTotalDuration() {
|
|
return DateUtil.playDuration(totalDuration.value);
|
|
}
|
|
|
|
/// 返回格式化后的已持续时间
|
|
String getPositionDuration() {
|
|
return DateUtil.playDuration(positionDuration.value);
|
|
}
|
|
|
|
/// 文件是否存在
|
|
Future<bool> _fileExists(String path) async {
|
|
if (await File(path).exists()) {
|
|
return true;
|
|
} else {
|
|
BaseEasyLoading.toast('Local resource does not exist');
|
|
return false;
|
|
}
|
|
}
|
|
}
|