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