diff --git a/README.md b/README.md index 895cb97..dad8183 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -[![Foo](https://img.shields.io/badge/Version-2.15-brightgreen.svg?style=flat-square)](#versions) +[![Foo](https://img.shields.io/badge/Version-2.16-brightgreen.svg?style=flat-square)](#versions) [![Foo](https://img.shields.io/badge/Website-AlexGyver.ru-blue.svg?style=flat-square)](https://alexgyver.ru/) [![Foo](https://img.shields.io/badge/%E2%82%BD$%E2%82%AC%20%D0%9D%D0%B0%20%D0%BF%D0%B8%D0%B2%D0%BE-%D1%81%20%D1%80%D1%8B%D0%B1%D0%BA%D0%BE%D0%B9-orange.svg?style=flat-square)](https://alexgyver.ru/support_alex/) @@ -66,6 +66,7 @@ ESP8266 (SDK v2.6+), ESP32 - [Время получения сообщения](#time) - [Часы реального времени](#rtc) - [Обновление прошивки из чата](#ota) + - [Оформление текста](#textmode) - [Всякие трюки](#tricks) - [Версии](#versions) - [Баги и обратная связь](#feedback) @@ -344,6 +345,7 @@ bot.sendMessage("Hello!", "112233"); // уйдёт в "112233" - `bool isBot` - сообщение от бота - `bool OTA` - запрос на OTA обновление (получен .bin файл) - `uint32_t unix` - время сообщения + - `String fileName` - имя файла - `String toString()` - вся информация из сообщения, удобно для отладки (с версии 2.11) **Примечания:** @@ -559,6 +561,23 @@ if (msg.OTA && msg.text == "update") bot.update(); if (msg.OTA && msg.chatID == "123456") bot.update(); ``` + +## Оформление текста +Библиотека поддерживает оформление текста в сообщениях. Разметка оформления выбирается при помощи `setTextMode(mode)`, где `mode`: +- `FB_TEXT` - по умолчанию (оформление отключено) +- `FB_MARKDOWN` - разметка Markdown v2 +- `FB_HTML` - разметка HTML + +Доступные теги описаны в [API Telegram](https://core.telegram.org/bots/api#formatting-options). Например для Markdown: +```cpp +bot.setTextMode(FB_MARKDOWN); +bot.sendMessage(F("*Bold*, ~Strike~, `code`, [alexgyver.ru](https://alexgyver.ru/)")); +``` + +Выведет в чат: **Bold**, ~~Strike~~, `code`, [alexgyver.ru](https://alexgyver.ru/) + +> **Внимание!** В режиме FB_MARKDOWN нельзя использовать в сообщениях символы `! + #`, сообщение не отправится. Возможно получится исправить в будущем (проблема urlencode и экранирования зарезервированных символов). + ## Трюки @@ -645,6 +664,7 @@ void loop() { - v2.13: Оптимизация памяти. Добавил OTA обновление - v2.14: Улучшен парсинг строки с ID, добавил отключение OTA, добавил парсинг названия группы/канала в username - v2.15: Заплатка для кривой библиотеки ESP32 +- v2.16: добавлен вывод fileName, пофикшены неотправляемые сообщения в Markdown режиме ## Баги и обратная связь diff --git a/examples/textMode/textMode.ino b/examples/textMode/textMode.ino index 35ac318..cdec0fe 100644 --- a/examples/textMode/textMode.ino +++ b/examples/textMode/textMode.ino @@ -12,33 +12,11 @@ void setup() { connectWiFi(); bot.setChatID(CHAT_ID); - bot.setTextMode(FB_MARKDOWN); + bot.setTextMode(FB_MARKDOWN); // вернуть по умолчанию - FB_TEXT // по форматированию читай тут https://core.telegram.org/bots/api#formatting-options - // символ точка . нужно экранировать как \\. - bot.sendMessage(F("*Bold*, ||spoiler||, ~Strike~, `code`, [alexgyver\\.ru](https://alexgyver\\.ru/)")); - - // пример из доки - // https://core.telegram.org/bots/update56kabdkb12ibuisabdubodbasbdaosd - bot.sendMessage(F("*bold _italic bold ~italic bold strikethrough ||italic bold strikethrough spoiler||~ __underline italic bold___ bold*")); + bot.sendMessage(F("*Bold*, ||spoiler||, ~Strike~, `code`, [alexgyver.ru](https://alexgyver.ru/)")); } -/* - bold \*text - _italic \*text_ - __underline__ - ~strikethrough~ - ||spoiler|| - [inline URL](http://www.example.com/) - [inline mention of a user](tg://user?id=123456789) - `inline fixed-width code` - ``` - pre-formatted fixed-width code block - ``` - ```python - pre-formatted fixed-width code block written in the Python programming language - ``` -*/ - void loop() { bot.tick(); } diff --git a/keywords.txt b/keywords.txt index cb1e035..805746e 100644 --- a/keywords.txt +++ b/keywords.txt @@ -70,6 +70,7 @@ edited KEYWORD2 isBot KEYWORD2 OTA KEYWORD2 unix KEYWORD2 +fileName KEYWORD2 toString KEYWORD2 second KEYWORD2 diff --git a/library.properties b/library.properties index b1b07cc..069751f 100644 --- a/library.properties +++ b/library.properties @@ -1,5 +1,5 @@ name=FastBot -version=2.15 +version=2.16 author=AlexGyver maintainer=AlexGyver sentence=Simple library for Telegram bot (messages and menus) diff --git a/src/FastBot.h b/src/FastBot.h index cb2da84..7235518 100644 --- a/src/FastBot.h +++ b/src/FastBot.h @@ -81,6 +81,7 @@ v2.13: Оптимизация памяти. Добавил OTA обновление v2.14: Улучшен парсинг строки с ID, добавил отключение OTA, добавил парсинг названия группы/канала в username v2.15: Заплатка для кривой библиотеки ESP32 + v2.16: добавлен вывод fileName, пофикшены неотправляемые сообщения в Markdown режиме */ /* @@ -327,6 +328,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String umsg; FB_urlencode(msg, umsg); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(umsg); #endif String req; _addToken(req); @@ -368,6 +370,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String utext; FB_urlencode(text, utext); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(utext); #endif String req; _addToken(req); @@ -428,6 +431,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String utext; FB_urlencode(text, utext); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(utext); #endif String req; _addToken(req); @@ -554,6 +558,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String umsg; FB_urlencode(msg, umsg); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(umsg); #endif String req; _addToken(req); @@ -594,6 +599,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String umsg; FB_urlencode(msg, umsg); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(umsg); #endif String req; _addToken(req); @@ -626,6 +632,7 @@ class FastBot { #ifndef FB_NO_URLENCODE String umsg; FB_urlencode(msg, umsg); + if (parseMode == FB_MARKDOWN) FB_escMarkdown(umsg); #endif String req; _addToken(req); @@ -857,8 +864,10 @@ class FastBot { #ifndef FB_NO_OTA String file; + String fileName; if (_file_ptr) _file_ptr = nullptr; if (find(str, file, textPos, F("\"file_name\":\""), '\"', IDpos)) { + fileName = file; if (file.endsWith(F(".bin"))) { find(str, file, textPos, F("\"file_id\":\""), '\"', IDpos); _file_ptr = &file; @@ -900,6 +909,7 @@ class FastBot { is_bot[0] == 't', (bool)_file_ptr, (uint32_t)date.toInt(), + fileName, // legacy userID, diff --git a/src/datatypes.h b/src/datatypes.h index a1b3143..de6770e 100644 --- a/src/datatypes.h +++ b/src/datatypes.h @@ -13,6 +13,7 @@ struct FB_msg { bool isBot; // сообщение от бота bool OTA; // запрос на OTA обновление uint32_t unix; // время сообщения + String& fileName; // имя файла // legacy String& usrID; // ID юзера diff --git a/src/utils.cpp b/src/utils.cpp index 12b7acb..c2ddded 100644 --- a/src/utils.cpp +++ b/src/utils.cpp @@ -1,5 +1,32 @@ #include "utils.h" +void FB_escHTML(String& s) { + String out; + out.reserve(s.length()); + for (uint16_t i = 0; i < s.length(); i++) { + switch (s[i]) { + case '<': out += F("<"); break; + case '>': out += F(">"); break; + case '&': out += F("&"); break; + default: out += s[i]; break; + } + } + s = out; +} + +static const char FB_escList[] = ">-={}.!"; + +void FB_escMarkdown(String& s) { + String out; + out.reserve(s.length()); + for (uint16_t i = 0; i < s.length(); i++) { + if (strchr(FB_escList, s[i]) != 0) out += '\\'; + out += s[i]; + } + Serial.println(out); + s = out; +} + int64_t FB_str64(const String &s) { return atoll(s.c_str()); } @@ -8,10 +35,10 @@ String FB_64str(int64_t id) { int32_t s1 = (int64_t)id % 1000000000; int32_t s2 = (int64_t)id / 1000000000; if (s2) { - s += s2; - s += abs(s1); + s += s2; + s += abs(s1); } else { - s += s1; + s += s1; } return s; } @@ -74,7 +101,7 @@ void FB_unicode(String &uStr) { out += (char)(0b10000000 | (uBytes & 0b111111)); } break; - default: out += uStr[i]; break; + default: out += uStr[i]; break; } } } diff --git a/src/utils.h b/src/utils.h index 7cdc289..af958b4 100644 --- a/src/utils.h +++ b/src/utils.h @@ -2,30 +2,32 @@ #include void FB_unicode(String &uStr); void FB_urlencode(const String& s, String& dest); +void FB_escHTML(String& s); +void FB_escMarkdown(String& s); int64_t FB_str64(const String &s); String FB_64str(int64_t id); struct FB_Parser { FB_Parser() { - str.reserve(20); + str.reserve(20); } bool parseNT(const String& s) { - while (!end) { - char c1 = s[++i]; - if (c1 == '\t' || c1 == '\n' || c1 == '\0') { - int to = i; - if (s[to - 1] == ' ') to--; - if (s[from] == ' ') from++; - str = s.substring(from, to); - from = i + 1; - end = (c1 == '\0'); - div = c1; - return 1; + while (!end) { + char c1 = s[++i]; + if (c1 == '\t' || c1 == '\n' || c1 == '\0') { + int to = i; + if (s[to - 1] == ' ') to--; + if (s[from] == ' ') from++; + str = s.substring(from, to); + from = i + 1; + end = (c1 == '\0'); + div = c1; + return 1; + } } - } - return 0; + return 0; } bool parse(const String& s) {