diff --git a/include/tgbotxx/objects/InputMedia.hpp b/include/tgbotxx/objects/InputMedia.hpp index 7ac3000dd..8ea6dec7f 100644 --- a/include/tgbotxx/objects/InputMedia.hpp +++ b/include/tgbotxx/objects/InputMedia.hpp @@ -19,11 +19,13 @@ namespace tgbotxx { /// @brief Type of the result. std::string type; - /// @brief File to send. Pass a file_id to send a file that exists on the Telegram servers (recommended), - /// Pass an HTTP URL for Telegram to get a file from the Internet, or - /// Pass “attach://” to upload a new one using multipart/form-data under name. + /// @brief File to send. + /// - Pass a file_id std::string to send a file that exists on the Telegram servers (recommended), + /// - Pass an HTTP URL std::string for Telegram to get a file from the Internet, or + /// - Pass a cpr::File to upload a local file + /// The latter will internally use “attach://” with multipart/form-data under name to upload the local file. /// More information on Sending Files » https://core.telegram.org/bots/api#sending-files - std::string media; + std::variant media{""}; /// @brief Optional. Caption of the media to be sent, 0-1024 characters after entities parsing std::string caption; @@ -41,7 +43,11 @@ namespace tgbotxx { virtual nl::json toJson() const { nl::json json = nl::json::object(); OBJECT_SERIALIZE_FIELD(json, "type", type); - OBJECT_SERIALIZE_FIELD(json, "media", media); + // media variant + if (auto idx = media.index(); idx == 0) + json["media"] = std::get(media).filepath; + else if (idx == 1) + json["media"] = std::get(media); OBJECT_SERIALIZE_FIELD(json, "caption", caption); OBJECT_SERIALIZE_FIELD(json, "parse_mode", parseMode); OBJECT_SERIALIZE_FIELD_PTR_ARRAY(json, "caption_entities", captionEntities); @@ -51,7 +57,8 @@ namespace tgbotxx { /// @brief Deserializes this object from JSON virtual void fromJson(const nl::json& json) { OBJECT_DESERIALIZE_FIELD(json, "type", type, "", false); - OBJECT_DESERIALIZE_FIELD(json, "media", media, "", false); + // media variant, we can't get a local file from remote, so it's always a URL or file id std::string. + OBJECT_DESERIALIZE_FIELD(json, "media", std::get(media), "", false); OBJECT_DESERIALIZE_FIELD(json, "caption", caption, "", true); OBJECT_DESERIALIZE_FIELD(json, "parse_mode", parseMode, "", true); OBJECT_DESERIALIZE_FIELD_PTR_ARRAY(json, "caption_entities", captionEntities, true); diff --git a/src/Api.cpp b/src/Api.cpp index ca4779660..aa62ef24f 100644 --- a/src/Api.cpp +++ b/src/Api.cpp @@ -731,8 +731,27 @@ std::vector> Api::sendMediaGroup(const std::variant 10 or media.size() < 2) throw Exception("Api::sendMediaGroup(): media must include 2-10 items. See https://core.telegram.org/bots/api#sendmediagroup"); nl::json mediaJson = nl::json::array(); + // Handle local media files if available, see https://core.telegram.org/bots/api#inputmediaphoto for (const Ptr& m: media) - mediaJson.push_back(m->toJson()); + { + nl::json mJson = m->toJson(); + switch(m->media.index()) { + case 0: // cpr::File (Local File) + { + const cpr::File& file = std::get(m->media); + std::string fileKey = StringUtils::random(8); + mJson["media"] = "attach://" + fileKey; + data.parts.emplace_back(fileKey, cpr::Files{file}); + break; + } + case 1: // std::string (URL, File ID) + { + // do nothing as toJson will export the "media": "URL or file ID" object. + break; + } + } + mediaJson.push_back(mJson); + } data.parts.emplace_back("media", mediaJson.dump()); if (messageThreadId) data.parts.emplace_back("message_thread_id", messageThreadId); diff --git a/tests/manual_tests.cpp b/tests/manual_tests.cpp index c2923b954..f8641cb46 100644 --- a/tests/manual_tests.cpp +++ b/tests/manual_tests.cpp @@ -153,7 +153,7 @@ class MyBot : public Bot { getApi()->sendMessage(message->chat->id, "Sending URL photo..."); getApi()->sendPhoto(message->chat->id, "https://www.hdwallpapers.in/download/landscape_view_of_sunset_under_yellow_black_cloudy_sky_4k_5k_hd_nature-5120x2880.jpg"); getApi()->sendMessage(message->chat->id, "Sending File photo..."); - getApi()->sendPhoto(message->chat->id, cpr::File{"/home/bader/Pictures/2021/05/30/thumb-1920-642642.jpg"}); + getApi()->sendPhoto(message->chat->id, cpr::File{fs::path(__FILE__).parent_path().parent_path() / "examples/sendPhoto/photos/image1.jpg"}); } else if (message->text == "/inline_buttons") { /* Create inline keyboard buttons @@ -226,7 +226,7 @@ class MyBot : public Bot { { getApi()->sendMessage(message->chat->id, "Sending pdf media group ..."); std::vector> mediaGroup; - for (const std::string_view docURL: {"https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4928.pdf", + for (const std::string docURL: {"https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4928.pdf", "https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4933.pdf", "https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/n4934.pdf", "https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2759r0.pdf"}) { @@ -234,20 +234,32 @@ class MyBot : public Bot { document->media = docURL; mediaGroup.push_back(document); } + // add extra local doc + Ptr localDoc(new InputMediaDocument()); + localDoc->media = cpr::File{__FILE__}; + mediaGroup.push_back(localDoc); + api()->sendMediaGroup(message->chat->id, mediaGroup); } { getApi()->sendMessage(message->chat->id, "Sending photo media group ..."); std::vector> mediaGroup; - for (const std::string_view photoURL: {"https://images.alphacoders.com/129/1299740.jpg", - "https://images2.alphacoders.com/112/1128233.jpg", - "https://images2.alphacoders.com/131/1311487.jpg", - "https://images5.alphacoders.com/129/1295587.jpg", - "https://images5.alphacoders.com/121/1217119.png", - "https://images6.alphacoders.com/510/510365.jpg"}) { + for (const fs::path& localPhotoPath: {fs::path(__FILE__).parent_path().parent_path() / "examples/sendPhoto/photos/image1.jpg", + fs::path(__FILE__).parent_path().parent_path() / "examples/sendPhoto/photos/image2.jpg"}) { + Ptr photo(new InputMediaPhoto()); + photo->media = cpr::File{localPhotoPath}; // Local + photo->hasSpoiler = false; + mediaGroup.push_back(photo); + } + for (const std::string photoURL: {"https://images.alphacoders.com/129/1299740.jpg", + "https://images2.alphacoders.com/112/1128233.jpg", + "https://images2.alphacoders.com/131/1311487.jpg", + "https://images5.alphacoders.com/129/1295587.jpg", + "https://images5.alphacoders.com/121/1217119.png", + "https://images6.alphacoders.com/510/510365.jpg"}) { Ptr photo(new InputMediaPhoto()); - photo->media = photoURL; - photo->hasSpoiler = !!(std::rand() % 3); + photo->media = photoURL; // URL + photo->hasSpoiler = false; mediaGroup.push_back(photo); } api()->sendMediaGroup(message->chat->id, mediaGroup);