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.
424 lines
12 KiB
424 lines
12 KiB
import 'dart:async';
|
|
import 'package:get/get.dart';
|
|
import 'package:qq_music/qq_music.dart';
|
|
import '../models/song_model.dart';
|
|
|
|
/// QQ音乐服务适配器 - 全局状态管理
|
|
class QqMusicService extends GetxService {
|
|
static QqMusicService get to => Get.find<QqMusicService>();
|
|
|
|
var isInitialized = false;
|
|
// 音乐服务实例
|
|
final QqMusic _qqMusic = QqMusic();
|
|
|
|
// 全局音乐状态
|
|
final isPlaying = false.obs;
|
|
final currentPosition = 0.obs; // 毫秒
|
|
final totalDuration = 0.obs; // 毫秒
|
|
final currentSong = Rxn<SongModel>();
|
|
|
|
// 状态监听定时器
|
|
Timer? _stateMonitorTimer;
|
|
|
|
@override
|
|
void onInit() {
|
|
super.onInit();
|
|
// print('QQ音乐 全局音乐服务初始化');
|
|
// 立即初始化插件
|
|
// initializePlugin();
|
|
}
|
|
|
|
@override
|
|
void onClose() {
|
|
_stateMonitorTimer?.cancel();
|
|
|
|
print('🎵 [QQMusicService] 全局音乐服务销毁');
|
|
super.onClose();
|
|
}
|
|
|
|
/// 启动播放状态监控
|
|
void startPlaybackStateMonitor() {
|
|
// 取消之前的定时器
|
|
_stateMonitorTimer?.cancel();
|
|
|
|
print('🎵 [QQMusicService] 启动全局状态监控');
|
|
|
|
// 立即执行一次同步
|
|
_syncPlaybackInfo();
|
|
|
|
// 改为每2-3秒同步一次,减少频率
|
|
_stateMonitorTimer = Timer.periodic(const Duration(seconds: 1), (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();
|
|
return;
|
|
}
|
|
|
|
// 如果当前不在播放状态,也停止监听
|
|
if (!newIsPlaying) {
|
|
print('⏸️ [QQMusicService] 当前未在播放,停止全局监听以节省资源');
|
|
stopPlaybackStateMonitor();
|
|
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;
|
|
}
|
|
}
|
|
} else {
|
|
// 同步失败时停止监听
|
|
print('❌ [QQMusicService] 全局同步失败,停止监听');
|
|
stopPlaybackStateMonitor();
|
|
}
|
|
} on TimeoutException {
|
|
print('⏰ [QQMusicService] 同步超时,跳过本次更新');
|
|
} catch (e) {
|
|
print('💥 [QQMusicService] 全局同步异常: $e');
|
|
stopPlaybackStateMonitor();
|
|
} finally {
|
|
_isSyncing = false;
|
|
}
|
|
}
|
|
|
|
/// 格式化时间
|
|
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 {
|
|
stopPlaybackStateMonitor();
|
|
isPlaying.value = true;
|
|
currentPosition.value = 0;
|
|
currentSong.value = currentSongModel;
|
|
final result = await _qqMusic.playSongs(
|
|
songMids: songMids,
|
|
index: index,
|
|
);
|
|
print('💥 [QQMusicService] playSongs: $result');
|
|
if (result['success'] == true) {
|
|
if (currentSongModel != null) {
|
|
currentSong.value = currentSongModel;
|
|
totalDuration.value = currentSongModel.duration;
|
|
}
|
|
isPlaying.value = true;
|
|
currentPosition.value = 0;
|
|
// 启动全局状态监听
|
|
Future.delayed(Duration(seconds: 1), () {
|
|
syncCurrentPlayInfo();
|
|
});
|
|
} else {
|
|
isPlaying.value = false;
|
|
currentPosition.value = 0;
|
|
currentSong.value = null;
|
|
}
|
|
|
|
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();
|
|
});
|
|
}
|
|
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;
|
|
}
|
|
return result;
|
|
} catch (e) {
|
|
return {'success': false, 'error': '暂停失败: ${e.toString()}'};
|
|
}
|
|
}
|
|
|
|
/// 自动暂停音乐
|
|
Future<bool> autopauseMusic() async {
|
|
try {
|
|
final result = await _qqMusic.autopauseMusic();
|
|
if (result['success'] == true) {
|
|
isPlaying.value = false;
|
|
}
|
|
return result['success'] == true;
|
|
} catch (e) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// 继续播放
|
|
Future<Map<String, dynamic>> resumeMusic() async {
|
|
try {
|
|
final result = await _qqMusic.resumeMusic();
|
|
if (result['success'] == true) {
|
|
isPlaying.value = true;
|
|
startPlaybackStateMonitor();
|
|
}
|
|
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();
|
|
}
|
|
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) {}
|
|
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) {}
|
|
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(
|
|
{bool isOpenPlay = false}) async {
|
|
try {
|
|
_stateMonitorTimer?.cancel(); //先关闭计时器
|
|
final result = await _qqMusic.syncCurrentPlayInfo();
|
|
print('💥 [QQMusicService] syncCurrentPlayInfo: $result');
|
|
// 如果同步成功,更新全局状态
|
|
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();
|
|
} else {
|
|
stopPlaybackStateMonitor();
|
|
currentSong.value = null;
|
|
|
|
if (isOpenPlay) {
|
|
Future.delayed(Duration(seconds: 2), () {
|
|
syncCurrentPlayInfo();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
return result;
|
|
} catch (e) {
|
|
return {'success': false, 'error': '同步播放信息失败: ${e.toString()}'};
|
|
}
|
|
}
|
|
}
|
|
|