diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 4491178..dfccc4e 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -34,4 +34,5 @@ api_exe(GroupMemberInfo) api_exe(GroupNameChange) api_exe(GroupConfig) api_exe(MemberCardChange) -api_exe(Command) \ No newline at end of file +api_exe(Command) +api_exe(VoiceMessage) \ No newline at end of file diff --git a/examples/VoiceMessage.cpp b/examples/VoiceMessage.cpp new file mode 100644 index 0000000..fc3f651 --- /dev/null +++ b/examples/VoiceMessage.cpp @@ -0,0 +1,45 @@ +#include +// 使用静态库必须要在引入 mirai.h 前定义这个宏 +#define MIRAICPP_STATICLIB +#include + +int main() +{ + using namespace std; + using namespace Cyan; + system("chcp 65001"); + MiraiBot bot("127.0.0.1", 539); + while (true) + { + try + { + bot.Auth("INITKEY7A3O1a9v", 1589588851_qq); + break; + } + catch (const std::exception& ex) + { + cout << ex.what() << endl; + } + MiraiBot::SleepSeconds(1); + } + cout << "成功登录 bot。" << endl; + + bot.On( + [&](GroupMessage m) + { + try + { + MiraiVoice voice = bot.UploadGroupVoice("D:\\5.amr"); + m.Reply(MessageChain().Voice(voice)); + } + catch (const std::exception& ex) + { + cout << ex.what() << endl; + } + }); + + + bot.EventLoop(); + + return 0; +} \ No newline at end of file diff --git a/include/mirai/defs/message_chain.hpp b/include/mirai/defs/message_chain.hpp index a84d91a..c977788 100644 --- a/include/mirai/defs/message_chain.hpp +++ b/include/mirai/defs/message_chain.hpp @@ -21,6 +21,7 @@ #include "messages/JsonMessage.hpp" #include "messages/PokeMessage.hpp" #include "messages/QuoteMessage.hpp" +#include "messages/VoiceMessage.hpp" using std::vector; @@ -182,6 +183,11 @@ namespace Cyan return this->Add(poke); } + MessageChain& Voice(const VoiceMessage& voice) + { + return this->Add(voice); + } + string GetPlainText() const; string GetPlainTextFirst() const; diff --git a/include/mirai/defs/messages/VoiceMessage.hpp b/include/mirai/defs/messages/VoiceMessage.hpp new file mode 100644 index 0000000..c186601 --- /dev/null +++ b/include/mirai/defs/messages/VoiceMessage.hpp @@ -0,0 +1,96 @@ +#pragma once +#ifndef mirai_cpp_defs_messages_voice_message_hpp_H_ +#define mirai_cpp_defs_messages_image_message_hpp_H_ + +#include "mirai/defs/message_interface.hpp" +#include "mirai/defs/qq_types.hpp" + +namespace Cyan +{ + class VoiceMessage : public IMessage + { + public: + VoiceMessage() {} + VoiceMessage(const MiraiVoice& m) + { + voiceId_ = m.Id; + url_ = m.Url; + path_ = m.Path; + } + virtual const string& GetType() const override + { + return type_; + } + virtual bool operator==(const IMessage& m) const override + { + if (auto m_ptr = dynamic_cast(&m)) + { + // 用 voiceId 作为判断依据,必须有一个 voiceId 不为空 + if (!m_ptr->voiceId_.empty() || !this->voiceId_.empty()) + { + return (m_ptr->voiceId_ == this->voiceId_); + } + // 如果 voiceId 都为空,那么用 url 再判断一下 + if (!m_ptr->url_.empty() || !this->url_.empty()) + { + return (m_ptr->url_ == this->url_); + } + // 如果 url 都为空,那么用 path 再判断一下 + if (!m_ptr->path_.empty() || !this->path_.empty()) + { + return (m_ptr->path_ == this->path_); + } + // 三个参数都为空,两个空的 VoiceMessage 当然是相等的: + return true; + } + // 类型都不同,直接不相等: + return false; + } + virtual bool operator!=(const IMessage& m) const override + { + return !(*this == m); + } + virtual bool Set(const json& json) override + { + if (json["type"].is_null() || json["type"].get() != this->GetType()) + throw std::runtime_error("给定的json不正确"); + if (!json["voiceId"].is_null()) + voiceId_ = json["voiceId"].get(); + if (!json["url"].is_null()) + url_ = json["url"].get(); + if (!json["path"].is_null()) + path_ = json["path"].get(); + return true; + } + virtual json ToJson() const override + { + return + { + { "type", type_ }, + { "voiceId", voiceId_ }, + { "url", url_ }, + { "path", path_ } + }; + } + virtual ~VoiceMessage() {} + + MiraiVoice ToMiraiVoice() const + { + MiraiVoice tmp; + tmp.Id = voiceId_; + tmp.Url = url_; + tmp.Path = path_; + return tmp; + } + + private: + string type_ = "Voice"; + protected: + string voiceId_; + string url_; + string path_; + }; + +} +#endif + diff --git a/include/mirai/defs/qq_types.hpp b/include/mirai/defs/qq_types.hpp index d81f2fd..94da1a8 100644 --- a/include/mirai/defs/qq_types.hpp +++ b/include/mirai/defs/qq_types.hpp @@ -92,6 +92,13 @@ namespace Cyan typedef MiraiImage TempImage; + struct MiraiVoice + { + string Id; + string Url; + string Path; + }; + // 预先声明 MiraiBot 类 class EXPORTED MiraiBot; diff --git a/include/mirai/mirai_bot.hpp b/include/mirai/mirai_bot.hpp index 8b9c387..e1b6fe3 100644 --- a/include/mirai/mirai_bot.hpp +++ b/include/mirai/mirai_bot.hpp @@ -71,7 +71,7 @@ namespace Cyan int GetRequiredApiVersionInt() const { // mirai-api-http v1.6.5 - return 10704; + return 10800; } /** @@ -81,7 +81,7 @@ namespace Cyan string GetRequiredApiVersion() const { // mirai-api-http v1.6.5 - return "v1.7.4"; + return "v1.8.0"; } /** @@ -154,6 +154,12 @@ namespace Cyan * \return 临时消息图片 */ TempImage UploadTempImage(const string& fileName); + /** + * @brief 上传可以发给群组的语音 + * @param filename 文件名(amr文件) + * @return MiraiVoice + */ + MiraiVoice UploadGroupVoice(const string& filename); /** * \brief 获得好友列表 * \return vector diff --git a/src/mirai_bot.cpp b/src/mirai_bot.cpp index 4f7ead3..aaa8664 100644 --- a/src/mirai_bot.cpp +++ b/src/mirai_bot.cpp @@ -255,6 +255,31 @@ namespace Cyan } + MiraiVoice MiraiBot::UploadGroupVoice(const string& filename) + { + string voice_data = ReadFile(filename); + httplib::MultipartFormDataItems items = + { + { "sessionKey", sessionKey_, "", "" }, + { "type", "group", "", "" }, + { "voice", voice_data, std::to_string(rand()) + ".amr", "application/octet-stream" } + }; + + auto res = http_client_.Post("/uploadVoice", items); + + if (!res) + throw runtime_error("网络错误"); + if (res->status != 200) + throw std::runtime_error("[mirai-http-api error]: " + res->body); + json re_json = json::parse(res->body); + MiraiVoice result; + result.Id = re_json["voiceId"].get(); + if (!re_json["url"].is_null()) + result.Url = re_json["url"].get(); + result.Path = re_json["path"].get(); + return result; + } + vector MiraiBot::GetFriendList() { auto res = http_client_.Get(("/friendList?sessionKey=" + sessionKey_).data()); @@ -628,9 +653,9 @@ namespace Cyan } MiraiBot& MiraiBot::RegisterCommand( - const string& commandName, - const vector alias, - const string& description, + const string& commandName, + const vector alias, + const string& description, const string& helpMessage) { json data =