14 changed files with 462 additions and 140 deletions
@ -0,0 +1,223 @@ |
|||||
|
import Foundation |
||||
|
import music_service |
||||
|
|
||||
|
class MusicSystemFunctionHandler { |
||||
|
|
||||
|
// 添加 registerAllFunctions 方法 |
||||
|
func registerAllFunctions(client: MCPClient) { |
||||
|
|
||||
|
|
||||
|
// 注册QQ音乐搜索和播放功能 |
||||
|
client.registerLocalFunction( |
||||
|
name: "music_searchandplay_songs", |
||||
|
description: "在音乐播放服务中搜索并播放歌曲,支持歌曲、专辑、歌手等搜索类型", |
||||
|
parameters: [ |
||||
|
"type": "object", |
||||
|
"properties": [ |
||||
|
"keyword": [ |
||||
|
"type": "string", |
||||
|
"description": "搜索关键词,歌曲名、专辑名或歌手名" |
||||
|
], |
||||
|
"searchType": [ |
||||
|
"type": "integer", |
||||
|
"description": "搜索类型:0-歌名搜索,1-歌手搜索,2-歌曲类型搜索", |
||||
|
"default": 0 |
||||
|
] |
||||
|
], |
||||
|
"required": ["keyword"] |
||||
|
], |
||||
|
handler: MusicSearchHandler() |
||||
|
) |
||||
|
|
||||
|
// 注册媒体控制函数 |
||||
|
registerMediaPlayFunction(client: client) |
||||
|
registerMediaPauseFunction(client: client) |
||||
|
registerMediaCloseFunction(client: client) |
||||
|
registerMediaPreviousFunction(client: client) |
||||
|
registerMediaNextFunction(client: client) |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// MARK: - Private Handler Classes |
||||
|
|
||||
|
private class MusicSearchHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
guard let keyword = arguments["keyword"] as? String else { |
||||
|
let result: [String: Any] = ["success": false, "message": "缺少搜索关键词"] |
||||
|
let jsonData = try JSONSerialization.data(withJSONObject: result) |
||||
|
return String(data: jsonData, encoding: .utf8) ?? "{}" |
||||
|
} |
||||
|
let searchType = arguments["searchType"] as? Int ?? 0 |
||||
|
|
||||
|
return await withCheckedContinuation { continuation in |
||||
|
MusicService.shared.searchSongs(keyword: keyword, searchType: searchType) { searchResult in |
||||
|
switch searchResult { |
||||
|
case .success(let songs): |
||||
|
let songsJson = songs.map { song -> [String: Any] in |
||||
|
return [ |
||||
|
"id": song["id"] ?? 0, |
||||
|
"name": song["name"] ?? "unknown", |
||||
|
"singer": song["singer"] ?? "unknown", |
||||
|
"url": song["url"] ?? "", |
||||
|
"image": song["image"] ?? "", |
||||
|
"ts": song["ts"] ?? 0 |
||||
|
] |
||||
|
} |
||||
|
|
||||
|
let result: [String: Any] = [ |
||||
|
"success": true, |
||||
|
"broadcast": false, |
||||
|
"message": "搜索成功,正在播放", |
||||
|
"data": songsJson |
||||
|
] |
||||
|
|
||||
|
do { |
||||
|
let jsonData = try JSONSerialization.data(withJSONObject: result, options: []) |
||||
|
let jsonString = String(data: jsonData, encoding: .utf8) ?? "{}" |
||||
|
continuation.resume(returning: jsonString) |
||||
|
} catch { |
||||
|
continuation.resume(returning: "{\"success\": false, \"message\": \"JSON serialization failed\"}") |
||||
|
} |
||||
|
|
||||
|
case .failure(let error): |
||||
|
let result: [String: Any] = [ |
||||
|
"success": false, |
||||
|
"message": "搜索失败: \(error.localizedDescription)" |
||||
|
] |
||||
|
do { |
||||
|
let jsonData = try JSONSerialization.data(withJSONObject: result) |
||||
|
let jsonString = String(data: jsonData, encoding: .utf8) ?? "{}" |
||||
|
continuation.resume(returning: jsonString) |
||||
|
} catch { |
||||
|
continuation.resume(returning: "{\"success\": false, \"message\": \"Search failed and JSON serialization failed\"}") |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 注册媒体播放函数 |
||||
|
private func registerMediaPlayFunction(client: MCPClient) { |
||||
|
let parameters: [String: Any] = [ |
||||
|
"type": "object", |
||||
|
"properties": [:], |
||||
|
"required": [] |
||||
|
] |
||||
|
|
||||
|
let handler = MediaPlayHandler() |
||||
|
_ = client.registerLocalFunction( |
||||
|
name: "music_resume", |
||||
|
description: "恢复音乐播放", |
||||
|
parameters: parameters, |
||||
|
handler: handler |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
/// 注册媒体暂停函数 |
||||
|
private func registerMediaPauseFunction(client: MCPClient) { |
||||
|
let parameters: [String: Any] = [ |
||||
|
"type": "object", |
||||
|
"properties": [:], |
||||
|
"required": [] |
||||
|
] |
||||
|
|
||||
|
let handler = MediaPauseHandler() |
||||
|
_ = client.registerLocalFunction( |
||||
|
name: "music_pause", |
||||
|
description: "暂停音乐播放", |
||||
|
parameters: parameters, |
||||
|
handler: handler |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
/// 注册媒体关闭函数 |
||||
|
private func registerMediaCloseFunction(client: MCPClient) { |
||||
|
let parameters: [String: Any] = [ |
||||
|
"type": "object", |
||||
|
"properties": [:], |
||||
|
"required": [] |
||||
|
] |
||||
|
|
||||
|
let handler = MediaCloseHandler() |
||||
|
_ = client.registerLocalFunction( |
||||
|
name: "music_close", |
||||
|
description: "关闭音乐播放", |
||||
|
parameters: parameters, |
||||
|
handler: handler |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/// 注册媒体上一首函数 |
||||
|
private func registerMediaPreviousFunction(client: MCPClient) { |
||||
|
let parameters: [String: Any] = [ |
||||
|
"type": "object", |
||||
|
"properties": [:], |
||||
|
"required": [] |
||||
|
] |
||||
|
|
||||
|
let handler = MediaPreviousHandler() |
||||
|
_ = client.registerLocalFunction( |
||||
|
name: "music_previous", |
||||
|
description: "播放上一首", |
||||
|
parameters: parameters, |
||||
|
handler: handler |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
/// 注册媒体下一首函数 |
||||
|
private func registerMediaNextFunction(client: MCPClient) { |
||||
|
let parameters: [String: Any] = [ |
||||
|
"type": "object", |
||||
|
"properties": [:], |
||||
|
"required": [] |
||||
|
] |
||||
|
|
||||
|
let handler = MediaNextHandler() |
||||
|
_ = client.registerLocalFunction( |
||||
|
name: "music_next", |
||||
|
description: "播放下一首", |
||||
|
parameters: parameters, |
||||
|
handler: handler |
||||
|
) |
||||
|
} |
||||
|
|
||||
|
/// 媒体播放处理器 |
||||
|
private class MediaPlayHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
NotificationCenter.default.post(name: NSNotification.Name("MediaPlay"), object: nil) |
||||
|
return "{\"broadcast\": false,\"result\": \"已开始音乐播放\"}" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 媒体暂停处理器 |
||||
|
private class MediaPauseHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
NotificationCenter.default.post(name: NSNotification.Name("MediaStop"), object: nil) |
||||
|
return "{\"broadcast\": false,\"result\": \"已停止音乐播放\"}" |
||||
|
} |
||||
|
} |
||||
|
/// 媒体暂停处理器 |
||||
|
private class MediaCloseHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
NotificationCenter.default.post(name: NSNotification.Name("MediaPause"), object: nil) |
||||
|
return "{\"broadcast\": false,\"result\": \"已暂停音乐播放\"}" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 媒体上一首处理器 |
||||
|
private class MediaPreviousHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
NotificationCenter.default.post(name: NSNotification.Name("MediaPrevious"), object: nil) |
||||
|
return "{\"broadcast\": false,\"result\": \"已切换到上一首\"}" |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/// 媒体下一首处理器 |
||||
|
private class MediaNextHandler: FunctionHandler { |
||||
|
func handle(arguments: [String: Any]) async throws -> String { |
||||
|
NotificationCenter.default.post(name: NSNotification.Name("MediaNext"), object: nil) |
||||
|
return "{\"broadcast\": false,\"result\": \"已切换到下一首\"}" |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue