import 'dart:async'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../../../core/utils/logger.dart'; import '../../../data/services/music_manager.dart'; import '../../../data/services/network/api.dart'; /// 音乐播放控制器 /// 负责管理音乐播放状态、播放列表和播放控制 class MusicController extends GetxController { static const String TAG = 'MusicController'; // 音乐播放管理器 final _musicManager = Get.find(); // 播放状态 final isPlaying = false.obs; final currentId = 0.obs; // 播放进度相关状态 final currentPosition = 0.obs; // 当前播放位置(毫秒) final duration = 0.obs; // 总时长(毫秒) final progress = 0.0.obs; // 播放进度(0.0-1.0) // 当前播放列表管理 final currentPlaylist = >[].obs; // 当前播放列表 final currentPlaylistIndex = 0.obs; // 当前播放歌曲在列表中的索引 // 加载状态跟踪 final isLoadingMusic = false.obs; final loadingMusicId = ''.obs; // 进度更新定时器 Timer? _progressTimer; @override void onInit() { super.onInit(); _initMusicStatus(); _setupMediaSessionCallbacks(); } @override void onClose() { _stopProgressTimer(); super.onClose(); } // 初始化音乐播放状态 Future _initMusicStatus() async { try { await musicStatus(); Logger.d(TAG, '音乐状态初始化完成'); } catch (e) { Logger.e(TAG, '音乐状态初始化失败: $e'); } } // 设置媒体会话回调 void _setupMediaSessionCallbacks() async { try { await _musicManager.setMediaSessionCallbacks( onPlay: onMediaSessionPlay, onPause: onMediaSessionPause, onNext: onMediaSessionNext, onPrevious: onMediaSessionPrevious, onSeekTo: onMediaSessionSeekTo, onStop: onMediaSessionStop, ); Logger.d(TAG, '媒体会话回调设置完成'); } catch (e) { Logger.e(TAG, '媒体会话回调设置失败: $e'); } } // 设置加载状态的方法 void setLoadingMusic(String id, bool loading) { loadingMusicId.value = loading ? id : ''; isLoadingMusic.value = loading; } // 获取音乐播放状态 Future musicStatus() async { try { var status = await _musicManager.getStatus(); isPlaying.value = status['isPlaying'] ?? false; currentId.value = status['id'] ?? 0; Logger.d(TAG, '音乐状态更新: playing=${isPlaying.value}, id=${currentId.value}'); } catch (e) { Logger.e(TAG, '获取音乐状态失败: $e'); } } // 播放音乐 Future musicPlay(Map song) async { try { Logger.d(TAG, '开始播放音乐: ${song['title'] ?? song['name']}'); // 立即更新UI状态,提供即时反馈 isPlaying.value = true; // 修复:确保currentId接收int类型 final songId = song['id']; currentId.value = songId is int ? songId : (int.tryParse(songId?.toString() ?? '0') ?? 0); // 重置进度状态 currentPosition.value = 0; duration.value = 0; progress.value = 0.0; final id = song['id'] ?? ""; final timestampMs = song['ts'] ?? 0; // 检查URL是否需要刷新(只有当有时间戳时才检查) if (timestampMs > 0) { final now = DateTime.now(); final tsTime = DateTime.fromMillisecondsSinceEpoch(timestampMs).add( const Duration(minutes: 10), // 转换为北京时间 ); // 判断是否过期 if (tsTime.isBefore(now)) { Logger.d(TAG, '音乐URL已过期,正在获取新URL...'); try { var response = await Api.getMusicUrl({ "ids": [id] }); print('getMusicUrl 响应数据: ${response.toString()}'); // 调试输出原始数据 final urldata = response['urls'][0] as Map; song["url"] = urldata['url'] ?? ''; // 修复:确保currentId接收int类型 final newSongId = song['id']; currentId.value = newSongId is int ? newSongId : (int.tryParse(newSongId?.toString() ?? '0') ?? 0); Logger.d(TAG, '获取新URL成功'); } catch (e) { Logger.e(TAG, '获取新URL失败: $e'); // 如果获取新URL失败,尝试使用原URL } } } // 转换为MusicManager期望的格式 final musicData = { 'id': song['id']?.toString() ?? '', 'url': song['url']?.toString() ?? '', 'title': song['title']?.toString() ?? song['name']?.toString() ?? '', 'artist': song['artist']?.toString() ?? song['sgener']?.toString() ?? '', 'coverUrl': song['coverUrl']?.toString() ?? song['image']?.toString() ?? '', }; // 调用音乐管理器播放 await _musicManager.play(musicData); // 更新媒体会话元数据和播放状态 await _updateMediaSessionMetadata(song); await _updateMediaSessionPlaybackState(true); // 启动进度定时器 _startProgressTimer(); Logger.d(TAG, '音乐播放启动成功'); } catch (e) { Logger.e(TAG, '播放音乐失败: $e'); // 发生错误时重置状态 isPlaying.value = false; currentId.value = 0; } } // 暂停音乐 Future musicPause() async { try { Logger.d(TAG, '暂停音乐播放'); await _musicManager.pause(); isPlaying.value = false; _stopProgressTimer(); // 更新媒体会话播放状态 await _updateMediaSessionPlaybackState(false); } catch (e) { Logger.e(TAG, '暂停音乐失败: $e'); } } // 恢复音乐播放 Future musicResume() async { try { Logger.d(TAG, '恢复播放音乐'); await _musicManager.resume(); isPlaying.value = true; _startProgressTimer(); // 更新媒体会话播放状态 await _updateMediaSessionPlaybackState(true); Logger.d(TAG, '音乐恢复播放成功'); } catch (e) { Logger.e(TAG, '恢复播放音乐失败: $e'); isPlaying.value = false; } } // 启动进度更新定时器 void _startProgressTimer() { _stopProgressTimer(); // 先停止现有定时器 Logger.d(TAG, '启动播放进度定时器'); _progressTimer = Timer.periodic(const Duration(milliseconds: 500), (timer) { if (isPlaying.value && currentId.value != 0) { updateMusicProgress(); } else if (!isPlaying.value) { // 如果不在播放状态,停止定时器 timer.cancel(); _progressTimer = null; Logger.d(TAG, '播放已停止,取消进度定时器'); } }); } // 停止进度更新定时器 void _stopProgressTimer() { if (_progressTimer != null) { Logger.d(TAG, '停止播放进度定时器'); _progressTimer?.cancel(); _progressTimer = null; } } // 获取播放进度 Future updateMusicProgress() async { try { if (!isPlaying.value || currentId.value == 0) { return; // 如果没有在播放,直接返回 } var progressInfo = await _musicManager.getProgress(); final newPosition = progressInfo['currentPosition'] ?? 0; final newDuration = progressInfo['duration'] ?? 0; final newProgress = progressInfo['progress'] ?? 0.0; bool hasUpdate = false; // 只有当值发生变化时才更新,避免不必要的UI刷新 if (currentPosition.value != newPosition) { currentPosition.value = newPosition; hasUpdate = true; } if (duration.value != newDuration) { duration.value = newDuration; hasUpdate = true; } if ((progress.value - newProgress).abs() > 0.001) { // 避免浮点数精度问题 progress.value = newProgress; hasUpdate = true; } // 如果有进度更新,通知系统媒体会话更新进度信息 if (hasUpdate) { await _updateMediaSessionProgress(); } } catch (e) { Logger.e(TAG, '获取播放进度失败: $e'); } } // 跳转到指定位置 Future seekToPosition(int positionMs) async { try { await _musicManager.seekTo(positionMs); // 立即更新进度状态 await updateMusicProgress(); } catch (e) { Logger.e(TAG, '跳转播放位置失败: $e'); } } /// 播放音乐列表 Future playPlaylist(List> playlist) async { try { if (playlist.isEmpty) { Logger.e(TAG, '播放列表为空,无法播放'); return; } Logger.d(TAG, '开始播放音乐列表,共${playlist.length}首歌曲'); // 保存当前播放列表 currentPlaylist.assignAll(playlist); currentPlaylistIndex.value = 0; // 设置加载状态 isLoadingMusic.value = true; loadingMusicId.value = playlist[0]['id']?.toString() ?? ''; // 重置播放状态 isPlaying.value = true; currentPosition.value = 0; duration.value = 0; progress.value = 0.0; // 格式化歌曲列表数据 final formattedPlaylist = playlist.map((song) { return { 'id': song['id']?.toString() ?? '', 'url': song['url']?.toString() ?? '', 'title': song['title']?.toString() ?? song['name']?.toString() ?? '', 'artist': song['artist']?.toString() ?? song['sgener']?.toString() ?? '', 'coverUrl': song['coverUrl']?.toString() ?? song['image']?.toString() ?? '', }; }).toList(); // 调用音乐管理器播放列表 await _musicManager.playPlaylist(formattedPlaylist); // 更新当前播放歌曲ID if (formattedPlaylist.isNotEmpty) { currentId.value = int.tryParse(formattedPlaylist[0]['id'] ?? '0') ?? 0; } // 启动进度定时器 _startProgressTimer(); Logger.d(TAG, '音乐列表播放启动成功'); } catch (e) { Logger.e(TAG, '播放音乐列表失败: $e'); isPlaying.value = false; currentId.value = 0; // 显示错误提示 Get.snackbar( '播放失败', '无法播放音乐列表,请稍后重试', snackPosition: SnackPosition.BOTTOM, backgroundColor: Colors.red[400], colorText: Colors.white, duration: const Duration(seconds: 2), ); } finally { // 清除加载状态 isLoadingMusic.value = false; loadingMusicId.value = ''; } } /// 播放上一曲 Future playPrevious() async { if (currentPlaylist.isEmpty) { Logger.w(TAG, '当前播放列表为空,无法播放上一曲'); return; } // 计算上一曲的索引 int previousIndex = currentPlaylistIndex.value - 1; if (previousIndex < 0) { previousIndex = currentPlaylist.length - 1; // 循环到最后一首 } currentPlaylistIndex.value = previousIndex; final previousSong = currentPlaylist[previousIndex]; Logger.d(TAG, '播放上一曲: ${previousSong['name'] ?? previousSong['title']}'); await musicPlay(previousSong); } /// 播放下一曲 Future playNext() async { if (currentPlaylist.isEmpty) { Logger.w(TAG, '当前播放列表为空,无法播放下一曲'); return; } // 计算下一曲的索引 int nextIndex = currentPlaylistIndex.value + 1; if (nextIndex >= currentPlaylist.length) { nextIndex = 0; // 循环到第一首 } currentPlaylistIndex.value = nextIndex; final nextSong = currentPlaylist[nextIndex]; Logger.d(TAG, '播放下一曲: ${nextSong['name'] ?? nextSong['title']}'); await musicPlay(nextSong); } /// 更新当前播放列表和索引(当单独播放某首歌曲时调用) void updateCurrentPlaylistContext( List> playlist, int songId) { currentPlaylist.assignAll(playlist); // 查找当前歌曲在列表中的索引 int index = -1; for (int i = 0; i < playlist.length; i++) { if (int.tryParse(playlist[i]['id']?.toString() ?? '0') == songId) { index = i; break; } } if (index != -1) { currentPlaylistIndex.value = index; Logger.d(TAG, '更新播放列表上下文,当前歌曲索引: $index'); } } // ========== 媒体会话回调处理方法 ========== /// 处理来自系统通知栏的播放操作 Future onMediaSessionPlay() async { Logger.d(TAG, '收到媒体会话播放回调'); if (!isPlaying.value) { await musicResume(); } } /// 处理来自系统通知栏的暂停操作 Future onMediaSessionPause() async { Logger.d(TAG, '收到媒体会话暂停回调'); if (isPlaying.value) { await musicPause(); } } /// 处理来自系统通知栏的下一曲操作 Future onMediaSessionNext() async { Logger.d(TAG, '收到媒体会话下一曲回调'); await playNext(); } /// 处理来自系统通知栏的上一曲操作 Future onMediaSessionPrevious() async { Logger.d(TAG, '收到媒体会话上一曲回调'); await playPrevious(); } /// 处理来自系统通知栏的跳转操作 Future onMediaSessionSeekTo(int positionMs) async { Logger.d(TAG, '收到媒体会话跳转回调: ${positionMs}ms'); await seekToPosition(positionMs); } /// 处理来自系统通知栏的停止操作 Future onMediaSessionStop() async { Logger.d(TAG, '收到媒体会话停止回调'); await musicPause(); // 重置播放状态 currentPosition.value = 0; progress.value = 0.0; _stopProgressTimer(); } // ========== 私有辅助方法 ========== /// 更新系统媒体会话的进度信息 Future _updateMediaSessionProgress() async { try { // 具体实现将在music_service插件中添加 await _musicManager.updateMediaSessionProgress( currentPosition.value, duration.value, progress.value, ); } catch (e) { // 忽略错误,避免影响正常播放 Logger.d(TAG, '更新媒体会话进度失败: $e'); } } /// 更新系统媒体会话的元数据 Future _updateMediaSessionMetadata(Map song) async { try { await _musicManager.updateMediaSessionMetadata(song); } catch (e) { Logger.d(TAG, '更新媒体会话元数据失败: $e'); } } /// 更新系统媒体会话的播放状态 Future _updateMediaSessionPlaybackState(bool isPlaying) async { try { await _musicManager.updateMediaSessionPlaybackState(isPlaying); } catch (e) { Logger.d(TAG, '更新媒体会话播放状态失败: $e'); } } }