You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

476 lines
14 KiB

import 'dart:async';
import 'package:get/get.dart';
import 'package:qq_music/qq_music.dart';
import '../models/song_model.dart';
/// QQ音乐服务适配器 - 全局状态管理
class QqMusocService extends GetxService {
static QqMusocService get to => Get.find<QqMusocService>();
var isInitialized = false;
// 音乐服务实例
final QqMusic _qqMusic = QqMusic();
// 全局音乐状态
final isPlaying = false.obs;
final currentPosition = 0.obs; // 毫秒
final totalDuration = 0.obs; // 毫秒
final currentSong = Rxn<SongModel>();
// final playlist = <SongModel>[].obs;
// final currentIndex = 0.obs;
// 状态监听定时器
Timer? _stateMonitorTimer;
// 监听器列表 - 用于通知页面状态变化
final List<Function()> _listeners = [];
/// 初始化插件并尝试自动登录
Future<void> initializePlugin() async {
try {
// 先触发插件注册
// await _qqMusic.getPlatformVersion();
// 尝试自动登录
final result = await _qqMusic.login();
if (result['success'] == true) {
print('QQ音乐自动登录成功: ${result['openId']}');
Future.delayed(Duration(milliseconds: 1000), () {
syncCurrentPlayInfo();
});
} else {
print('QQ音乐自动登录失败: ${result['error']}');
}
} catch (e) {
print('QQ音乐插件初始化失败: $e');
}
}
@override
void onInit() {
super.onInit();
print('QQ音乐 全局音乐服务初始化');
// 立即初始化插件
initializePlugin();
}
@override
void onClose() {
_stateMonitorTimer?.cancel();
_listeners.clear();
print('🎵 [QQMusicService] 全局音乐服务销毁');
super.onClose();
}
/// 添加状态监听器
void addListener(Function() listener) {
_listeners.add(listener);
}
/// 移除状态监听器
void removeListener(Function() listener) {
_listeners.remove(listener);
}
/// 通知所有监听器
void _notifyListeners() {
for (final listener in _listeners) {
try {
listener();
} catch (e) {
print('🔥 [QQMusicService] 监听器回调异常: $e');
}
}
}
/// 启动播放状态监控
void startPlaybackStateMonitor() {
// 取消之前的定时器
_stateMonitorTimer?.cancel();
print('🎵 [QQMusicService] 启动全局状态监控');
// 立即执行一次同步
_syncPlaybackInfo();
// 改为每2-3秒同步一次,减少频率
_stateMonitorTimer = Timer.periodic(const Duration(seconds: 2), (timer) {
_syncPlaybackInfo();
});
print('🎵 [QQMusicService] 全局状态监控已启动');
}
/// 停止播放状态监控
void stopPlaybackStateMonitor() {
_stateMonitorTimer?.cancel();
_stateMonitorTimer = null;
print('⏹️ [QQMusicService] 全局状态监控已停止');
}
/// 统一同步播放信息
bool _isSyncing = false;
Future<void> _syncPlaybackInfo() async {
if (_isSyncing) {
print('🔄 [QQMusicService] 上次同步未完成,跳过本次');
return;
}
_isSyncing = true;
try {
final result = await _qqMusic
.syncCurrentPlayInfo()
.timeout(const Duration(milliseconds: 500)); // 500ms超时
if (result['success'] == true && result['data'] != null) {
final data = result['data'];
// 更新播放状态
final newIsPlaying = data['isPlaying'] ?? false;
final wasPlaying = isPlaying.value;
if (isPlaying.value != newIsPlaying) {
print(
'🎮 [QQMusicService] 全局播放状态变化: ${isPlaying.value} -> $newIsPlaying');
isPlaying.value = newIsPlaying;
}
// 如果从播放状态变为停止状态,自动停止监听
if (wasPlaying && !newIsPlaying) {
print('⏹️ [QQMusicService] 检测到播放停止,自动停止全局监听');
stopPlaybackStateMonitor();
_notifyListeners();
return;
}
// 如果当前不在播放状态,也停止监听
if (!newIsPlaying) {
print('⏸️ [QQMusicService] 当前未在播放,停止全局监听以节省资源');
stopPlaybackStateMonitor();
_notifyListeners();
return;
}
// 更新播放时间(Android端返回秒,转换为毫秒)
final currentTimeSec = data['currentTime'] ?? 0;
final totalTimeSec = data['totalTime'] ?? 0;
final newCurrentPosition = (currentTimeSec * 1000).round();
final newTotalDuration = (totalTimeSec * 1000).round();
if (currentPosition.value != newCurrentPosition) {
currentPosition.value = newCurrentPosition;
}
if (totalDuration.value != newTotalDuration) {
totalDuration.value = newTotalDuration;
}
// 更新当前歌曲信息
final songData = data['currentSong'];
if (songData != null) {
final newSong = SongModel(
mid: songData['mid'] ?? '',
name: songData['name'] ?? '',
artist: songData['singer'] ?? '',
album: songData['album'] ?? '',
albumPic: songData['coverUri'],
duration: songData['duration'] ?? 0,
);
if (currentSong.value?.mid != newSong.mid) {
print(
'🎵 [QQMusicService] 当前歌曲变化: ${currentSong.value?.name} -> ${newSong.name}');
currentSong.value = newSong;
}
}
// 通知所有监听器
_notifyListeners();
} else {
// 同步失败时停止监听
print('❌ [QQMusicService] 全局同步失败,停止监听');
stopPlaybackStateMonitor();
}
} on TimeoutException {
print('⏰ [QQMusicService] 同步超时,跳过本次更新');
} catch (e) {
print('💥 [QQMusicService] 全局同步异常: $e');
stopPlaybackStateMonitor();
} finally {
_isSyncing = false;
}
}
// 后台执行的同步方法
static Future<Map<String, dynamic>> _performSync(dynamic _) async {
final qqMusic = QqMusic();
return await qqMusic.syncCurrentPlayInfo();
}
/// 格式化时间
String formatDuration(int milliseconds) {
final duration = Duration(milliseconds: milliseconds);
final minutes = duration.inMinutes;
final seconds = duration.inSeconds % 60;
return '${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}';
}
/// 登录QQ音乐
Future<Map<String, dynamic>> login() async {
try {
final result = await _qqMusic.login();
if (result['success'] == true) {
isInitialized = true;
return result;
} else {
return {'success': false, 'error': result['error'] ?? '登录失败'};
}
} catch (e) {
return {'success': false, 'error': '登录异常: ${e.toString()}'};
}
}
/// 搜索歌曲
Future<Map<String, dynamic>> searchSongs({
required String keyword,
int searchType = 0,
}) async {
try {
final result = await _qqMusic.searchSongs(
keyword: keyword,
searchType: searchType,
);
return result;
} catch (e) {
return {'success': false, 'error': '搜索失败: ${e.toString()}'};
}
}
/// 播放歌曲列表 - 更新全局状态
Future<Map<String, dynamic>> playSongs({
required List<String> songMids,
int index = 0,
List<SongModel>? songList,
SongModel? currentSongModel,
}) async {
try {
final result = await _qqMusic.playSongs(
songMids: songMids,
index: index,
);
if (result['success'] == true) {
if (currentSongModel != null) {
currentSong.value = currentSongModel;
totalDuration.value = currentSongModel.duration;
}
isPlaying.value = true;
currentPosition.value = 0;
// 启动全局状态监听
Future.delayed(Duration(milliseconds: 500), () {
syncCurrentPlayInfo();
});
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '播放失败: ${e.toString()}'};
}
}
/// 播放音乐
Future<Map<String, dynamic>> playMusic() async {
try {
final result = await _qqMusic.playMusic();
if (result['success'] == true) {
isPlaying.value = true;
currentPosition.value = 0;
// 启动全局状态监听
Future.delayed(Duration(milliseconds: 500), () {
syncCurrentPlayInfo();
});
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '播放失败: ${e.toString()}'};
}
}
/// 暂停音乐
Future<Map<String, dynamic>> pauseMusic() async {
try {
final result = await _qqMusic.pauseMusic();
if (result['success'] == true) {
isPlaying.value = false;
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '暂停失败: ${e.toString()}'};
}
}
/// 继续播放
Future<Map<String, dynamic>> resumeMusic() async {
try {
final result = await _qqMusic.resumeMusic();
if (result['success'] == true) {
isPlaying.value = true;
startPlaybackStateMonitor();
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '继续播放失败: ${e.toString()}'};
}
}
/// 停止音乐
Future<Map<String, dynamic>> stopMusic() async {
try {
final result = await _qqMusic.stopMusic();
if (result['success'] == true) {
isPlaying.value = false;
currentPosition.value = 0;
stopPlaybackStateMonitor();
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '停止失败: ${e.toString()}'};
}
}
/// 下一首
Future<Map<String, dynamic>> skipToNext() async {
try {
final result = await _qqMusic.skipToNext();
if (result['success'] == true) {
// 更新当前索引
// if (currentIndex.value < playlist.length - 1) {
// currentIndex.value++;
// currentSong.value = playlist[currentIndex.value];
// }
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '下一首失败: ${e.toString()}'};
}
}
/// 上一首
Future<Map<String, dynamic>> skipToPrevious() async {
try {
final result = await _qqMusic.skipToPrevious();
if (result['success'] == true) {
// 更新当前索引
// if (currentIndex.value > 0) {
// currentIndex.value--;
// currentSong.value = playlist[currentIndex.value];
// }
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '上一首失败: ${e.toString()}'};
}
}
/// 获取播放状态
Future<Map<String, dynamic>> getPlaybackState() async {
try {
final result = await _qqMusic.getPlaybackState();
return result;
} catch (e) {
return {'success': false, 'error': '获取播放状态失败: ${e.toString()}'};
}
}
/// 获取当前播放歌曲
Future<Map<String, dynamic>> getCurrentSong() async {
try {
final result = await _qqMusic.getCurrentSong();
return result;
} catch (e) {
return {'success': false, 'error': '获取当前歌曲失败: ${e.toString()}'};
}
}
/// 获取播放时间
Future<Map<String, dynamic>> getPlayTime() async {
try {
final result = await _qqMusic.getPlayTime();
return result;
} catch (e) {
return {'success': false, 'error': '获取播放时间失败: ${e.toString()}'};
}
}
/// 同步当前播放信息 - 统一接口
Future<Map<String, dynamic>> syncCurrentPlayInfo() async {
try {
_stateMonitorTimer?.cancel(); //先关闭计时器
final result = await _qqMusic.syncCurrentPlayInfo();
// 如果同步成功,更新全局状态
if (result['success'] == true && result['data'] != null) {
final data = result['data'];
// 更新播放状态
final newIsPlaying = data['isPlaying'] ?? false;
if (isPlaying.value != newIsPlaying) {
isPlaying.value = newIsPlaying;
}
// 更新播放时间(Android端返回秒,转换为毫秒)
final currentTimeSec = data['currentTime'] ?? 0;
final totalTimeSec = data['totalTime'] ?? 0;
final newCurrentPosition = (currentTimeSec * 1000).round();
final newTotalDuration = (totalTimeSec * 1000).round();
if (currentPosition.value != newCurrentPosition) {
currentPosition.value = newCurrentPosition;
}
if (totalDuration.value != newTotalDuration) {
totalDuration.value = newTotalDuration;
}
// 更新当前歌曲信息
final songData = data['currentSong'];
if (songData != null) {
final newSong = SongModel(
mid: songData['mid'] ?? '',
name: songData['name'] ?? '',
artist: songData['singer'] ?? '',
album: songData['album'] ?? '',
albumPic: songData['coverUri'],
duration: songData['duration'] ?? 0,
);
if (currentSong.value?.mid != newSong.mid) {
currentSong.value = newSong;
}
}
if (newIsPlaying) {
//正在播放
startPlaybackStateMonitor();
}
// 通知所有监听器
_notifyListeners();
}
return result;
} catch (e) {
return {'success': false, 'error': '同步播放信息失败: ${e.toString()}'};
}
}
}