From 399958cea0f7f750de35f8753c6623801a2dbc37 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 19 Aug 2025 10:22:18 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0ai=E8=B6=85=E6=97=B6?= =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../yunqiinnovation/chat_api/ChatApiService.kt | 16 ++++++++++++++-- pubspec.yaml | 2 +- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt index a0841af03..6d49ecbd5 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/ChatApiService.kt @@ -404,12 +404,24 @@ class ChatApiService(private val context: android.content.Context? = null) : Cor throw IllegalStateException("OpenAI客户端未初始化") } Log.e("ChatApiService", "liwei---------,发送AI请求 model:${currentModel} messages:${chatMessages}") - val flow = openAI!!.chatCompletions(chatCompletionRequest) + // 添加超时控制,10秒超时 + val flow = withTimeout(10.seconds) { + openAI!!.chatCompletions(chatCompletionRequest) + } Log.d(TAG, "liwei-------------------------开始AI 对话 6") flow } catch (e: Exception) { Log.e("ChatApiService", "创建ChatCompletionRequest或调用chatCompletions失败: ${e.message}", e) - throw e + if (sessionid == currSessionId) { + try { + getSessionCallback(sessionid)?.onError(sessionid,ChatApiException("流式请求失败: ${e.message}")) + } catch (ex: Exception) { + Log.e(TAG, "onError回调异常: ${ex.message}", ex) + } + clearCurrentSession() + } + return@launch +// throw e } var replyContext = ""; diff --git a/pubspec.yaml b/pubspec.yaml index 04aa9127f..7810473cb 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -53,7 +53,7 @@ dependencies: flutter_local_notifications: ^18.0.1 device_info_plus: ^11.5.0 uuid: ^4.3.3 - record: ^5.2.1 + record: ^6.0.0 share_plus: ^11.0.0 image_picker: ^1.1.2 audio_waveforms: ^1.3.0 From fd942d8484c8ec2a2681cf8de75b7e6114c76b15 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Tue, 19 Aug 2025 12:10:44 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E6=97=A5=E5=8E=86?= =?UTF-8?q?=E6=9D=83=E9=99=90?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Runner/Info.plist | 2 + lib/data/services/novice_guide_service.dart | 8 ++-- .../permissions/models/permission_group.dart | 26 +++++------ .../permissions/views/permissions_view.dart | 43 ++++++++++--------- local_plugins/jl_opus/pubspec.yaml | 2 +- pubspec.yaml | 7 +-- 6 files changed, 44 insertions(+), 44 deletions(-) diff --git a/ios/Runner/Info.plist b/ios/Runner/Info.plist index f840f7ef3..4fc81d382 100644 --- a/ios/Runner/Info.plist +++ b/ios/Runner/Info.plist @@ -106,6 +106,8 @@ Bluetooth permission is required to connect and manage audio devices NSCalendarsUsageDescription Calendar permission is required to schedule and manage your audio meetings and recording tasks + NSCalendarsFullAccessUsageDescription + Calendar permission is required to schedule and manage your audio meetings and recording tasks NSCameraUsageDescription Camera permission is required for QR code scanning and video calling functions NSLocationAlwaysAndWhenInUseUsageDescription diff --git a/lib/data/services/novice_guide_service.dart b/lib/data/services/novice_guide_service.dart index be154d551..fb124a77a 100644 --- a/lib/data/services/novice_guide_service.dart +++ b/lib/data/services/novice_guide_service.dart @@ -68,11 +68,11 @@ class NoviceGuideService extends GetxService { 'method': () async { //创建会议提醒需要日历权限 await PermissionUtil.instance.requestPermission( - permissionType: Permission.calendarWriteOnly, - permissionName: 'calendarWrite'.tr, // 日历写入 - explanationText: 'calendarWritePermissionDesc'.tr, // 用于创建日历事件和提醒 + permissionType: Permission.calendarFullAccess, + permissionName: 'calendarFullAccess'.tr, // 日历写入 + explanationText: 'calendarFullAccessPermissionDesc'.tr, // 用于创建日历事件和提醒 permanentDenialText: - 'calendarWritePermissionDetailDesc'.tr, // 创建日历事件需要日历写入权限 + 'calendarFullAccessPermissionDetailDesc'.tr, // 创建日历事件需要日历写入权限 ); }, }, diff --git a/lib/modules/permissions/models/permission_group.dart b/lib/modules/permissions/models/permission_group.dart index 5426a7336..c3c2ca4f6 100644 --- a/lib/modules/permissions/models/permission_group.dart +++ b/lib/modules/permissions/models/permission_group.dart @@ -3,17 +3,19 @@ import 'package:flutter/material.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:device_info_plus/device_info_plus.dart'; -class PermissionGroup { +class PermissionGroupModel { final String titleKey; final IconData icon; final List permissions; - const PermissionGroup({ + const PermissionGroupModel({ required this.titleKey, required this.icon, required this.permissions, }); +} +class PermissionGroup { /// 获取蓝牙权限列表(根据平台和Android版本) static Future> _getBluetoothPermissions() async { if (Platform.isAndroid) { @@ -41,55 +43,55 @@ class PermissionGroup { } /// 获取平台特定的权限组列表(异步方法) - static Future> getPlatformGroups() async { + static Future> getPlatformGroups() async { // 动态获取蓝牙权限列表 final bluetoothPermissions = await _getBluetoothPermissions(); - + return [ // 通讯权限组 - 仅Android(包含联系人权限) - const PermissionGroup( + const PermissionGroupModel( titleKey: 'communicationPermissions', icon: Icons.phone_android, permissions: [Permission.phone, Permission.sms, Permission.contacts], ), // 蓝牙权限组 - 根据平台动态获取权限 - PermissionGroup( + PermissionGroupModel( titleKey: 'bluetoothPermissions', icon: Icons.bluetooth, permissions: bluetoothPermissions, ), // 通知权限组 - const PermissionGroup( + const PermissionGroupModel( titleKey: 'notificationPermissions', icon: Icons.notifications, permissions: [Permission.notification], ), // 闹钟权限组 - 仅Android - const PermissionGroup( + const PermissionGroupModel( titleKey: 'alarmPermissions', icon: Icons.alarm, permissions: [Permission.scheduleExactAlarm], ), // 日历权限组 - const PermissionGroup( + const PermissionGroupModel( titleKey: 'calendarPermissions', icon: Icons.calendar_today, permissions: [Permission.calendarFullAccess], ), // 位置权限组 - const PermissionGroup( + const PermissionGroupModel( titleKey: 'locationPermissions', icon: Icons.location_on, permissions: [Permission.location], ), // 存储权限组 - const PermissionGroup( + const PermissionGroupModel( titleKey: 'storagePermissions', icon: Icons.storage, permissions: [Permission.storage], ), // 麦克风权限组 - const PermissionGroup( + const PermissionGroupModel( titleKey: 'microphonePermissions', icon: Icons.mic, permissions: [Permission.microphone], diff --git a/lib/modules/permissions/views/permissions_view.dart b/lib/modules/permissions/views/permissions_view.dart index 94d188ff2..abfed7de3 100644 --- a/lib/modules/permissions/views/permissions_view.dart +++ b/lib/modules/permissions/views/permissions_view.dart @@ -4,7 +4,6 @@ import 'package:permission_handler/permission_handler.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'dart:ui'; import 'dart:io' show Platform; -import 'package:device_info_plus/device_info_plus.dart'; import '../controllers/permissions_controller.dart'; import '../models/permission_group.dart'; @@ -56,23 +55,23 @@ class PermissionsView extends GetView { } Widget _buildPermissionGroups(bool isDarkMode) { - return FutureBuilder>( + return FutureBuilder>( future: PermissionGroup.getPlatformGroups(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } - + if (snapshot.hasError) { return Center(child: Text('加载权限组失败: ${snapshot.error}')); } - + final groups = snapshot.data ?? []; final List widgets = []; for (int i = 0; i < groups.length; i++) { final group = groups[i]; - + // 过滤平台特定权限 if (_shouldShowGroup(group)) { widgets.add(_buildPermissionSection( @@ -82,21 +81,21 @@ class PermissionsView extends GetView { controller.permissionStatuses, isDarkMode, )); - + if (i < groups.length - 1) { widgets.add(SizedBox(height: 20.h)); } } } - + return Column(children: widgets); - }, - ); + }, + ); } - bool _shouldShowGroup(PermissionGroup group) { + bool _shouldShowGroup(PermissionGroupModel group) { // Android特定权限组 - if (group.titleKey == 'communicationPermissions' || + if (group.titleKey == 'communicationPermissions' || group.titleKey == 'alarmPermissions') { return Platform.isAndroid; } @@ -162,7 +161,8 @@ class PermissionsView extends GetView { ? ImageFilter.blur(sigmaX: 5, sigmaY: 5) : ImageFilter.blur(sigmaX: 0, sigmaY: 0), child: Column( - children: _buildPermissionItems(permissions, statuses, isDarkMode), + children: + _buildPermissionItems(permissions, statuses, isDarkMode), ), ), ), @@ -238,12 +238,13 @@ class PermissionsView extends GetView { ), ), Obx(() => Switch( - value: status.isGranted, - onChanged: controller.isRequestingPermission.value - ? null - : (value) => _handlePermissionToggle(permission, status, value), - activeColor: Colors.blue[600], - )), + value: status.isGranted, + onChanged: controller.isRequestingPermission.value + ? null + : (value) => + _handlePermissionToggle(permission, status, value), + activeColor: Colors.blue[600], + )), ], ), ); @@ -281,8 +282,8 @@ class PermissionsView extends GetView { } void _handlePermissionToggle( - Permission permission, - PermissionStatus status, + Permission permission, + PermissionStatus status, bool value, ) { if (value) { @@ -293,4 +294,4 @@ class PermissionsView extends GetView { controller.openSettings(); } } -} \ No newline at end of file +} diff --git a/local_plugins/jl_opus/pubspec.yaml b/local_plugins/jl_opus/pubspec.yaml index 3d553c10c..b28aaeb0d 100644 --- a/local_plugins/jl_opus/pubspec.yaml +++ b/local_plugins/jl_opus/pubspec.yaml @@ -11,7 +11,7 @@ dependencies: flutter: sdk: flutter path_provider: ^2.0.0 - permission_handler: ^11.4.0 + permission_handler: ^12.0.1 dev_dependencies: flutter_test: diff --git a/pubspec.yaml b/pubspec.yaml index 04aa9127f..f60b70b0a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -28,7 +28,7 @@ dependencies: htmltopdfwidgets: ^1.1.0 wifi_iot: ^0.3.19+2 flutter_intro: ^3.4.0 - permission_handler: ^10.4.5 + permission_handler: ^12.0.1 web_socket_channel: ^2.4.0 flutter_dotenv: ^5.1.0 synchronized: ^3.1.0 @@ -119,11 +119,6 @@ dev_dependencies: build_runner: ^2.3.3 # 用于生成代码 flutter pub run build_runner build json_serializable: ^6.6.0 # 用于自动生成代码 -dependency_overrides: - permission_handler: ^12.0.0 - permission_handler_android: ^13.0.0 - permission_handler_apple: ^9.4.0 - flutter: uses-material-design: true shaders: From da0e0c12df10c81c01a4f5f4045d66d1014ee429 Mon Sep 17 00:00:00 2001 From: tanlongsheng <252620078@qq.com> Date: Tue, 19 Aug 2025 15:20:55 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9iOS17=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E9=97=AA=E9=80=80=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ios/Runner.xcodeproj/project.pbxproj | 2 -- local_plugins/ble_service/ios/ble_service/Package.swift | 7 +++---- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index 0a7a4df09..6d64fb0f1 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -45,7 +45,6 @@ /* Begin PBXFileReference section */ 0AD944112DD9DB5C00557D21 /* GoogleService-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "GoogleService-Info.plist"; sourceTree = ""; }; - 0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AccessorySetupKit.framework; path = System/Library/Frameworks/AccessorySetupKit.framework; sourceTree = SDKROOT; }; 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; 162D67C21ED243BA396CEF5C /* Pods_RunnerTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_RunnerTests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -109,7 +108,6 @@ 1E5DDD8701F6FB27AA502080 /* Frameworks */ = { isa = PBXGroup; children = ( - 0AD944132DDA0C0D00557D21 /* AccessorySetupKit.framework */, EFDA2C0DD7A7D82CA03799B2 /* Pods_Runner.framework */, 162D67C21ED243BA396CEF5C /* Pods_RunnerTests.framework */, ); diff --git a/local_plugins/ble_service/ios/ble_service/Package.swift b/local_plugins/ble_service/ios/ble_service/Package.swift index ca43c17a7..f3e505b27 100644 --- a/local_plugins/ble_service/ios/ble_service/Package.swift +++ b/local_plugins/ble_service/ios/ble_service/Package.swift @@ -21,10 +21,9 @@ let package = Package( linkerSettings: [ .linkedFramework("AVFoundation"), .linkedFramework("AudioToolbox"), - .linkedFramework("CoreBluetooth"), - .linkedFramework("AccessorySetupKit", .when(platforms: [.iOS], configuration: .release)), - .linkedFramework("AccessorySetupKit", .when(platforms: [.iOS], configuration: .debug)) + .linkedFramework("CoreBluetooth") + // 移除 AccessorySetupKit 链接,因为它只在 iOS 18+ 可用 ] ) ] -) \ No newline at end of file +) \ No newline at end of file From 2844784d9b22a170ea29d4bb98f5c7eb2f2d0b37 Mon Sep 17 00:00:00 2001 From: liwei1dao Date: Tue, 19 Aug 2025 18:21:10 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=B8=8A=E4=BC=A0qq=E9=9F=B3=E4=B9=90?= =?UTF-8?q?=E6=92=AD=E6=94=BE=E6=8E=A7=E5=88=B6=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../agent_service/AgentService.kt | 12 ++ .../chat_api/QQMusicSystemFunctionHandler.kt | 136 ++++++++++++------ .../qq_music/QQMusicManager.kt | 37 +++++ .../qq_music/QQMusicSingleton.kt | 17 ++- 4 files changed, 156 insertions(+), 46 deletions(-) diff --git a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt index 6fc1400c2..648b37238 100644 --- a/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt +++ b/local_plugins/agent_service/android/src/main/kotlin/com/yunqiinnovation/agent_service/AgentService.kt @@ -131,6 +131,9 @@ object AgentService : CoroutineScope { // 语音识别模式 private var currentRecognitionMode = "normal" // 当前识别模式:normal, ble_wakeup, phone_call, push_to_talk + //是否播放音乐中 + private var isplaymusic = false; + // 打断防抖相关 private var lastInterruptTime = 0L private val INTERRUPT_DEBOUNCE_MS = 300L @@ -358,6 +361,11 @@ object AgentService : CoroutineScope { setPackage(context.packageName) } context.sendBroadcast(intent) + QQMusicSingleton.getInstance().autopauseMusic { result -> + if (result.isSuccess) { + isplaymusic = true + } + } } TtsEventType.PLAYBACK_COMPLETED -> { //结束AI播报内容 @@ -369,6 +377,10 @@ object AgentService : CoroutineScope { setPackage(context.packageName) } context.sendBroadcast(intent) + if(isplaymusic){ + isplaymusic = false + QQMusicSingleton.getInstance().resumeMusic { } + } } TtsEventType.ERROR -> { diff --git a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt index 6b1235040..08a0578c5 100644 --- a/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt +++ b/local_plugins/chat_api/android/src/main/kotlin/com/yunqiinnovation/chat_api/QQMusicSystemFunctionHandler.kt @@ -4,6 +4,8 @@ import android.content.Context import android.util.Log import kotlinx.coroutines.delay import com.yunqiinnovation.qq_music.QQMusicSingleton +import kotlin.coroutines.suspendCoroutine +import kotlin.coroutines.resume /** * QQ音乐系统功能处理器 * 负责注册QQ音乐相关的MCP函数 @@ -195,60 +197,110 @@ private class QQMusicLoginHandler(private val context: Context?) : FunctionHandl } } } - private class QQMusicSearchHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { return try { val keyword = arguments["keyword"] as? String ?: return "{\"success\": false, \"message\": \"缺少搜索关键词\"}" val searchType = arguments["searchType"] as? Int ?: 0 // 默认搜索歌曲 val qqMusicSingleton = QQMusicSingleton.getInstance() - var result = "" - - // 直接调用搜索,内部会自动处理登录检查 - qqMusicSingleton.searchSongs(keyword) { searchResult -> - result = if (searchResult.isSuccess) { - val songs = searchResult.getOrNull() ?: emptyList() - // 根据搜索类型处理结果 - val processedSongs = when (searchType) { - 0 -> { // 歌曲搜索,只返回第一个结果 -// if (songs.isNotEmpty()) listOf(songs.first()) else emptyList() - songs - } - else -> { // 专辑、歌手等其他类型,返回所有结果 - songs + // 使用 suspendCoroutine 将回调转换为协程 + suspendCoroutine { continuation -> + qqMusicSingleton.searchSongs(keyword) { searchResult -> + val result = if (searchResult.isSuccess) { + val songs = searchResult.getOrNull() ?: emptyList() + + // 根据搜索类型处理结果 + val processedSongs = when (searchType) { + 0 -> { // 歌曲搜索,返回所有结果 + songs + } + else -> { // 专辑、歌手等其他类型,返回所有结果 + songs + } } - } - val songsJson = processedSongs.joinToString(",") { song -> - val songMap = song as Map - // 添加调试日志 - Log.d("QQMusicSearchHandler", "原始数据: $songMap") - // 修正字段名映射 - val mid = songMap["mid"] ?: "unknown" - val name = songMap["name"] ?: "unknown" - val artist = songMap["singer"] ?: "unknown" - val album = songMap["album"] ?: "" - val pic = songMap["pic"] ?: "" - val duration = songMap["duration"] ?: 0 - "{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}" + val songsJson = processedSongs.joinToString(",") { song -> + val songMap = song as Map + // 添加调试日志 + Log.d("QQMusicSearchHandler", "原始数据: $songMap") + // 修正字段名映射 + val mid = songMap["mid"] ?: "unknown" + val name = songMap["name"] ?: "unknown" + val artist = songMap["singer"] ?: "unknown" + val album = songMap["album"] ?: "" + val pic = songMap["pic"] ?: "" + val duration = songMap["duration"] ?: 0 + "{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}" + } + "{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,正在播放\", \"data\": [$songsJson]}" + } else { + val error = searchResult.exceptionOrNull() + "{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}" } - "{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,增在播放\", \"data\": [$songsJson]}" - } else { - val error = searchResult.exceptionOrNull() - "{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}" + // 恢复协程执行 + continuation.resume(result) } } - - // 等待回调完成 - delay(5000) - result.ifEmpty { "{\"success\": false, \"message\": \"搜索超时\"}" } } catch (e: Exception) { Log.e("QQMusicSearchHandler", "QQ音乐搜索失败", e) "{\"success\": false, \"message\": \"搜索异常: ${e.message}\"}" } } } +//private class QQMusicSearchHandler(private val context: Context?) : FunctionHandler { +// override suspend fun handle(arguments: Map): String { +// return try { +// val keyword = arguments["keyword"] as? String ?: return "{\"success\": false, \"message\": \"缺少搜索关键词\"}" +// val searchType = arguments["searchType"] as? Int ?: 0 // 默认搜索歌曲 +// val qqMusicSingleton = QQMusicSingleton.getInstance() +// var result = "" +// +// // 直接调用搜索,内部会自动处理登录检查 +// qqMusicSingleton.searchSongs(keyword) { searchResult -> +// result = if (searchResult.isSuccess) { +// val songs = searchResult.getOrNull() ?: emptyList() +// +// // 根据搜索类型处理结果 +// val processedSongs = when (searchType) { +// 0 -> { // 歌曲搜索,只返回第一个结果 +//// if (songs.isNotEmpty()) listOf(songs.first()) else emptyList() +// songs +// } +// else -> { // 专辑、歌手等其他类型,返回所有结果 +// songs +// } +// } +// +// val songsJson = processedSongs.joinToString(",") { song -> +// val songMap = song as Map +// // 添加调试日志 +// Log.d("QQMusicSearchHandler", "原始数据: $songMap") +// // 修正字段名映射 +// val mid = songMap["mid"] ?: "unknown" +// val name = songMap["name"] ?: "unknown" +// val artist = songMap["singer"] ?: "unknown" +// val album = songMap["album"] ?: "" +// val pic = songMap["pic"] ?: "" +// val duration = songMap["duration"] ?: 0 +// "{\"mid\": \"$mid\", \"name\": \"$name\", \"artist\": \"$artist\", \"album\": \"$album\", \"duration\":$duration,\"pic\": \"$pic\"}" +// } +// "{\"success\": true, \"broadcast\": false, \"message\": \"搜索成功,增在播放\", \"data\": [$songsJson]}" +// } else { +// val error = searchResult.exceptionOrNull() +// "{\"success\": false, \"message\": \"搜索失败: ${error?.message}\"}" +// } +// } +// +// // 等待回调完成 +// delay(5000) +// result.ifEmpty { "{\"success\": false, \"message\": \"搜索超时\"}" } +// } catch (e: Exception) { +// Log.e("QQMusicSearchHandler", "QQ音乐搜索失败", e) +// "{\"success\": false, \"message\": \"搜索异常: ${e.message}\"}" +// } +// } +//} private class QQMusicPlaySongsHandler(private val context: Context?) : FunctionHandler { override suspend fun handle(arguments: Map): String { @@ -310,7 +362,7 @@ private class QQMusicPauseHandler(private val context: Context?) : FunctionHandl qqMusicSingleton.pauseMusic { pauseResult -> result = if (pauseResult.isSuccess) { - "{\"notreply\": true, \"success\": true, \"message\": \"暂停播放\"}" + "{\"broadcast\": false, \"success\": true, \"message\": \"暂停播放\"}" } else { val error = pauseResult.exceptionOrNull() "{\"success\": false, \"message\": \"暂停失败: ${error?.message}\"}" @@ -334,7 +386,7 @@ private class QQMusicResumeHandler(private val context: Context?) : FunctionHand qqMusicSingleton.resumeMusic { resumeResult -> result = if (resumeResult.isSuccess) { - "{\"notreply\": true, \"success\": true, \"message\": \"恢复播放\"}" + "{\"broadcast\": false, \"success\": true, \"message\": \"恢复播放\"}" } else { val error = resumeResult.exceptionOrNull() "{\"success\": false, \"message\": \"恢复播放失败: ${error?.message}\"}" @@ -358,7 +410,7 @@ private class QQMusicStopHandler(private val context: Context?) : FunctionHandle qqMusicSingleton.stopMusic { stopResult -> result = if (stopResult.isSuccess) { - "{\"notreply\": true, \"success\": true, \"message\": \"停止播放\"}" + "{\"broadcast\": false, \"success\": true, \"message\": \"停止播放\"}" } else { val error = stopResult.exceptionOrNull() "{\"success\": false, \"message\": \"停止失败: ${error?.message}\"}" @@ -382,7 +434,7 @@ private class QQMusicNextHandler(private val context: Context?) : FunctionHandle qqMusicSingleton.skipToNext { nextResult -> result = if (nextResult.isSuccess) { - "{\"notreply\": true, \"success\": true, \"message\": \"切换到下一首\"}" + "{\"broadcast\": false, \"success\": true, \"message\": \"切换到下一首\"}" } else { val error = nextResult.exceptionOrNull() "{\"success\": false, \"message\": \"切换失败: ${error?.message}\"}" @@ -406,7 +458,7 @@ private class QQMusicPreviousHandler(private val context: Context?) : FunctionHa qqMusicSingleton.skipToPrevious { previousResult -> result = if (previousResult.isSuccess) { - "{\"notreply\": true, \"success\": true, \"message\": \"切换到上一首\"}" + "{\"broadcast\": false, \"success\": true, \"message\": \"切换到上一首\"}" } else { val error = previousResult.exceptionOrNull() "{\"success\": false, \"message\": \"切换失败: ${error?.message}\"}" @@ -434,7 +486,7 @@ private class QQMusicGetPlaybackStateHandler(private val context: Context?) : Fu val stateJson = state.entries.joinToString(",") { (key, value) -> "\"$key\": \"$value\"" } - "{\"notreply\": true, \"success\": true, \"message\": \"获取播放状态成功\", \"data\": {$stateJson}}" + "{\"broadcast\": false, \"success\": true, \"message\": \"获取播放状态成功\", \"data\": {$stateJson}}" } else { val error = stateResult.exceptionOrNull() "{\"success\": false, \"message\": \"获取播放状态失败: ${error?.message}\"}" diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt index 1e4f8a5c1..b7851ff0c 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt +++ b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicManager.kt @@ -319,6 +319,43 @@ class QQMusicManager(private val activity: Activity) { } } + fun autopauseMusic(callback: PlayCallback){ + if (!isBindQQMusicService || qqmusicApi == null) { + callback.onError(-1, "QQ音乐服务未连接") + return + } + // 获取播放状态 + val stateResult = qqmusicApi?.execute("getPlaybackState", null) + val stateCode = stateResult?.getInt(Keys.API_RETURN_KEY_CODE) ?: -1 + + // 处理播放状态 - 使用正确的常量 + if (stateCode == ErrorCodes.ERROR_OK) { + val playState = stateResult?.getInt(Keys.API_RETURN_KEY_DATA) ?: 0 + val isPlaying = when (playState) { + PlayState.STARTED -> true + PlayState.PREPARED -> true + PlayState.BUFFERING -> true + PlayState.PAUSED -> false + PlayState.STOPPED -> false + PlayState.ERROR -> false + else -> false + } + if(isPlaying){ + val result = qqmusicApi?.execute("pauseMusic", null) + val code = result?.getInt(Keys.API_RETURN_KEY_CODE) ?: -1 + if (code == ErrorCodes.ERROR_OK) { + callback.onSuccess() + } else { + callback.onError(code, "暂停失败") + } + }else { + callback.onError(-1, "未播放") + } + } else { + callback.onError(-1, "未播放") + } + } + /** * 暂停音乐 */ diff --git a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt index e617a7db6..6cd6de9de 100644 --- a/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt +++ b/local_plugins/qq_music/android/src/main/kotlin/com/yunqiinnovation/qq_music/QQMusicSingleton.kt @@ -25,8 +25,8 @@ class QQMusicSingleton private constructor() { private const val KEY_EXPIRE_TIME = "expire_time" private const val LOGIN_WAIT_DELAY_MS = 30000L // 添加搜索重试相关常量 - private const val SEARCH_TIMEOUT_MS = 50000L - private const val MAX_RETRY_COUNT = 3 + private const val SEARCH_TIMEOUT_MS = 10000L + private const val MAX_RETRY_COUNT = 1 private const val RETRY_DELAY_MS = 1000L @Volatile @@ -194,7 +194,7 @@ class QQMusicSingleton private constructor() { callback(Result.failure(Exception("未安装QQ音乐软件,请先安装QQ音乐软件"))) return } - searchWithRetry(keyword, searchType, 0, callback) + searchWithRetry(keyword, searchType, 1, callback) } /** @@ -413,7 +413,16 @@ class QQMusicSingleton private constructor() { musicManager.pauseMusic(playCallback) }(callback) } - + + + /** + * 暂停音乐 + */ + fun autopauseMusic(callback: (Result) -> Unit) { + executePlaybackAction("自动暂停") { musicManager, playCallback -> + musicManager.autopauseMusic(playCallback) + }(callback) + } /** * 恢复播放 */