1
0
mirror of https://github.com/InsanusMokrassar/TelegramBotAPI.git synced 2025-11-16 12:00:18 +00:00

Compare commits

..

246 Commits

Author SHA1 Message Date
69973c597b update BotCommandNameRegex 2020-06-02 22:10:33 +06:00
22e8b06fda BotBuilder fixes 2020-06-02 21:18:49 +06:00
7ede53fdbb BotCommandNameRegex and strict check of incoming command 2020-06-02 20:16:55 +06:00
ca9051920d new setMyCommands extension added 2020-06-02 19:54:13 +06:00
b477e8d585 extend getChat extensions 2020-06-02 13:54:30 +06:00
8ae2f57d55 update description of PreviewFeature annotation 2020-06-02 13:47:28 +06:00
1fb2ecf15f executes was replaced 2020-06-02 13:39:09 +06:00
6073d914d5 hotfixes in new media groups shortcuts 2020-06-02 13:22:36 +06:00
16f55d70af resend and other media group utils replaced into TelegramBotAPI_extensions-utils 2020-06-02 13:21:38 +06:00
b484a31a4a replacement of CaptionAndTextSourcesToText 2020-06-02 13:05:15 +06:00
0a162c4129 StringFormattiing replacement 2020-06-02 01:26:46 +06:00
648f1b488b add makeLinkToAddStickerSet 2020-06-02 01:15:08 +06:00
5fbde4bc06 new "row" 2020-06-02 01:02:38 +06:00
2a276d9272 safely function 2020-06-01 12:56:48 +06:00
9ae252717d versions update 2020-06-01 12:00:06 +06:00
456143a266 complete refresh of CaptinAndTextSourcesToText 2020-06-01 11:55:48 +06:00
0bcc98e126 update caption errors 2020-06-01 11:53:33 +06:00
ab9ceba41c updates in caption and text lengths 2020-06-01 11:44:58 +06:00
7cd5666e88 use maxTextLength inside of CaptionAndTextSourcesToText 2020-05-31 22:53:04 +06:00
35dcd6ada7 fix in SendMessage 2020-05-31 22:51:42 +06:00
ec37df82a9 start 0.27.5 2020-05-31 22:43:35 +06:00
220cb47615 update look like of kdocs badge 2020-05-23 15:46:49 +06:00
d79b8a337a add kdocs badge 2020-05-23 15:43:47 +06:00
cef6a6f741 update telegram badge 2020-05-23 15:27:45 +06:00
9471df1f2d Merge pull request #89 from InsanusMokrassar/0.27.4
0.27.4
2020-05-23 15:22:13 +06:00
f121e5f9c3 renames for JVM signature duplication avoiding 2020-05-23 12:53:42 +06:00
7f4fe318c5 update filters 2020-05-22 16:40:30 +06:00
dbf5c2dbb2 update publish scripts 2020-05-22 14:03:48 +06:00
105415873d updates extensions 2020-05-22 13:21:22 +06:00
ff32fd1dfc 0.27.4 started 2020-05-22 12:56:50 +06:00
006251ed07 fixes 2020-05-17 15:10:02 +06:00
9307582654 Add TelegramBotAPI-all status to readme 2020-05-17 01:30:05 +06:00
fe11a2119e Return opts in telegram bot api 2020-05-16 22:24:50 +06:00
c31403c1a2 Merge pull request #88 from InsanusMokrassar/0.27.3
0.27.3
2020-05-16 22:07:56 +06:00
0260e7bedc fixes of warnings 2020-05-16 22:02:57 +06:00
fa43a55f26 one more update of labeler 2020-05-16 21:54:54 +06:00
e9e1f4b9cf Merge branch 'master' into 0.27.3 2020-05-16 21:24:14 +06:00
e7b5b9184d update rules for labelers 2020-05-16 21:22:37 +06:00
81aa3f2307 update labeler task 2020-05-16 21:19:38 +06:00
a9fe584504 add TOC for TelegramBotAPI-extensions-utils 2020-05-16 21:14:10 +06:00
4c8861ba79 change visibility of internalSetWebhookInfoAndStartListenWebhooks 2020-05-16 20:57:57 +06:00
0ec18cbf06 dice changes 2020-05-16 20:46:49 +06:00
7008f312dc fixes 2020-05-16 20:43:09 +06:00
85317a510e update docs 2020-05-16 11:09:31 +06:00
d629aa206e fixes 2020-05-15 22:14:19 +06:00
6394e1a52b setWebhookInfo 2020-05-15 22:02:53 +06:00
23dca3d307 small grammar fix in WebhookInfo 2020-05-15 19:19:30 +06:00
3032aa8474 renaming of telegramBot functions 2020-05-15 19:14:09 +06:00
db19b69ca0 fails handler in executeUnsafe 2020-05-15 19:04:10 +06:00
f3827f81a7 change mechanism of executeUnsafe 2020-05-15 18:59:42 +06:00
0532dbb1ae fixes 2020-05-15 18:39:12 +06:00
efc2681da8 add additional signatures for setWebhookInfoAndStartListenWebhooks 2020-05-15 18:35:16 +06:00
735ed9fd86 change flowsUpdatesFilter signature 2020-05-15 18:31:49 +06:00
e856dc4754 add flowsUdatesFilter 2020-05-15 18:17:55 +06:00
0706ff1f95 Update labeler.yml 2020-05-15 18:06:29 +06:00
336b830b0b Merge branch 'master' into 0.27.3 2020-05-15 18:05:57 +06:00
1a638fe0a5 update labeler
one more update of labeler
2020-05-15 18:05:00 +06:00
45467e5bd7 Create labeler.yml 2020-05-15 18:05:00 +06:00
8419b0ab6a Create label.yml 2020-05-15 18:05:00 +06:00
49573607fb Create greetings.yml 2020-05-15 18:05:00 +06:00
35fe48db35 Create labeler.yml 2020-05-15 17:05:53 +06:00
590db3e672 Create label.yml 2020-05-15 17:02:33 +06:00
ea40474c47 add opportunity to set up media groups devounce time 2020-05-15 16:53:21 +06:00
7354389f2d Create greetings.yml 2020-05-15 15:49:10 +06:00
1f20ae16aa Update README.md 2020-05-15 00:54:00 +06:00
095c91bf39 update readmes with updates handling 2020-05-15 00:48:34 +06:00
dc173d752c optimize imports 2020-05-15 00:29:17 +06:00
a1788e35b2 clean up in webhooks 2020-05-15 00:28:16 +06:00
ea224fd765 add javax.activation dependency 2020-05-14 21:18:33 +06:00
7f51544bb9 Fix links in TelegramBotAPI-all readme 2020-05-14 16:25:39 +06:00
dfb22b0e89 update readme of all includer 2020-05-14 14:26:42 +06:00
e675e841da update urls 2020-05-14 14:23:26 +06:00
dea43aad8e update subprojects implementation types 2020-05-14 14:11:33 +06:00
52e25e934d add TelegramBotAPI-all 2020-05-14 14:07:23 +06:00
acc067585d add build instructions in README 2020-05-14 13:44:18 +06:00
47aa1a0795 fixes in CHANGELOG and docs 2020-05-14 13:26:56 +06:00
b40cc0c1ea fixes 2020-05-14 13:11:46 +06:00
b5632626ad small extention docs for RequestsExecutor 2020-05-14 12:21:38 +06:00
67fafdac00 add docs for RequestsExecutor 2020-05-14 12:14:38 +06:00
738e628a89 small change of deprecations message 2020-05-13 23:25:22 +06:00
420b846466 replace long polling and webhook tools 2020-05-13 23:22:35 +06:00
05e8c9c90d replace webhooks work into api subproject 2020-05-13 21:21:07 +06:00
e776c5182f additional setWebhook 2020-05-13 20:56:03 +06:00
be5b3745b9 extension was added 2020-05-13 20:01:58 +06:00
0de1d9cfda UpdateDeserializationStrategy currently is public 2020-05-13 19:53:27 +06:00
01da98d2fe start 0.27.3 2020-05-13 19:48:07 +06:00
e985100c21 Update README.md 2020-05-13 19:41:46 +06:00
671faabef9 add telegramBot function 2020-05-12 18:52:37 +06:00
bb9c9e22a2 remove dokka docs from github 2020-05-12 00:14:16 +06:00
42228f0eaa Merge pull request #86 from InsanusMokrassar/0.27.2
0.27.2
2020-05-11 23:42:17 +06:00
dafd0a8ece add docs 2020-05-11 23:37:38 +06:00
bee9d82372 update folder of dokka 2020-05-11 23:24:26 +06:00
ec6cf0f029 docs 2020-05-11 20:44:03 +06:00
9cee22165d start normal filling of docs 2020-05-11 20:32:14 +06:00
a58aad1198 update docs generation 2020-05-11 13:56:45 +06:00
aa78d99179 add docs project 2020-05-11 01:09:07 +06:00
603efe9259 small update of utils readme 2020-05-10 16:40:53 +06:00
21e3e10222 renames 2020-05-10 16:33:44 +06:00
34eb6eb4bf add ChatEventsConversations and refill README of telegramboapi-extensions-utils 2020-05-10 16:25:42 +06:00
565a724b9c remove todo from thumbed input media 2020-05-10 15:30:23 +06:00
e87c4a0126 MediaGroupMemberInputMedia deserialization 2020-05-10 15:26:07 +06:00
9b16d5d82b add MimeType 2020-05-10 14:37:55 +06:00
9747c8bff1 warnings fixes 2020-05-09 21:04:56 +06:00
3ee84700f4 update versions 2020-05-09 20:57:55 +06:00
04a463f42c start 0.27.2 2020-05-09 20:52:52 +06:00
668a201789 Merge pull request #85 from InsanusMokrassar/0.27.1
0.27.1
2020-04-25 10:12:53 +06:00
b336b17eef FullTextSourcesList 2020-04-25 09:57:59 +06:00
76b25d719a explanation small utils and explanationLimit 2020-04-25 09:48:23 +06:00
a4d077dd17 add Explained interface and use it in polls 2020-04-25 09:41:04 +06:00
469712150b started 0.27.1 2020-04-25 09:26:10 +06:00
fad27ede78 Merge pull request #84 from InsanusMokrassar/0.27.0
0.27.0
2020-04-24 21:25:11 +06:00
1de90412b3 addition in changelog 2020-04-24 21:24:24 +06:00
215c8793e1 optimize imports 2020-04-24 20:25:53 +06:00
54835f97d1 update TelegramBotAPI utils readme 2020-04-24 20:23:25 +06:00
923e929670 update TelegramBotAPI readme 2020-04-24 20:16:12 +06:00
37488e92e6 utils ScheduledCloseInfo shortcuts 2020-04-24 20:01:20 +06:00
830ca8122d add openPeriodPollSecondsLimit and checks 2020-04-24 19:46:47 +06:00
fbb2758bdb update changelog 2020-04-24 19:26:57 +06:00
a5c3e06f1c remove List<TextPart> extensions for texts due to JVM signature conflict and actualize TelegramBotAPI-extensions-api 2020-04-24 19:24:49 +06:00
c6fb50c4a6 SendPoll#closeInfo functionality 2020-04-24 19:08:54 +06:00
976c0b86dc send quiz poll functionality 2020-04-24 18:46:26 +06:00
fee5d8f925 texts and captions utils 2020-04-24 18:44:04 +06:00
808746e12d Dice#emoji support 2020-04-24 18:25:47 +06:00
3fb80dd475 add support of income explanation functionality in polls and polls auto close functionality 2020-04-24 17:51:09 +06:00
db8ea0da94 update versions 2020-04-24 16:18:07 +06:00
fbdfb714a3 started 0.27.0 2020-04-24 16:13:02 +06:00
1facfbc2b7 Merge pull request #83 from InsanusMokrassar/0.26.4
0.26.4
2020-04-22 15:08:35 +06:00
914a0662a9 CallbackGameInlineKeyboardButton now have only one income parameter 2020-04-22 14:11:46 +06:00
eda3003b7d change the way how we are deserializing updates in webhooks 2020-04-22 13:20:15 +06:00
459942de36 webhook update handling enhancement 2020-04-22 13:16:46 +06:00
17f64f9b48 CallbackGame update 2020-04-22 13:08:05 +06:00
3f896c2240 fix not implemented error thrown 2020-04-22 13:05:57 +06:00
94f8c971c5 started 0.26.4 2020-04-22 13:01:17 +06:00
c43109c063 Update README.md 2020-04-17 15:52:47 +06:00
f6058e29b4 Update README.md 2020-04-17 15:52:28 +06:00
3a37311331 Update README.md 2020-04-17 15:52:03 +06:00
9fe1472e64 update readme for help on JS platform 2020-04-17 15:43:43 +06:00
f1480c40a7 Merge pull request #81 from InsanusMokrassar/0.26.3
0.26.3
2020-04-13 12:55:48 +06:00
88eebdc448 small optimization of updates polling exception handling 2020-04-13 12:53:02 +06:00
8c76283db5 suspend inline function handleSafely was added 2020-04-13 12:40:14 +06:00
7668c48081 BaseEditMessageUpdate#data now is CommonMessage 2020-04-13 12:09:59 +06:00
35d2135f73 update serialization of InlineKeyboardButton 2020-04-13 11:31:36 +06:00
1cb0e096be fixes in InlineKeyboardButtonSerializer 2020-04-13 11:20:39 +06:00
31f7c7f31b UnknownUpdateType even if serialization exception 2020-04-13 11:17:15 +06:00
82d3b3bc48 add UnknownInlineKeyboardButton 2020-04-13 11:11:09 +06:00
b3734a5c2a fix of changelog 2020-04-13 01:46:58 +06:00
55b8736d50 Merge pull request #80 from Djaler/inline-keyboard-button-callback-game
Add support for inline keyboard buttons with callback_game field
2020-04-13 01:40:52 +06:00
3334fd3ca6 started 0.26.3 2020-04-13 01:39:31 +06:00
Kirill Romanov
e2416b405a add support for inline keyboard buttons with callback_game field 2020-04-12 22:30:37 +03:00
14f012fbfa Update README.md 2020-04-09 01:24:55 +06:00
1ff55057f2 Merge pull request #78 from InsanusMokrassar/0.26.2
0.26.2
2020-04-08 16:48:00 +06:00
71b5e33dbc update common README 2020-04-08 15:28:03 +06:00
08d9d183f4 add filterCommandsWithArgs 2020-04-08 15:23:12 +06:00
7183634fd6 experimentally make source string available inside of text sources 2020-04-08 15:17:13 +06:00
cf9f270651 rename new getting updates extension to avoid JVM signature collisions 2020-04-08 14:56:56 +06:00
bd87938e9c fixes in UpdatesChatFilters 2020-04-08 14:51:26 +06:00
ba76eaeb90 update readmes 2020-04-08 14:34:55 +06:00
d8492ae168 fixes, new readme 2020-04-08 14:02:55 +06:00
0db85232d3 fixes in changelog 2020-04-08 13:20:48 +06:00
bcf2325be8 make new startGettingOfUpdates more useful 2020-04-08 13:19:19 +06:00
51174a13de added some of extensions in TelegramBotAPI-extensions-utils 2020-04-08 11:50:47 +06:00
dfc1fa4d7e refill of changelog 2020-04-08 11:11:31 +06:00
10a1d1cb38 add TelegramBotAPI-extensions-utils 2020-04-08 11:05:48 +06:00
6c39dc4d06 new startGettingOfUpdates extension 2020-04-08 10:44:44 +06:00
4877b8958e start 0.26.2 2020-04-08 10:37:05 +06:00
db9c460e66 Merge pull request #75 from InsanusMokrassar/0.26.1
0.26.1
2020-04-06 12:15:27 +06:00
2bd5d53b2a fill changelog 2020-04-06 12:11:14 +06:00
577436843d fixes 2020-04-06 12:09:59 +06:00
048aa93044 InvalidPhotoDimensionsException 2020-04-05 14:06:40 +06:00
4e49de0dd7 fix in hashtag 2020-04-04 12:12:12 +06:00
9dc5a7624d complete CHANGELOG 2020-04-03 14:26:32 +06:00
21a15db031 StorageFile improvement 2020-04-03 14:22:34 +06:00
a6aa4b8758 BotCommand checks 2020-04-01 10:08:44 +06:00
e85d5df03e started 0.26.1 2020-04-01 10:05:30 +06:00
6833640c48 Create write-good.yml 2020-03-31 19:13:48 +06:00
c22c1bb144 Merge pull request #74 from InsanusMokrassar/0.26.0
0.26.0
2020-03-31 11:45:47 +06:00
8293d6683c optimize imports 2020-03-31 11:41:58 +06:00
7e6e892c45 libraries updates 2020-03-31 11:31:24 +06:00
43ac09a79b fixes in startGettingUpdates 2020-03-31 11:28:48 +06:00
ee1f115d77 refill TelegramBotAPI-extensions-api 2020-03-31 11:11:37 +06:00
7d85b6fb88 update readme of telegram bot api 2020-03-31 11:00:22 +06:00
013944c5c9 real fix:) 2020-03-30 22:52:57 +06:00
55ed3e165b resolve compiling errors 2020-03-30 22:47:20 +06:00
9c0106d229 StickerSetAction -> StandardStickerSetAction 2020-03-30 22:31:54 +06:00
9cd2a6220c add setStickerSetThumb 2020-03-30 22:29:34 +06:00
033ec8f2da update version 2020-03-30 22:18:59 +06:00
274afe8efc addAnimatedStickerToSet 2020-03-30 22:12:31 +06:00
e60630b331 add StickerSet#thumb 2020-03-30 22:07:13 +06:00
f6692a22d1 create new animated sticker set 2020-03-30 22:03:59 +06:00
53257ff131 hotfix for setMyCommands request 2020-03-30 21:53:36 +06:00
ec70813e49 commands handling added 2020-03-30 21:52:00 +06:00
54589ed17b BotCommand 2020-03-30 21:40:36 +06:00
1d3736c44e add realisation of DiceContent#createResend 2020-03-30 21:37:30 +06:00
8ef7acab2d sendDice in extensions api 2020-03-30 21:33:17 +06:00
c3fca5c6c4 include dice in TelegramBotAPI 2020-03-30 21:30:22 +06:00
84d2c88032 started 0.25.2 2020-03-30 21:16:04 +06:00
b7ec2f2b86 Merge pull request #71 from InsanusMokrassar/0.25.1
0.25.1
2020-03-26 14:36:00 +06:00
97d6d3ad13 update kotlin 2020-03-26 14:27:17 +06:00
3dd428c7d9 fix of error inside of update utils for media groups 2020-03-26 14:26:44 +06:00
688de1053b started 0.25.1 2020-03-26 14:13:00 +06:00
a4fae36b22 hotfix for ExtendedUser 2020-03-22 22:57:01 +06:00
909a7fd26a add ExtendedUser 2020-03-22 22:37:26 +06:00
041232e260 FlowUpdatesFilter update 2020-03-22 17:21:01 +06:00
d4c409107a Merge pull request #69 from InsanusMokrassar/0.25.0
0.25.0
2020-03-22 16:50:50 +06:00
a0db95d929 suppressions nad compiler args 2020-03-22 16:41:48 +06:00
fb34b0bec1 optimize imports 2020-03-22 16:04:11 +06:00
d18863b7b3 TelegramDateTests now using strict json 2020-03-22 15:56:05 +06:00
c5c8a743e6 fixes in ChatIdentifierSerializer 2020-03-22 15:53:37 +06:00
89881a7349 removing of deprecations 2020-03-22 15:15:01 +06:00
865edf385f fix several todo 2020-03-22 14:07:00 +06:00
c85faa73c0 fixes 2020-03-22 13:53:42 +06:00
6b3f836096 new libraries versions adaptation 2020-03-22 13:37:01 +06:00
574ffbc44d update versions 2020-03-22 13:04:40 +06:00
a0120afb08 now bot username is not nullable 2020-03-22 12:56:52 +06:00
0b4b4950c2 started 0.25.0 2020-03-22 12:54:15 +06:00
b3391330a0 add setting up of socketTimeoutMillis inside of abstract request call factory for GetUpdates 2020-03-19 12:41:16 +06:00
518dee46b3 now startGettingOfUpdates have exceptions handler as argument 2020-03-19 12:03:40 +06:00
c9de4bc79e hotfix for installing of HttpTimeout inside of client only in case when it was not installed previously 2020-03-19 11:10:18 +06:00
badb138bc1 Merge pull request #67 from InsanusMokrassar/0.24.1
0.24.1
2020-03-18 23:02:01 +06:00
4b980d3f44 remove redundant import from webhooks 2020-03-18 22:58:23 +06:00
b11da02c8b refactor UpdatesUtils 2020-03-18 22:56:57 +06:00
71c0b688e8 fixes and improvements 2020-03-17 21:24:04 +06:00
d61aa8b50e getting updates refactoring 2020-03-17 20:24:31 +06:00
be64287c42 copypaste functions from TelegramBotAPI to TelegramBotAPI-extensions-api with adaptation of updates 2020-03-17 19:50:25 +06:00
e7027047cb abstracts for difference between sent and edited messages updates 2020-03-17 19:46:42 +06:00
944d15f326 new startGettingUpdates method 2020-03-17 17:20:42 +06:00
ba2c4cbb30 UpdatesFilter now is interface 2020-03-17 17:16:14 +06:00
244a1e5175 replacement of UpdatesPolling help functions 2020-03-17 16:59:28 +06:00
9c9a938d94 started 0.24.1 2020-03-17 16:47:59 +06:00
a2a403045b a little fix on README 2020-03-17 13:30:01 +06:00
6858af14f8 update info sections 2020-03-17 13:25:10 +06:00
779009c2a6 Merge pull request #66 from InsanusMokrassar/0.24.0
0.24.0
2020-02-25 21:01:46 +06:00
b22d8a5a25 ForwardFromChannelInfo#channelChat now is ChannelChat 2020-02-25 13:45:32 +06:00
54e3c43999 Most part of sending media messages functions was removed and replaced with their InputFile args analogs 2020-02-23 21:29:31 +06:00
f8a312acb3 removing of deprecations 2020-02-23 20:23:33 +06:00
a51e68be04 Update LICENSE 2020-02-19 22:29:53 +06:00
39dab0b970 Replace build badge and link it with travis 2020-02-19 20:12:54 +06:00
b42a6ca0cf Create .travis.yml 2020-02-19 20:08:15 +06:00
a34e67722b update telegrambotapi-extensions-api readme 2020-02-18 19:10:08 +06:00
c0e660c8d3 replace awesome badge 2020-02-17 15:35:33 +06:00
7cca12930c fixes and fill up 2020-02-17 15:33:28 +06:00
5da60b4ac2 update README 2020-02-17 15:25:08 +06:00
51dac40e45 now for extensions api system environment will be checked too 2020-02-17 11:49:48 +06:00
51fc33960a now group is common 2020-02-17 11:47:43 +06:00
b89b798eb6 remove redundant readme 2020-02-15 16:58:26 +06:00
a9326bb374 Merge pull request #65 from InsanusMokrassar/0.23.3
0.23.3
2020-02-15 16:57:29 +06:00
289 changed files with 5759 additions and 5486 deletions

7
.github/labeler.yml vendored Normal file
View File

@@ -0,0 +1,7 @@
api: "TelegramBotAPI-extensions-api/**"
utils: "TelegramBotAPI-extensions-utils/**"
core: "TelegramBotAPI/**" # currently not work
code: "**/*.kt"
gradle: "**/*.gradle"
markdown: "**/*.md"

13
.github/workflows/greetings.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Greetings
on: [pull_request, issues]
jobs:
greeting:
runs-on: ubuntu-latest
steps:
- uses: actions/first-interaction@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
issue-message: 'Welcome with your first issue'
pr-message: 'Welcome with your first PullRequest'

18
.github/workflows/label.yml vendored Normal file
View File

@@ -0,0 +1,18 @@
# This workflow will triage pull requests and apply a label based on the
# paths that are modified in the pull request.
#
# To use this workflow, you will need to set up a .github/labeler.yml
# file with configuration. For more information, see:
# https://github.com/actions/labeler/blob/master/README.md
name: "Pull Request Labeler"
on:
- pull_request
jobs:
triage:
runs-on: ubuntu-latest
steps:
- uses: actions/labeler@v2
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

1
.github/write-good.yml vendored Normal file
View File

@@ -0,0 +1 @@
spellchecker: true

10
.travis.yml Normal file
View File

@@ -0,0 +1,10 @@
language: java
install: true
os: linux
dist: trusty
jdk: oraclejdk8
script:
- ./gradlew build -s

View File

@@ -1,5 +1,337 @@
# TelegramBotAPI changelog
## 0.27.0
* `Common`:
* Versions updates:
* `Kotlin`: `1.3.71` -> `1.3.72`
* `Klock`: `1.10.3` -> `1.10.5`
* `TelegramBotAPI`:
* Typealias `LongSeconds` was added for correct explanation of seconds in `Long` primitive type
* Several new fields was added:
* `explanationField`
* `explanationEntitiesField`
* `openPeriodField`
* `closeDateField`
* Extension `List<TextPart>#justTextSources` was added for mapping of `List<TextPart>` to `List<TextSource>`
* Field `SendPoll#closeInfo` was added
* Range `openPeriodPollSecondsLimit` was added and used in all `SendPoll` requests for checking income data
* `SendQuizPoll` now able to use fields `caption` and `parseMode` for `explanation` functionality
* `quizPollExplanationLimit` was added for checking `QuizPoll` explanation size
* Field `TextLinkTextSource#url` was added
* Field `TextMentionTextSource#user` was added
* Sealed class `ScheduledCloseInfo` was added
* Class `ExactScheduledCloseInfo` was added for cases with `close_date`
* Class `ApproximateScheduledCloseInfo` was added for cases with `open_period`
* Field `Poll#scheduledCloseInfo` was added
* Sealed class `MultipleAnswersPoll` was added
* Class `RegularPoll` now extends `MultipleAnswersPoll`
* `Dice` class was replaced into new package
* Sealed class `DiceAnimationType` was added
* Field `Dice#animationType` was added as `emoji` API representation
* `SendDice` now receive `animationType` as second parameter
* For `List<TextSource>` was added several extensions:
* `toMarkdownCaptions`
* `toMarkdownTexts`
* `toMarkdownV2Captions`
* `toMarkdownV2Texts`
* `toHtmlCaptions`
* `toHtmlTexts`
* `TelegramBotAPI-extensions-api`:
* All `RequestsExecutor#sendDice` extensions now accept `DiceAnimationType?` as second parameter
* All `RequestsExecutor#sendRegularPoll` extensions now accept `ScheduledCloseInfo` fourth parameter
* All `RequestsExecutor#sendQuizPoll` extensions now accept additional parameters `caption: String` and
`parseMode: ParseMode` for `explanation` functionality and `closeInfo: ScheduledCloseInfo?` for autoclose poll
functionality
* `TelegramBotAPI-extensions-utils`:
* Several shortcuts for `ScheduledCloseInfo` was added:
* `closePollExactAt`
* `closePollExactAfter`
* `closePollAfter`
### 0.27.5
* `Common`:
* Versions:
* `Klock`: `1.11.1` -> `1.11.3`
* `TelegramotAPI`:
* Fix: for sending requests caption and text lengths limits were updated
* New variant of `row` was added
* `makeLinkToMessage` extensions has been deprecated (replaced into `TelegramBotAPI-extensions-utils`)
* Next things was deprecated and replaced into `TelegramBotAPI-extensions-utils`:
* All `String` formatting public extensions and functions
* All extensions like `CaptionedInput#toHtmlCaptions`
* All helper extensions for `List<BaseMessageUpdate>`
* All `RequestsExecutor#executeAsync` and `RequestsExecutor#executeUnsafe`
* `BotCommand` now more strictly check commands which passed to it
* Regex `BotCommandNameRegex` was added
* `TelegramBotAPI-extensions-api`:
* A lot of `RequesstExecutor#getChat` extensions was added for more explicit types showing
* New `RequesstExecutor#setMyCommands` extension was added
* New field `BotBuilder#ktorClientEngineFactory` introduced
* Field `BotBuilder#ktorClientEngine` now is deprecated
* `TelegramBotAPI-extensions-utils`:
* `safely` function was introduced. It is in `PreviewFeature` state currently
* `makeLinkToMessage` extensions has been added
* `makeLinkToAddStickerSet` function and its variations were added
* Next tools was added from `TelegramBotAPI`:
* All `String` formatting extensions and functions
* All extensions like `CaptionedInput#toHtmlCaptions`
* All helper extensions for `List<BaseMessageUpdate>`
* Several new extensions for `SentMediaGroupUpdate` were added:
* `SentMediaGroupUpdate#forwardInfo`
* `SentMediaGroupUpdate#replyTo`
* `SentMediaGroupUpdate#chat`
* `SentMediaGroupUpdate#mediaGroupId`
* Several `List<MediaGroupMessage>.createResend` extensions were added
* `RequestsExecutor#executeAsync` and `RequestsExecutor#executeUnsafe`
### 0.27.4
* `TelegramBotAPI-extensions-utils`:
* Several extensions for updates was added:
* `onlyBaseMessageUpdates`
* `onlySentMessageUpdates`
* `onlyEditMessageUpdates`
* `onlyMediaGroupsUpdates`
* `onlySentMediaGroupUpdates`
* `onlyEditMediaGroupUpdates`
* Renames in chat filters extensions:
* `filterBaseMessageUpdates` -> `filterBaseMessageUpdatesByChatId` and `filterBaseMessageUpdatesByChat`
* `filterSentMediaGroupUpdates` -> `filterSentMediaGroupUpdatesByChatId` and `filterSentMediaGroupUpdatesByChat`
### 0.27.3
* `TelegramBotAPI`:
* `UpdateDeserializationStrategy` is publicly available now
* All `setWebhook` extensions was marked as deprecated, renamed and replaced into `TelegramBotAPI-extensions-utils`
* Typealias `ExceptionHandler` was added - it will be used for `handleSafely`
* `SetWebhook` factories signatures was changed (backward compatibility was not broken)
* `executeUnsafe` now working differently
* Now it is possible to pass exceptions handler into `executeUnsafe`
* `BasketballDiceAnimationType` was added
* `UnknownDiceAnimationType` now is deprecated due to renaming - currently it is typealias for `CustomDiceAnimationType`
* `CustomDiceAnimationType` now is `data` class instead of common class
* `FlowsUpdatesFilter` will use size 64 by default for internal broadcast channels
* `TelegramBotAPI-extensions-api`:
* Long Polling extensions now are deprecated in this project. It was replaced into `TelegramBotAPI-extensions-utils`
* Several `telegramBot` functions was renamed into `telegramBotWithCustomClientConfig`
* Add one more `setWebhookInfo` realisation
* `TelegramBotAPI-extensions-utils`:
* Extension `toTelegramUpdate` was added
* Long Polling extensions were added
* Updates utils were added
* New extensions `startListenWebhooks`, `setWebhookInfoAndStartListenWebhooks` and `includeWebhookHandlingInRoute` was added
* New extension `CoroutineScope#updateHandlerWithMediaGroupsAdaptation` was added
* New extension `flowsUpdatesFilter` was added
* `TelegramBotAPI-all`:
* Project was created
### 0.27.2
* `Common`:
* Versions:
* Coroutines: `1.3.5` -> `1.3.6`
* Klock: `1.10.5` -> `1.11.1`
* `TelegramBotAPI`:
* Expected class `MimeType` was added
* Field `MimeTyped#mimeType` now typed by `MimeType` instead of `String`
* `MediaGroupMemberInputMedia` children now can be deserialized (but only those ones who are declared inside library)
* `TelegramBotAPI-extensions-utils`:
* Chat events splitters added:
* Extension `Flow<ChatEventMessage>#onlyChannelEvents` was added
* Extension `Flow<ChatEventMessage>#onlyGroupEvents` was added
* Extension `Flow<ChatEventMessage>#onlySupergroupEvents` was added
### 0.27.1
* `TelegramBotAPI`:
* Interface `Explained` and subsinterfaces `ExplainedInput` and `ExplainedOutput` was added
* Class `QuizPoll` now implement `ExplainedInput`
* In `QuizPoll#caption` and `QuizPoll#captionEntities` are deprecated now
* Class `SendQuizPoll` now implement `ExplainedOutput`
* In `SendQuizPoll#caption` is deprecated now
* `explanationLimit` range was added as future replacement of `quizPollExplanationLimit`
* `quizPollExplanationLimit` now is deprecated
* Extensions `toMarkdownExplanations`, `toMarkdownV2Explanations` and `toHtmlExplanations` was added
* Typealias `FullTextSourcesList` was added
* All extensions `fullEntitiesList` now return `FullTextSourcesList`
* All extensions of `List<TextSource>` now are extensions for `FullTextSourcesList`
* `TelegramBotAPI-extensions-api`:
* `sendQuizPoll` now is using `explanation` parameter instead of `caption`
## 0.26.0
* `Common`:
* Versions updates:
* `Klock`: `1.10.0` -> `1.10.3`
* `TelegramBotAPI`:
* Request `SendDice` was added (calling [sendDice](https://core.telegram.org/bots/api#senddice))
* Class `Dice` was added (type [dice](https://core.telegram.org/bots/api#dice))
* Class `DiceContent` was added (for including it in [message](https://core.telegram.org/bots/api#message) object)
* `BotCommand` was added
* `GetMyCommands` request was added
* `SetMyCommands` request was added
* `GetMe` now is object instead of class
* `GetMe` was replaced into package `com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe`
* `CreateNewStickerSet` renamed to `CreateStaticNewStickerSet`
* `CreateNewAnimatedStickerSet` request was added (it handle work with `tgs_sticker`)
* `StickerSet#thumb` was added
* `AddStickerToSet` renamed to `AddStaticStickerToSet`
* `AddAnimatedStickerToSet` request was added
* `SetStickerSetThumb` request was added
* Most of sticker actions now implements `StandardStickerSetAction` instead of `StickerSetAction`
* `getUpdatesLimit` was added to be ensure in get updates limit
* `GetUpdates` now will check count of requesting updates and throw exception if it is not in range `1 .. 100`
* `GetUpdates#limit` now is not nullable and by default set up to 100
* `TelegramBotAPI-extensions-api`:
* Extensions `sendDice` was added
* Extension `getMyCommands` request was added
* Extension `setMyCommands` request was added
* Extension `getMe` was replaced into package `com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.GetMeKt.getMe`
* **All extensions `createNewStickerSet` was renamed to `createNewStaticStickerSet`**
* Extensions `createNewAnimatedStickerSet` was added
* **All extensions `addStickerToSet` was renamed to `addStaticStickerToSet`**
* Extensions `addAnimatedStickerToSet` was added
* Extensions `setStickerSetThumb` was added
* Extension `startGettingUpdates` now will drop `SentMediaGroupUpdate` in case if it is the last in updates group
and size of retrieved updates is equal to 100 (max count of retrieved updates)
* Extensions `getUpdates` now will receive only not nullable `limit` parameter
### 0.26.4
* `TelegramBotAPI`:
* Now any getting of updates will return `UnknownUpdateType` when inside of deserialization will be
`SerializationException` or `NotImplemented` error
* `CallbackGame` currently is an object
* It is possible to use `CallbackGame` for now
* `CallbackGameInlineKeyboardButton` now will not accept `callbackGame` as income object
* Now it is possible to pass exception handler in webhook
### 0.26.3
* `TelegramBotAPI`:
* `CallbackGameInlineKeyboardButton` was added
([Issue-79](https://github.com/InsanusMokrassar/TelegramBotAPI/issues/79),
[PR-80](https://github.com/InsanusMokrassar/TelegramBotAPI/pull/80))
* `UnknownInlineKeyboardButton` was added. It is unavailable for creating, but you can receive it, for example, in
`InlineQueryResult`
* `Update` now will be created even if was `SerializationException` inside of creating the update instance - in this
case will be created `UnknownUpdateType`
* `UnknownUpdateType$rawJson` value now is included (`JsonElement`)
* **EXPERIMENTALLY** `BaseEditMessageUpdate#data` now is `CommonMessage<*>`
* Suspend inline function `handleSafely` was added
* `KtorRequestsExecutor` now use `handleSafely` instead of `try` with `supervisorScope`
* `UpdatesPolling` now use `handleSafely` instead of `try` with `supervisorScope`
### 0.26.2
* `TelegramBotAPI`:
* Now `EditMediaGroupUpdate` also extends `BaseEditMessageUpdate`
* **EXPERIMENTALLY** Now all `TextSource` realisations will contain `source` field as a property inside of them
* `TelegramBotAPI-extensions-api`:
* `startGettingFlowsUpdates` extension which do not require filter (but return a new one) was added
* `TelegramBotAPI-extensions-utils`:
* Subproject was added
* `filterBaseMessageUpdates`, `filterSentMediaGroupUpdates` and `filterEditMediaGroupUpdates` extensions was added
* `filterCommandsWithArgs`, `filterExactCommands` and `filterCommandsInsideTextMessages` extensions was added
* `asContentMessagesFlow`, `asChatEventsFlow` and `asUnknownMessagesFlow` extensions was added
* `withContentType` extension was added
* `onlyAnimationContentMessages` extension was added
* `onlyAudioContentMessages` extension was added
* `onlyContactContentMessages` extension was added
* `onlyDiceContentMessages` extension was added
* `onlyDocumentContentMessages` extension was added
* `onlyGameContentMessages` extension was added
* `onlyInvoiceContentMessages` extension was added
* `onlyLocationContentMessages` extension was added
* `onlyPhotoContentMessages` extension was added
* `onlyPollContentMessages` extension was added
* `onlyStickerContentMessages` extension was added
* `onlyTextContentMessages` extension was added
* `onlyVenueContentMessages` extension was added
* `onlyVideoContentMessages` extension was added
* `onlyVideoNoteContentMessages` extension was added
* `onlyVoiceContentMessages` extension was added
### 0.26.1
* `TelegramBotAPI`:
* `BotCommand` now will check and throw error in case when command or description lengths is/are incorrect
* `StorageFile` now is common for all platforms
* JavaScript realization was removed due to its redundancy
* JVM realization was replaced with `fun` factory
* `StorageFile` now able to accept any factory of `Input`
* `StorageFileInfo` was added to avoid strange collisions with throws in `StorageFile`
* Fixes issue with `hashTag` for markdown
* `InvalidPhotoDimensionsException` was added for cases when `PHOTO_INVALID_DIMENSION` answer received
* Other fixes
## 0.25.0
* Common:
* Versions updates:
* `Kotlin`: `1.3.61` -> `1.3.70`
* `Kotlin coroutines`: `1.3.3` -> `1.3.5`
* `Kotlin serialization`: `0.14.0` -> `0.20.0`
* `Ktor`: `1.3.1` -> `1.3.2`
* `Klock`: `1.8.7` -> `1.10.0`
* `UUID`: `0.0.7` -> `0.1.0`
* `TelegramBotAPI`:
* `Bot` implementations (as and `Bot` itself) now have not nullable `username`
* `File#toInputFile` extension now will throw error when file does not exists
* `InlineKeyboardMarkup` will check that `PayInlineKeyboardButton` is the first in case if it is exists in
`keyboard`
* `makeLinkToMessage` now is not `PreviewFeature`
* All deprecations was removed
* `RequestException` now extends `io.ktor.utils.io.errors.IOException` instead of `kotlinx.io.IOException`
* `Any#toJson` now is NOT `inline`
* `FlowsUpdatesFilter` now as marked my annotation `FlowPreview`
* `PathedFile#fullUrl` now is not `inline` function
* `SimpleRequest#json` now is not `inline` and `internal` function
* `FlowsUpdatesFilter` now have two additional flows: `pollAnswerFlow`, `unknownUpdateTypeFlow`
* `ExtendedUser` (`typealias`) was added as a `PreviewFeature`
### 0.25.1
* Update kotlin: `1.3.70` -> `1.3.71`
* Fix of error inside of update utils for media groups
## 0.24.0
* `TelegramBotAPI`:
* All suspend functions for `RequestsExecutor` was removed (due to replacement into
[TelegramBotAPI extensions project](TelegramBotAPI-extensions-api/README.md))
* `ForwardFromChannelInfo#channelChat` now is `ChannelChat` instead of `Chat`
* `TelegramBotAPI-extensions-api`:
* Most part of sending media messages functions was removed and replaced with their `InputFile` args analogs
### 0.24.1
* `TelegramBotAPI`:
* `UpdateReceiver` was replaced to the package `com.github.insanusmokrassar.TelegramBotAPI.updateshandlers`
* All functions inside `com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.UpdatesPolling` are deprecated
and will be removed in some soon versions. Their replacement are able inside `TelegramBotAPI-extensions-api`
* `UpdatesFilter` is interface for now
* Previous `UpdatesFilter` class was renamed to `SimpleUpdatesFilter` and for backward compatibility was added
builder function `UpdatesFilter`, which will be removed in near releases
* `FlowsUpdatesFilter` now implements `UpdatesFilter`
* `BaseSentMessageUpdate` and `BaseEditMessageUpdate` interfaces was added
* `EditChannelPostUpdate` now is implementing `BaseEditMessageUpdate` interface
* `EditMessageUpdate` now is implementing `BaseEditMessageUpdate` interface
* `ChannelPostUpdate` now is implementing `BaseSentMessageUpdate` interface
* `MessageUpdate` now is implementing `BaseSentMessageUpdate` interface
* `UpdatesPoller` and all its usages, childs and childs usages now are deprecated
* `GetUpdates#timeout` type now is `Seconds` (in fact it is `Int` as previously)
* `KtorRequestsExecutor` now is using a copy of incoming `HttpClient` object and install `HttpTimeout` feature
* `AbstractRequestCallFactory` now setting up a custom delay in case if request is `GetUpdates`
* `TelegramBotAPI-extensions-api`:
* All functions from `com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.UpdatesPolling` now available
in package `com.github.insanusmokrassar.TelegramBotAPI.extensions.api.updates.UpdatesPolling`
* Now new method of getting updates available: `startGettingUpdates` with `UpdatesFilter` as incoming first
parameter
* `startGettingUpdates` with `receiver` and `allowedUpdates` parameters now will handle updates by itself
## 0.23.0 TelegramBotAPI 4.6
* `Poll` now is sealed class

View File

@@ -178,7 +178,7 @@
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "{}"
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
@@ -186,7 +186,7 @@
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright 2018 Insanus
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

337
README.md
View File

@@ -1,250 +1,127 @@
# TelegramBotAPI
[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI)
[![Build Status](https://jenkins.insanusmokrassar.com/buildStatus/icon?job=TelegramBotAPI_master__publishing)](https://jenkins.insanusmokrassar.com/job/TelegramBotAPI_master__publishing/)
| Common info | [![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin) [![Chat in Telegram](badges/chat.svg)](https://teleg.one/InMoTelegramBotAPI) [![Build Status](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI.svg?branch=master)](https://travis-ci.com/InsanusMokrassar/TelegramBotAPI) [![KDocs](badges/kdocs.svg)](https://tgbotapi.inmo.dev/docs/index.html) |
| -------------------------------------:|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| TelegramBotAPI status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI) |
| TelegramBotAPI Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api) |
| TelegramBotAPI Util Extensions status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils) |
| TelegramBotAPI All status | [![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-all/images/download.svg)](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-all/_latestVersion) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-all/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-all) |
[![Chat in Telegram](badges/chat.svg)](https://t.me/InMoTelegramBotAPI)
It is a complex of libraries for working with `TelegramBotAPI` in type-safe and strict way as much as it possible. In
the list of this complex currently next projects:
* [TelegramBotAPI](TelegramBotAPI/README.md) - core of library. In fact it is independent library and can be used alone
without any additional library
* [TelegramBotAPI Extensions](TelegramBotAPI-extensions-api/README.md) - contains extensions (mostly for
`RequestsExecutor`), which allows to use the core library in more pleasant way
* [TelegramBotAPI Util Extensions](TelegramBotAPI-extensions-utils/README.md) - contains extensions for more comfortable
work with commands, updates and other different things
* [TelegramBotAPI All](TelegramBotAPI-all/README.md) - concentration of all previously mentioned libraries
## What is it?
Library for Object-Oriented and type-safe work with Telegram Bot API. Most part of some specific solves or unuseful
Most part of some specific solves or unuseful
moments are describing by official [Telegram Bot API](https://core.telegram.org/bots/api).
## Compatibility
## JavaScript notes
This version compatible with [23th of January 2020 update of TelegramBotAPI (version 4.6)](https://core.telegram.org/bots/api#january-23-2020).
There is Telegram Passport API exception of implemented functionality, which was presented in
[August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented
as soon as possible. All APIs that are not included are presented
[wiki](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Not-included-API).
In case if you are want to use this library inside of browser, you will need additional settings (thanks for help to [Alexander Nozik](https://research.jetbrains.org/researchers/altavir)):
## How to implement library?
Common ways to implement this library are presented here. In some cases it will require additional steps
like inserting of additional libraries (like `kotlin stdlib`). In the examples will be used variable
`telegrambotapi.version`, which must be set up by developer. Available versions are presented on
[bintray](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI), next version is last published:
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion)
Currently, last versions of library can be available from the Maven repository with errors (for the reason difficult in publishing
of signed artifacts in Bintray). You can:
* Use earlier version (available version you can find
[here](https://mvnrepository.com/artifact/com.github.insanusmokrassar/TelegramBotAPI))
* Add `jCenter` repository in build config
### TelegramBotAPI
Contains core and most required things, like types, requests and `KtorRequestsExecutor`.
#### Maven
Dependency config presented here:
```xml
<dependency>
<groupId>com.github.insanusmokrassar</groupId>
<artifactId>TelegramBotAPI</artifactId>
<version>${telegrambotapi.version}</version>
</dependency>
```
#### Gradle
To use last versions you will need to add one line in repositories block of your `build.gradle`:
`jcenter()` or `mavenCentral()`
And add next line to your dependencies block:
```groovy
implementation "com.github.insanusmokrassar:TelegramBotAPI:$telegrambotapi_version"
```
or for old gradle:
```groovy
compile "com.github.insanusmokrassar:TelegramBotAPI:$telegrambotapi_version"
```
### API extensions
Contains extensions for `RequestsExecutor` which usually more obvious than original ones in `TelegramBotAPI` and more
useful.
#### Maven
Dependency config presented here:
```xml
<dependency>
<groupId>com.github.insanusmokrassar</groupId>
<artifactId>TelegramBotAPI-extensions-api</artifactId>
<version>${telegrambotapi.version}</version>
</dependency>
```
#### Gradle
To use last versions you will need to add one line in repositories block of your `build.gradle`:
`jcenter()` or `mavenCentral()`
And add next line to your dependencies block:
```groovy
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$telegrambotapi_version"
```
or for old gradle:
```groovy
compile "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$telegrambotapi_version"
```
## How to work with library?
For now, this library have no some API god-object. Instead of this, this library has several
important objects:
* [RequestsExecutor](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/RequestsExecutor.kt)
* [Requests](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests)
* [Types](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types)
### Types
Types declare different objects representation. For example, `Chat` for now represented as
interface and has several realisations:
* `PrivateChat`
* `GroupChat`
* `SupergroupChat`
* `ChannelChat`
Instead of common garbage with all information as in original [Chat](https://core.telegram.org/bots/api#chat),
here it was separated for more obvious difference between chats types and their possible content.
The same principle work with a lot of others things in this Telegram bot API.
### Requests
Requests usually are very simple objects, but some of them are using their own
build factories. For example, the next code show, how to get information about bot:
```kotlin
val requestsExecutor: RequestsExecutor = ...
requestsExecutor.execute(GetMe())
```
Or you can use new syntax (available by implementing of project [API extensions](#API-extensions):
```kotlin
val bot: RequestsExecutor = ...
bot.getMe()
```
The result type of [GetMe (and getMe extension)](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests/GetMe.kt)
request is
[ExtendedBot](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types/User.kt).
### RequestsExecutor
It is base object which can be used to execute requests in API. For now by default included Ktor
realisation of `RequestsExecutor`, but it is possible, that in future it will be extracted in separated
project. How to create `RequestsExecutor`:
```kotlin
val requestsExecutor = KtorRequestsExecutor(
TelegramAPIUrlsKeeper(TOKEN)
)
```
Here:
* `KtorRequestsExecutor` - default realisation with [ktor](https://ktor.io)
* `TelegramAPIUrlsKeeper` - special keeper, which you can save and use for getting files full urls (`resolveFileURL`
extension inside of `PathedFile.kt`)
* `TOKEN` is just a token of bot which was retrieved according to
[instruction](https://core.telegram.org/bots#3-how-do-i-create-a-bot).
By default, for JVM there is implemented `CIO` client engine, but there is not server engine. Both can be changed like
here:
<details>
<summary>Gradle build script help</summary>
```groovy
dependencies {
// ...
implementation "io.ktor:ktor-server-cio:$ktor_version" // for implementing of server engine
implementation "io.ktor:ktor-client-okhttp:$ktor_version" // for implementing of additional client engine
// ...
/* ... */
implementation "com.github.insanusmokrassar:TelegramBotAPI:$tgbot_api_version"
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$tgbot_api_version" // optional
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$tgbot_api_version" // optional
/* Block of dependencies for correct building in browser */
implementation(npm("fs"))
implementation(npm("bufferutil"))
implementation(npm("utf-8-validate"))
implementation(npm("abort-controller"))
implementation(npm("text-encoding"))
}
/* ... */
kotlin {
target {
browser {
/* Block for fix of exception in absence of some functionality, https://github.com/ktorio/ktor/issues/1339 */
dceTask {
dceOptions {
keep("ktor-ktor-io.\$\$importsForInline\$\$.ktor-ktor-io.io.ktor.utils.io")
}
}
}
}
}
```
You can avoid using of `server` dependency in case if you will not use `Webhook`s. In this case,
dependencies list will be simplify:
</details>
## Ok, where should I start?
In most cases, the most simple way will be to implement [TelegramBotAPI All](TelegramBotAPI-all/README.md) - it contains
all necessary tools for comfort usage of this library. If you want to exclude some libraries, you can implement just
[TelegramBotAPI API Extensions](TelegramBotAPI-extensions-api/README.md),
[TelegramBotAPI Util Extensions](TelegramBotAPI-extensions-utils/README.md) or even
[TelegramBotAPI](TelegramBotAPI/README.md).
If you want to dive deeper in the core of library or develop something for it - welcome to learn more from
[TelegramBotAPI](TelegramBotAPI/README.md) and our [Telegram Chat](https://teleg.one/InMoTelegramBotAPIChat).
Anyway, all libraries are very typical inside of them. Examples:
* In `TelegramBotAPI` common request look like `requestsExecutor.execute(SomeRequest())`
* `TelegramBotAPI-extensions-api` typical syntax look like `requestsExecutor.someRequest()` (in most cases it would be
better to use `bot` name instead of `requestsExecutor`)
* `TelegramBotAPI-extensions-utils` will look like `filter.filterBaseMessageUpdates(chatId).filterExactCommands(Regex("^.*$"))...`
## Build instruction
If you want to build this project or to contribute, there are several recommendations:
### Build
In case if you want to just build project, run next command:
```bash
./gradlew clean build
```
On windows:
```
gradlew.bat clean build
```
### Publishing for work with your version locally
In case, if you want to work in your other projects using your modification (or some state) of this library,
you can use next code:
```bash
./gradlew clean build publishToMavenLocal
```
On windows:
```
gradlew.bat clean build publishToMavenLocal
```
But you must remember, that in this case your local maven repo must be the first one from
your project retrieving libraries:
```groovy
dependencies {
// ...
implementation "io.ktor:ktor-client-okhttp:$ktor_version" // for implementing of additional client engine
// ...
repositories {
mavenLocal() // that must be the first one
jcenter()
mavenCentral()
}
```
Here was used `okhttp` realisation of client, but there are several others engines for Ktor. More information
available on ktor.io site for [client](https://ktor.io/clients/http-client/engines.html) and [server](https://ktor.io/quickstart/artifacts.html)
engines.
## Getting updates
In this library currently realised two ways to get updates from telegram:
* Polling - in this case bot will request updates from time to time (you can set up delay between requests)
* Webhook via reverse proxy or something like this
### Updates filters
Currently webhook method contains `UpdatesFilter` as necessary argument for getting updates.
`UpdatesFilter` will sort updates and throw their into different callbacks. Currently supporting
separate getting updates for media groups - they are accumulating with debounce in one second
(for being sure that all objects of media group was received).
Updates polling also support `UpdatesFilter` but it is not required to use it and you can get updates directly
in `UpdateReceiver`, which you will provide to `startGettingOfUpdates` method
### Webhook set up
If you wish to use webhook method, you will need:
* White IP - your IP address or host, which available for calling. [TelegramBotAPI](https://core.telegram.org/bots/api#setwebhook)
recommend to use some unique address for each bot which you are using
* SSL certificate. Usually you can obtain the certificate using your domain provider, [Let'sEncrypt](https://letsencrypt.org/) or [create it](https://core.telegram.org/bots/self-signed)
* Nginx or something like this
Template for Nginx server config you can find in [this gist](https://gist.github.com/InsanusMokrassar/fcc6e09cebd07e46e8f0fdec234750c4#file-nginxssl-conf).
For webhook you can provide `File` with public part of certificate, `URL` where bot will be available and inner `PORT` which
will be used to start receiving of updates. Actually, you can skip passing of `File` when you have something like
nginx for proxy forwarding.
In case of using `nginx` with reverse-proxy config, setting up of Webhook will look like:
```kotlin
requestsExecutor.setWebhook(
WEBHOOK_URL,
INTERNAL_PORT,
filter,
ENGINE_FACTORY
)
```
Here:
* `WEBHOOK_URL` - the url which will be used by Telegram system to send updates
* `INTERNAL_PORT` - the port which will be used in bot for listening of updates
* `filter` - instance of [UpdatesFilter](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/updateshandlers/UpdatesFilter.kt),
which will be used to filter incoming updates
* `ENGINE_FACTORY` - used factory name, for example, `CIO` in case of usage `io.ktor:ktor-server-cio` as server engine
Besides, for your own version you can change variable `library_version` in the file [gradle.properties](./gradle.properties).

View File

@@ -0,0 +1,16 @@
# TelegramBotAPI-all
Concentration of all TelegramBotAPI libraries:
* [TelegramBotAPI](../TelegramBotAPI/README.md)
* [TelegramBotAPI Extensions](../TelegramBotAPI-extensions-api/README.md)
* [TelegramBotAPI Util Extensions](../TelegramBotAPI-extensions-utils/README.md)
## Implementation
```groovy
dependencies {
// ...
implementation "com.github.insanusmokrassar:TelegramBotAPI-all:tgBotAPIVersion"
}
```

View File

@@ -0,0 +1,52 @@
buildscript {
repositories {
mavenLocal()
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
}
project.version = "$library_version"
project.group = "$library_group"
apply from: "publish.gradle"
repositories {
mavenLocal()
jcenter()
mavenCentral()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
kotlin {
jvm()
js()
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:TelegramBotAPI:$library_version"
api "${project.group}:TelegramBotAPI-extensions-api:$library_version"
api "${project.group}:TelegramBotAPI-extensions-utils:$library_version"
} else {
api project(":TelegramBotAPI")
api project(":TelegramBotAPI-extensions-api")
api project(":TelegramBotAPI-extensions-utils")
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "This project just include all subproject of TelegramBotAPI"
name = "Telegram Bot API All"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-all"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -0,0 +1 @@
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API All","description":"This project just include all subproject of TelegramBotAPI","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-all","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}

View File

@@ -0,0 +1,55 @@
apply plugin: 'com.jfrog.bintray'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
pkg {
repo = "StandardRepository"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
if (it.name.contains('kotlinMultiplatform')) {
null
} else {
it.name
}
} - null
}
bintrayUpload.dependsOn publishToMavenLocal

View File

@@ -0,0 +1,129 @@
# TelegramBotAPI extensions
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-api)
## What is it?
It is wrapper library for [TelegramBotAPI](../TelegramBotAPI/README.md). Here you can find extensions for
`RequestsExecutor`, which are more look like Telegram Bot API requests and in the same time have more obvious signatures
to help understand some restrictions in Telegram system.
## Compatibility
This library always compatible with original `TelegramBotAPI` library version
## How to implement library?
Common ways to implement this library are presented here. In some cases it will require additional steps
like inserting of additional libraries (like `kotlin stdlib`). In the examples will be used variable
`telegrambotapi-extensions-api.version`, which must be set up by developer. Available versions are presented on
[bintray](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api), next version is last published:
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-api/_latestVersion)
### Maven
Dependency config presented here:
```xml
<dependency>
<groupId>com.github.insanusmokrassar</groupId>
<artifactId>TelegramBotAPI-extensions-api</artifactId>
<version>${telegrambotapi-extensions-api.version}</version>
</dependency>
```
### Gradle
To use last versions you will need to add one line in repositories block of your `build.gradle`:
`jcenter()` or `mavenCentral()`
And add next line to your dependencies block:
```groovy
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$telegrambotapi_extensions_api_version"
```
or for old gradle:
```groovy
compile "com.github.insanusmokrassar:TelegramBotAPI-extensions-api:$telegrambotapi_extensions_api_version"
```
## Example of usage and comparison with `TelegramBotAPI`
Here presented review table for comparison of api from original [TelegramBotAPI](../TelegramBotAPI/README.md#Requests)
and extensions-api library. First of all, this library allow to create bot instance in a new way:
```kotlin
val bot = telegramBot("IT IS YOUR TOKEN")
```
There are a lot of signature for this. For example, you can create bot with next code:
```kotlin
val bot = telegramBot("IT IS YOUR TOKEN") {
proxy = ProxyBuilder.socks("127.0.0.1", 1080)
}
```
In all examples supposed that you have created bot.
| TelegramBotAPI | TelegramBotAPI-extensions-api |
|----------------|-------------------------------|
| bot.execute(GetMe) | bot.getMe() |
| bot.execute(SendTextMessage(someChatId, text)) | bot.sendTextMessage(chat, text) |
## Updates
**Currently, these paragraphs almost outdated due to the fact that extensions for listening of updates and webhooks were
replaced into `TelegramBotAPI-extensions-utils`. But, most part of information below is correct with small fixes and
adding of `TelegramBotAPI-extensions-utils` dependency.**
Usually, it is more comfortable to use filter object to get separated types of updates:
```kotlin
val filter = FlowsUpdatesFilter(100)
```
In this case you will be able:
* Separate types of incoming updates (even media groups)
* Simplify launch of getting updates:
```kotlin
bot.startGettingOfUpdates(
filter,
scope = CoroutineScope(Dispatchers.Default)
)
```
* Use `filter` flows to comfortable filter, map and do other operations with the whole
getting updates process:
```kotlin
filter.messageFlow.mapNotNull {
it.data as? ContentMessage<*>
}.onEach {
println(it)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
```
### Alternative way
There is an alternative way to get updates. In fact it is almost the same, but could be more useful for some cases:
```kotlin
val filter = bot.startGettingOfUpdates(
scope = CoroutineScope(Dispatchers.Default)
) { // Here as reveiver will be FlowsUpdatesFilter
messageFlow.mapNotNull {
it.data as? ContentMessage<*>
}.onEach {
println(it)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
}
```

View File

@@ -18,7 +18,7 @@ plugins {
}
project.version = "$library_version"
project.group = "com.github.insanusmokrassar"
project.group = "$library_group"
apply from: "publish.gradle"
@@ -37,10 +37,10 @@ kotlin {
commonMain {
dependencies {
implementation kotlin('stdlib')
if (project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") {
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:TelegramBotAPI:$library_version"
} else {
implementation project(":TelegramBotAPI")
api project(":TelegramBotAPI")
}
}
}

View File

@@ -20,37 +20,33 @@ publishing {
publications.all {
artifact javadocsJar
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
pom {
description = "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
name = "Telegram Bot API Extensions for API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api"
description "API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference"
name "Telegram Bot API Extensions for API"
url "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
scm {
developerConnection "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
developers {
developer {
id "InsanusMokrassar"
name "Ovsiannikov Aleksei"
email "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name "Apache Software License 2.0"
url "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}

View File

@@ -1 +1 @@
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Extensions for API","description":"API extensions which provide work with RequestsExecutor of TelegramBotAPI almost like it is described in original Telegram Bot API reference","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-api","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}

View File

@@ -0,0 +1,54 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.*
/**
* @param proxy Standard ktor [ProxyConfig]
* @param ktorClientEngine Engine like [io.ktor.client.engine.cio.CIO]
* @param ktorClientConfig Config block for preconfiguring of bot [HttpClient]
*/
data class BotBuilder internal constructor(
var proxy: ProxyConfig? = null,
@Deprecated("ktorClientEngineFactory parameter will be used preferable. In future this parameter will be removed")
var ktorClientEngine: HttpClientEngine? = null,
var ktorClientEngineFactory: HttpClientEngineFactory<out HttpClientEngineConfig>? = null,
var ktorClientConfig: (HttpClientConfig<*>.() -> Unit) ? = null
) {
internal fun createHttpClient(): HttpClient = ktorClientEngineFactory ?.let {
HttpClient(
it.create {
this@create.proxy = this@BotBuilder.proxy ?: this@create.proxy
}
) {
ktorClientConfig ?.let { it() }
}
} ?: ktorClientEngine ?.let { engine ->
HttpClient(engine) {
ktorClientConfig ?.let { it() }
engine {
this@engine.proxy = this@BotBuilder.proxy ?: this@engine.proxy
}
}
} ?: HttpClient {
ktorClientConfig ?.let { it() }
engine {
this@engine.proxy = this@BotBuilder.proxy ?: this@engine.proxy
}
}
}
/**
* @return Created by [telegramBotWithCustomClientConfig] function [RequestsExecutor]. This executor will be preconfigured using [token] and
* [block]
*/
fun telegramBot(
token: String,
block: BotBuilder.() -> Unit
): RequestsExecutor = telegramBot(
TelegramAPIUrlsKeeper(token),
BotBuilder().apply(block).createHttpClient()
)

View File

@@ -0,0 +1,76 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorRequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
import io.ktor.client.HttpClient
import io.ktor.client.HttpClientConfig
import io.ktor.client.engine.HttpClientEngine
/**
* Allows to create bot using bot [urlsKeeper] and already prepared [client]
*/
fun telegramBot(
urlsKeeper: TelegramAPIUrlsKeeper,
client: HttpClient
): RequestsExecutor = KtorRequestsExecutor(
urlsKeeper,
client
)
/**
* Allows to create bot using bot [urlsKeeper] and specify [HttpClientEngine] by passing [clientEngine] param and optionally
* configure [HttpClient] using [clientConfig]
*/
fun telegramBotWithCustomClientConfig(
urlsKeeper: TelegramAPIUrlsKeeper,
clientEngine: HttpClientEngine,
clientConfig: HttpClientConfig<*>.() -> Unit = {}
): RequestsExecutor = telegramBot(
urlsKeeper,
HttpClient(clientEngine, clientConfig)
)
/**
* Allows to create bot using bot [urlsKeeper] and optionally configure [HttpClient] using [clientConfig]
*/
fun telegramBotWithCustomClientConfig(
urlsKeeper: TelegramAPIUrlsKeeper,
clientConfig: HttpClientConfig<*>.() -> Unit = {}
): RequestsExecutor = telegramBot(
urlsKeeper,
HttpClient(clientConfig)
)
/**
* Allows to create bot using bot [token]
*/
fun telegramBot(
token: String
): RequestsExecutor = telegramBotWithCustomClientConfig(TelegramAPIUrlsKeeper(token))
/**
* Allows to create bot using bot [token] and already prepared [client]
*/
fun telegramBot(
token: String,
client: HttpClient
): RequestsExecutor = telegramBot(TelegramAPIUrlsKeeper(token), client)
/**
* Allows to create bot using bot [token] and configure [HttpClient] using [clientConfig]
*/
fun telegramBotWithCustomClientConfig(
token: String,
clientConfig: HttpClientConfig<*>.() -> Unit
): RequestsExecutor = telegramBotWithCustomClientConfig(TelegramAPIUrlsKeeper(token), clientConfig)
/**
* Allows to create bot using bot [token] and specify [HttpClientEngine] by passing [clientEngine] param and optionally
* configure [HttpClient] using [clientConfig]
*/
fun telegramBot(
token: String,
clientEngine: HttpClientEngine,
clientConfig: HttpClientConfig<*>.() -> Unit = {}
): RequestsExecutor = telegramBotWithCustomClientConfig(TelegramAPIUrlsKeeper(token), clientEngine, clientConfig)

View File

@@ -1,6 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetMe
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.getMe
suspend fun RequestsExecutor.getMe() = execute(GetMe())
@Deprecated(
"Replaced",
ReplaceWith("getMe", "com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot.GetMeKt.getMe")
)
suspend fun RequestsExecutor.getMe() = getMe()

View File

@@ -2,14 +2,13 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.ALL_UPDATES_LIST
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
suspend fun RequestsExecutor.getUpdates(
offset: UpdateIdentifier? = null,
limit: Int? = null,
timeout: Int? = null,
limit: Int = getUpdatesLimit.last,
timeout: Seconds? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST
) = execute(
GetUpdates(
@@ -19,8 +18,8 @@ suspend fun RequestsExecutor.getUpdates(
suspend fun RequestsExecutor.getUpdates(
lastUpdate: Update,
limit: Int? = null,
timeout: Int? = null,
limit: Int = getUpdatesLimit.last,
timeout: Seconds? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST
) = getUpdates(
lastUpdate.updateId + 1, limit, timeout, allowed_updates

View File

@@ -0,0 +1,70 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils
import com.github.insanusmokrassar.TelegramBotAPI.types.MediaGroupIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
internal fun Update.lastUpdateIdentifier(): UpdateIdentifier {
return if (this is SentMediaGroupUpdate) {
origins.last().updateId
} else {
updateId
}
}
internal fun List<Update>.lastUpdateIdentifier(): UpdateIdentifier? {
return maxBy { it.updateId } ?.lastUpdateIdentifier()
}
internal fun List<Update>.convertWithMediaGroupUpdates(): List<Update> {
val resultUpdates = mutableListOf<Update>()
val mediaGroups = mutableMapOf<MediaGroupIdentifier, MutableList<BaseSentMessageUpdate>>()
for (update in this) {
val data = (update.data as? MediaGroupMessage)
if (data == null) {
resultUpdates.add(update)
continue
}
when (update) {
is BaseEditMessageUpdate -> resultUpdates.add(
update.toEditMediaGroupUpdate()
)
is BaseSentMessageUpdate -> {
mediaGroups.getOrPut(data.mediaGroupId) {
mutableListOf()
}.add(update)
}
else -> resultUpdates.add(update)
}
}
mediaGroups.values.map {
it.toSentMediaGroupUpdate() ?.let { mediaGroupUpdate ->
resultUpdates.add(mediaGroupUpdate)
}
}
resultUpdates.sortBy { it.updateId }
return resultUpdates
}
internal fun List<BaseSentMessageUpdate>.toSentMediaGroupUpdate(): SentMediaGroupUpdate? = (this as? SentMediaGroupUpdate) ?: let {
if (isEmpty()) {
return@let null
}
val resultList = sortedBy { it.updateId }
when (first()) {
is MessageUpdate -> MessageMediaGroupUpdate(resultList)
is ChannelPostUpdate -> ChannelPostMediaGroupUpdate(resultList)
else -> null
}
}
internal fun BaseEditMessageUpdate.toEditMediaGroupUpdate(): EditMediaGroupUpdate = (this as? EditMediaGroupUpdate) ?: let {
when (this) {
is EditMessageUpdate -> EditMessageMediaGroupUpdate(this)
is EditChannelPostUpdate -> EditChannelPostMediaGroupUpdate(this)
else -> error("Unsupported type of ${BaseEditMessageUpdate::class.simpleName}")
}
}

View File

@@ -0,0 +1,11 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api
import kotlinx.serialization.json.Json
@Suppress("EXPERIMENTAL_API_USAGE")
internal val nonstrictJsonFormat = Json {
isLenient = true
ignoreUnknownKeys = true
serializeSpecialFloatingPointValues = true
useArrayPolymorphism = true
}

View File

@@ -0,0 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe
suspend fun RequestsExecutor.getMe() = execute(GetMe)

View File

@@ -0,0 +1,6 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMyCommands
suspend fun RequestsExecutor.getMyCommands() = execute(GetMyCommands)

View File

@@ -0,0 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.bot
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.SetMyCommands
import com.github.insanusmokrassar.TelegramBotAPI.types.BotCommand
suspend fun RequestsExecutor.setMyCommands(
commands: List<BotCommand>
) = execute(SetMyCommands(commands))
suspend fun RequestsExecutor.setMyCommands(
vararg commands: BotCommand
) = setMyCommands(commands.toList())

View File

@@ -2,8 +2,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.chat.get
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.chat.get.GetChat
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.extended.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.PreviewFeature
suspend fun RequestsExecutor.getChat(
chatId: ChatIdentifier
@@ -12,3 +16,117 @@ suspend fun RequestsExecutor.getChat(
suspend fun RequestsExecutor.getChat(
chat: Chat
) = getChat(chat.id)
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedPublicChat] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: PublicChat
) = getChat(chat.id) as ExtendedPublicChat
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedChannelChat] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: ChannelChat
) = getChat(chat.id) as ExtendedChannelChat
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedChannelChatImpl] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: ChannelChatImpl
) = getChat(chat.id) as ExtendedChannelChatImpl
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedGroupChat] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: GroupChat
) = getChat(chat.id) as ExtendedGroupChat
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedGroupChatImpl] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: GroupChatImpl
) = getChat(chat.id) as ExtendedGroupChatImpl
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedSupergroupChat] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: SupergroupChat
) = getChat(chat.id) as ExtendedSupergroupChat
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedSupergroupChatImpl] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: SupergroupChatImpl
) = getChat(chat.id) as ExtendedSupergroupChatImpl
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedPrivateChat] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: PrivateChat
) = getChat(chat.id) as ExtendedPrivateChat
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedPrivateChatImpl] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: PrivateChatImpl
) = getChat(chat.id) as ExtendedPrivateChatImpl
/**
* Will cast incoming [com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat] to a
* [ExtendedUser] with unsafe operator "as"
*
* @throws ClassCastException
*/
@PreviewFeature
suspend fun RequestsExecutor.getChat(
chat: CommonUser
) = getChat(chat.id) as ExtendedUser

View File

@@ -0,0 +1,27 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendDice
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.dice.DiceAnimationType
suspend fun RequestsExecutor.sendDice(
chatId: ChatIdentifier,
animationType: DiceAnimationType? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendDice(chatId, animationType, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendDice(
chat: Chat,
animationType: DiceAnimationType? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendDice(chat.id, animationType, disableNotification, replyToMessageId, replyMarkup)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendAnimation
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.AnimationFile
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: FileId,
thumb: FileId? = null,
animation: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -42,104 +40,6 @@ suspend fun RequestsExecutor.sendAnimation(
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: AnimationFile,
thumb: PhotoSize? = animation.thumb,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAnimation(
chatId, animation.fileId, thumb ?.fileId, text, parseMode, animation.duration, animation.width, animation.height, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAnimation(
chatId,
animation,
thumb,
text,
parseMode,
duration,
width,
height,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAnimation(
chatId,
animation,
thumb,
text,
parseMode,
duration,
width,
height,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAnimation(
chatId,
animation,
thumb,
text,
parseMode,
duration,
width,
height,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -149,19 +49,6 @@ suspend fun RequestsExecutor.sendAnimation(
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAnimation(
chatId, animation, thumb ?.fileId , text, parseMode, duration, width, height, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendAnimation(
chatId: ChatIdentifier,
animation: AnimationFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAnimation(
chatId, animation.fileId, thumb, text, parseMode, animation.duration, animation.width, animation.height, disableNotification, replyToMessageId, replyMarkup
chatId, animation.fileId, animation.thumb ?.fileId, text, parseMode, duration, width, height, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendAudio
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.AudioFile
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: FileId,
thumb: FileId? = null,
audio: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -42,7 +40,6 @@ suspend fun RequestsExecutor.sendAudio(
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: AudioFile,
thumb: PhotoSize? = audio.thumb,
text: String? = null,
parseMode: ParseMode? = null,
title: String? = audio.title,
@@ -50,119 +47,5 @@ suspend fun RequestsExecutor.sendAudio(
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAudio(
chatId, audio.fileId, thumb ?.fileId, text, parseMode, audio.duration, audio.performer, title, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
performer: String? = null,
title: String? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAudio(
chatId,
audio,
thumb,
text,
parseMode,
duration,
performer,
title,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
performer: String? = null,
title: String? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAudio(
chatId,
audio,
thumb,
text,
parseMode,
duration,
performer,
title,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
performer: String? = null,
title: String? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendAudio(
chatId,
audio,
thumb,
text,
parseMode,
duration,
performer,
title,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
performer: String? = null,
title: String? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAudio(
chatId, audio, thumb ?.fileId , text, parseMode, duration, performer, title, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendAudio(
chatId: ChatIdentifier,
audio: AudioFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
title: String? = audio.title,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendAudio(
chatId, audio.fileId, thumb, text, parseMode, audio.duration, audio.performer, title, disableNotification, replyToMessageId, replyMarkup
chatId, audio.fileId, audio.thumb ?.fileId, text, parseMode, audio.duration, audio.performer, title, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendDocument
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.DocumentFile
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: FileId,
thumb: FileId? = null,
document: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
@@ -36,104 +34,11 @@ suspend fun RequestsExecutor.sendDocument(
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: DocumentFile,
thumb: PhotoSize? = document.thumb,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendDocument(
chatId, document.fileId, thumb ?.fileId, text, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendDocument(
chatId,
document,
thumb,
text,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendDocument(
chatId,
document,
thumb,
text,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendDocument(
chatId,
document,
thumb,
text,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendDocument(
chatId, document, thumb ?.fileId , text, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendDocument(
chatId: ChatIdentifier,
document: DocumentFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendDocument(
chatId, document.fileId, thumb, text, parseMode, disableNotification, replyToMessageId, replyMarkup
chatId, document.fileId, document.thumb ?.fileId, text, parseMode, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -1,19 +1,16 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendPhoto
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.files.*
suspend fun RequestsExecutor.sendPhoto(
chatId: ChatIdentifier,
fileId: FileId,
fileId: InputFile,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
@@ -30,107 +27,3 @@ suspend fun RequestsExecutor.sendPhoto(
replyMarkup
)
)
suspend fun RequestsExecutor.sendPhoto(
chatId: ChatIdentifier,
photo: MultipartFile,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendPhoto(
chatId,
photo,
caption,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendPhoto(
chatId: ChatIdentifier,
file: PhotoSize,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chatId, file.fileId, caption, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendPhoto(
chatId: ChatIdentifier,
photo: Photo,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chatId, photo.biggest() ?: throw IllegalArgumentException("Photo $photo is empty"), caption, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendPhoto(
chat: Chat,
fileId: FileId,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chat.id,
fileId,
caption,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)
suspend fun RequestsExecutor.sendPhoto(
chat: Chat,
file: PhotoSize,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chat.id, file.fileId, caption, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendPhoto(
chat: Chat,
photo: Photo,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chat.id, photo.biggest() ?: throw IllegalArgumentException("Photo $photo is empty"), caption, parseMode, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendPhoto(
chat: Chat,
fileId: MultipartFile,
caption: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendPhoto(
chat.id,
fileId,
caption,
parseMode,
disableNotification,
replyToMessageId,
replyMarkup
)

View File

@@ -1,66 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendSticker
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.files.Sticker
suspend fun RequestsExecutor.sendSticker(
chatId: ChatIdentifier,
sticker: FileId,
sticker: InputFile,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendSticker(chatId, sticker, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendSticker(
chatId: ChatIdentifier,
sticker: MultipartFile,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendSticker(chatId, sticker, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendSticker(
chat: Chat,
sticker: FileId,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat.id, sticker, disableNotification, replyToMessageId, replyMarkup)
suspend fun RequestsExecutor.sendSticker(
chat: Chat,
sticker: MultipartFile,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat.id, sticker, disableNotification, replyToMessageId, replyMarkup)
suspend fun RequestsExecutor.sendSticker(
chatId: ChatIdentifier,
sticker: Sticker,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendSticker(
chatId, sticker.fileId, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendSticker(
chat: Chat,
sticker: Sticker,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendSticker(chat.id, sticker.fileId, disableNotification, replyToMessageId, replyMarkup)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendVideo
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
import com.github.insanusmokrassar.TelegramBotAPI.types.files.VideoFile
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: FileId,
thumb: FileId? = null,
video: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -43,93 +41,11 @@ suspend fun RequestsExecutor.sendVideo(
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: VideoFile,
thumb: PhotoSize? = video.thumb,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideo(
chatId, video.fileId, thumb ?.fileId, text, parseMode, video.duration, video.width, video.height, disableNotification, replyToMessageId, replyMarkup
chatId, video.fileId, video.thumb ?.fileId, text, parseMode, video.duration, video.width, video.height, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
supportStreaming: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideo(chatId, video, thumb, text, parseMode, duration, width, height, supportStreaming, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
supportStreaming: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideo(chatId, video, thumb, text, parseMode, duration, width, height, supportStreaming, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideo(chatId, video, thumb, text, parseMode, duration, width, height, null, disableNotification, replyToMessageId, replyMarkup)
)
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
width: Int? = null,
height: Int? = null,
supportStreaming: Boolean? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideo(
chatId, video, thumb ?.fileId , text, parseMode, duration, width, height, supportStreaming, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVideo(
chatId: ChatIdentifier,
video: VideoFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideo(
chatId, video.fileId, thumb, text, parseMode, video.duration, video.width, video.height, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendVideoNote
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
import com.github.insanusmokrassar.TelegramBotAPI.types.files.VideoFile
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: FileId,
thumb: FileId? = null,
videoNote: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -40,118 +38,11 @@ suspend fun RequestsExecutor.sendVideoNote(
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: VideoFile,
thumb: PhotoSize? = videoNote.thumb,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideoNote(
chatId, videoNote.fileId, thumb ?.fileId, text, parseMode, videoNote.duration, videoNote.width, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
size: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideoNote(
chatId,
videoNote,
thumb,
text,
parseMode,
duration,
size,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
size: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideoNote(
chatId,
videoNote,
thumb,
text,
parseMode,
duration,
size,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
size: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVideoNote(
chatId,
videoNote,
thumb,
text,
parseMode,
duration,
size,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
size: Int? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideoNote(
chatId, videoNote, thumb ?.fileId , text, parseMode, duration, size, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVideoNote(
chatId: ChatIdentifier,
videoNote: VideoFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVideoNote(
chatId, videoNote.fileId, thumb, text, parseMode, videoNote.duration, videoNote.width, disableNotification, replyToMessageId, replyMarkup
chatId, videoNote.fileId, videoNote.thumb ?.fileId, text, parseMode, videoNote.duration, videoNote.width, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -1,20 +1,18 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.send.media
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.InputFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendVoice
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.files.AudioFile
import com.github.insanusmokrassar.TelegramBotAPI.types.files.PhotoSize
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: FileId,
thumb: FileId? = null,
voice: InputFile,
thumb: InputFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
@@ -38,112 +36,11 @@ suspend fun RequestsExecutor.sendVoice(
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: AudioFile,
thumb: PhotoSize? = voice.thumb,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVoice(
chatId, voice.fileId, thumb ?.fileId, text, parseMode, voice.duration, disableNotification, replyToMessageId, replyMarkup
chatId, voice.fileId, voice.thumb ?.fileId, text, parseMode, voice.duration, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: MultipartFile,
thumb: FileId? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVoice(
chatId,
voice,
thumb,
text,
parseMode,
duration,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: MultipartFile,
thumb: MultipartFile? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVoice(
chatId,
voice,
thumb,
text,
parseMode,
duration,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: FileId,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendVoice(
chatId,
voice,
thumb,
text,
parseMode,
duration,
disableNotification,
replyToMessageId,
replyMarkup
)
)
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: MultipartFile,
thumb: PhotoSize? = null,
text: String? = null,
parseMode: ParseMode? = null,
duration: Long? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVoice(
chatId, voice, thumb ?.fileId , text, parseMode, duration, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendVoice(
chatId: ChatIdentifier,
voice: AudioFile,
thumb: MultipartFile,
text: String? = null,
parseMode: ParseMode? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendVoice(
chatId, voice.fileId, thumb, text, parseMode, voice.duration, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -5,10 +5,10 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendQuizPo
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.polls.SendRegularPoll
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.QuizPoll
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.RegularPoll
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.*
suspend fun RequestsExecutor.sendRegularPoll(
chatId: ChatIdentifier,
@@ -17,12 +17,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
isAnonymous: Boolean = true,
isClosed: Boolean = false,
allowMultipleAnswers: Boolean = false,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendRegularPoll(
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
)
suspend fun RequestsExecutor.sendRegularPoll(
@@ -33,12 +34,13 @@ suspend fun RequestsExecutor.sendRegularPoll(
options: List<String> = poll.options.map { it.text },
isAnonymous: Boolean = poll.isAnonymous,
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendRegularPoll(
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
chatId, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
)
@@ -49,11 +51,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
isAnonymous: Boolean = true,
isClosed: Boolean = false,
allowMultipleAnswers: Boolean = false,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendRegularPoll(
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendRegularPoll(
@@ -64,11 +67,12 @@ suspend fun RequestsExecutor.sendRegularPoll(
options: List<String> = poll.options.map { it.text },
isAnonymous: Boolean = poll.isAnonymous,
allowMultipleAnswers: Boolean = poll.allowMultipleAnswers,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendRegularPoll(
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, disableNotification, replyToMessageId, replyMarkup
chat.id, question, options, isAnonymous, isClosed, allowMultipleAnswers, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
@@ -79,12 +83,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
correctOptionId: Int,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
explanation: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendQuizPoll(
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
chatId, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
)
@@ -95,11 +102,14 @@ suspend fun RequestsExecutor.sendQuizPoll(
correctOptionId: Int,
isAnonymous: Boolean = true,
isClosed: Boolean = false,
explanation: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendQuizPoll(
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
chat.id, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
suspend fun RequestsExecutor.sendQuizPoll(
@@ -110,12 +120,15 @@ suspend fun RequestsExecutor.sendQuizPoll(
options: List<String> = quizPoll.options.map { it.text },
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
isAnonymous: Boolean = quizPoll.isAnonymous,
explanation: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = execute(
SendQuizPoll(
chatId, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
chatId, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
)
)
@@ -127,9 +140,12 @@ suspend fun RequestsExecutor.sendQuizPoll(
options: List<String> = quizPoll.options.map { it.text },
correctOptionId: Int = quizPoll.correctOptionId ?: error("Correct option ID must be provided by income QuizPoll or by developer"),
isAnonymous: Boolean = quizPoll.isAnonymous,
explanation: String? = null,
parseMode: ParseMode? = null,
closeInfo: ScheduledCloseInfo? = null,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
) = sendQuizPoll(
chat.id, question, options, correctOptionId, isAnonymous, isClosed, disableNotification, replyToMessageId, replyMarkup
chat.id, question, options, correctOptionId, isAnonymous, isClosed, explanation, parseMode, closeInfo, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -0,0 +1,90 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddAnimatedStickerToSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddAnimatedStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addAnimatedStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addAnimatedStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -3,88 +3,88 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStickerToSet
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.AddStaticStickerToSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = execute(
AddStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
AddStaticStickerToSet(userId, stickerSetName, sticker, emojis, maskPosition)
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser,
stickerSetName: String,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
user.id, stickerSetName, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
userId: UserId,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
userId, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: FileId,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)
suspend fun RequestsExecutor.addStickerToSet(
suspend fun RequestsExecutor.addStaticStickerToSet(
user: CommonUser,
stickerSet: StickerSet,
sticker: MultipartFile,
emojis: String,
maskPosition: MaskPosition? = null
) = addStickerToSet(
) = addStaticStickerToSet(
user.id, stickerSet.name, sticker, emojis, maskPosition
)

View File

@@ -0,0 +1,54 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewAnimatedStickerSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
userId: UserId,
name: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
userId: UserId,
name: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewAnimatedStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)
suspend fun RequestsExecutor.createNewAnimatedStickerSet(
user: CommonUser,
name: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewAnimatedStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -3,12 +3,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.stickers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewStickerSet
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.CreateNewStaticStickerSet
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.MaskPosition
suspend fun RequestsExecutor.createNewStickerSet(
suspend fun RequestsExecutor.createNewStaticStickerSet(
userId: UserId,
name: String,
sticker: FileId,
@@ -16,10 +16,10 @@ suspend fun RequestsExecutor.createNewStickerSet(
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
CreateNewStaticStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewStickerSet(
suspend fun RequestsExecutor.createNewStaticStickerSet(
userId: UserId,
name: String,
sticker: MultipartFile,
@@ -27,28 +27,28 @@ suspend fun RequestsExecutor.createNewStickerSet(
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = execute(
CreateNewStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
CreateNewStaticStickerSet(userId, name, sticker, emojis, containsMasks, maskPosition)
)
suspend fun RequestsExecutor.createNewStickerSet(
suspend fun RequestsExecutor.createNewStaticStickerSet(
user: CommonUser,
name: String,
sticker: FileId,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewStickerSet(
) = createNewStaticStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)
suspend fun RequestsExecutor.createNewStickerSet(
suspend fun RequestsExecutor.createNewStaticStickerSet(
user: CommonUser,
name: String,
sticker: MultipartFile,
emojis: String,
containsMasks: Boolean? = null,
maskPosition: MaskPosition? = null
) = createNewStickerSet(
) = createNewStaticStickerSet(
user.id, name, sticker, emojis, containsMasks, maskPosition
)

View File

@@ -0,0 +1,74 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.thumbs
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.stickers.SetStickerSetThumb
import com.github.insanusmokrassar.TelegramBotAPI.types.CommonUser
import com.github.insanusmokrassar.TelegramBotAPI.types.UserId
import com.github.insanusmokrassar.TelegramBotAPI.types.stickers.StickerSet
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSetName: String,
thumb: FileId
) = execute(
SetStickerSetThumb(userId, thumbSetName, thumb)
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSetName: String,
thumb: MultipartFile
) = execute(
SetStickerSetThumb(userId, thumbSetName, thumb)
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSetName: String,
thumb: FileId
) = setStickerSetThumb(
user.id, thumbSetName, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSetName: String,
thumb: MultipartFile
) = setStickerSetThumb(
user.id, thumbSetName, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSet: StickerSet,
thumb: FileId
) = setStickerSetThumb(
userId, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
userId: UserId,
thumbSet: StickerSet,
thumb: MultipartFile
) = setStickerSetThumb(
userId, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSet: StickerSet,
thumb: FileId
) = setStickerSetThumb(
user.id, thumbSet.name, thumb
)
suspend fun RequestsExecutor.setStickerSetThumb(
user: CommonUser,
thumbSet: StickerSet,
thumb: MultipartFile
) = setStickerSetThumb(
user.id, thumbSet.name, thumb
)

View File

@@ -0,0 +1,182 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.updates
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.RequestException
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.convertWithMediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.lastUpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.getUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import kotlinx.coroutines.*
@Deprecated("Replaced and renamed in TelegramBotAPI-extensions-utils")
fun RequestsExecutor.startGettingOfUpdates(
timeoutSeconds: Seconds = 30,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: (ExceptionHandler<Unit>)? = null,
allowedUpdates: List<String>? = null,
updatesReceiver: UpdateReceiver<Update>
): Job = scope.launch {
var lastUpdateIdentifier: UpdateIdentifier? = null
while (isActive) {
handleSafely(
{ e ->
exceptionsHandler ?.invoke(e)
if (e is RequestException) {
delay(1000L)
}
}
) {
val updates = getUpdates(
offset = lastUpdateIdentifier?.plus(1),
timeout = timeoutSeconds,
allowed_updates = allowedUpdates
).let { originalUpdates ->
val converted = originalUpdates.convertWithMediaGroupUpdates()
/**
* Dirty hack for cases when the media group was retrieved not fully:
*
* We are throw out the last media group and will reretrieve it again in the next get updates
* and it will guarantee that it is full
*/
if (originalUpdates.size == getUpdatesLimit.last && converted.last() is SentMediaGroupUpdate) {
converted - converted.last()
} else {
converted
}
}
handleSafely {
for (update in updates) {
updatesReceiver(update)
lastUpdateIdentifier = update.lastUpdateIdentifier()
}
}
}
}
}
/**
* This method will create a new one [FlowsUpdatesFilter]. This method could be unsafe due to the fact that it will start
* getting updates IMMEDIATELY. That means that your bot will be able to skip some of them until you will call
* [kotlinx.coroutines.flow.Flow.collect] on one of [FlowsUpdatesFilter] flows. To avoid it, you can pass
* [flowUpdatesPreset] lambda - it will be called BEFORE starting updates getting
*/
@FlowPreview
@PreviewFeature
@Suppress("unused")
@Deprecated("Replaced and renamed in TelegramBotAPI-extensions-utils")
fun RequestsExecutor.startGettingFlowsUpdates(
timeoutSeconds: Seconds = 30,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
flowsUpdatesFilterUpdatesKeeperCount: Int = 64,
flowUpdatesPreset: FlowsUpdatesFilter.() -> Unit = {}
): FlowsUpdatesFilter = FlowsUpdatesFilter(flowsUpdatesFilterUpdatesKeeperCount).apply {
flowUpdatesPreset()
startGettingOfUpdates(timeoutSeconds, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver)
}
@Deprecated("Replaced and renamed in TelegramBotAPI-extensions-utils")
fun RequestsExecutor.startGettingOfUpdates(
updatesFilter: UpdatesFilter,
timeoutSeconds: Seconds = 30,
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
): Job = startGettingOfUpdates(
timeoutSeconds,
scope,
exceptionsHandler,
updatesFilter.allowedUpdates,
updatesFilter.asUpdateReceiver
)
@Deprecated("Replaced and renamed in TelegramBotAPI-extensions-utils")
fun RequestsExecutor.startGettingOfUpdates(
messageCallback: UpdateReceiver<MessageUpdate>? = null,
messageMediaGroupCallback: UpdateReceiver<MessageMediaGroupUpdate>? = null,
editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
editedMessageMediaGroupCallback: UpdateReceiver<EditMessageMediaGroupUpdate>? = null,
channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
channelPostMediaGroupCallback: UpdateReceiver<ChannelPostMediaGroupUpdate>? = null,
editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
editedChannelPostMediaGroupCallback: UpdateReceiver<EditChannelPostMediaGroupUpdate>? = null,
chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null,
pollCallback: UpdateReceiver<PollUpdate>? = null,
pollAnswerCallback: UpdateReceiver<PollAnswerUpdate>? = null,
timeoutSeconds: Seconds = 30,
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
scope: CoroutineScope = GlobalScope
): Job {
return startGettingOfUpdates(
SimpleUpdatesFilter(
messageCallback,
messageMediaGroupCallback,
editedMessageCallback,
editedMessageMediaGroupCallback,
channelPostCallback,
channelPostMediaGroupCallback,
editedChannelPostCallback,
editedChannelPostMediaGroupCallback,
chosenInlineResultCallback,
inlineQueryCallback,
callbackQueryCallback,
shippingQueryCallback,
preCheckoutQueryCallback,
pollCallback,
pollAnswerCallback
),
timeoutSeconds,
exceptionsHandler,
scope
)
}
@Suppress("unused")
@Deprecated("Replaced and renamed in TelegramBotAPI-extensions-utils")
fun RequestsExecutor.startGettingOfUpdates(
messageCallback: UpdateReceiver<MessageUpdate>? = null,
mediaGroupCallback: UpdateReceiver<MediaGroupUpdate>? = null,
editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null,
pollCallback: UpdateReceiver<PollUpdate>? = null,
pollAnswerCallback: UpdateReceiver<PollAnswerUpdate>? = null,
timeoutSeconds: Seconds = 30,
exceptionsHandler: (suspend (Exception) -> Unit)? = null,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
): Job = startGettingOfUpdates(
messageCallback = messageCallback,
messageMediaGroupCallback = mediaGroupCallback,
editedMessageCallback = editedMessageCallback,
editedMessageMediaGroupCallback = mediaGroupCallback,
channelPostCallback = channelPostCallback,
channelPostMediaGroupCallback = mediaGroupCallback,
editedChannelPostCallback = editedChannelPostCallback,
editedChannelPostMediaGroupCallback = mediaGroupCallback,
chosenInlineResultCallback = chosenInlineResultCallback,
inlineQueryCallback = inlineQueryCallback,
callbackQueryCallback = callbackQueryCallback,
shippingQueryCallback = shippingQueryCallback,
preCheckoutQueryCallback = preCheckoutQueryCallback,
pollCallback = pollCallback,
pollAnswerCallback = pollAnswerCallback,
timeoutSeconds = timeoutSeconds,
exceptionsHandler = exceptionsHandler,
scope = scope
)

View File

@@ -0,0 +1,49 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.api.utils
import com.github.insanusmokrassar.TelegramBotAPI.extensions.api.InternalUtils.convertWithMediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.accumulateByKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
/**
* Create [UpdateReceiver] object which will correctly accumulate updates and send into output updates which INCLUDE
* [com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.MediaGroupUpdate]s.
*
* @see UpdateReceiver
*/
fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
output: UpdateReceiver<Update>,
mediaGroupsDebounceMillis: Long = 1000L
): UpdateReceiver<Update> {
val updatesChannel = Channel<Update>(Channel.UNLIMITED)
val mediaGroupChannel = Channel<Pair<String, BaseMessageUpdate>>(Channel.UNLIMITED)
val mediaGroupAccumulatedChannel = mediaGroupChannel.accumulateByKey(
mediaGroupsDebounceMillis,
scope = this
)
launch {
launch {
for (update in updatesChannel) {
when (val data = update.data) {
is MediaGroupMessage -> mediaGroupChannel.send("${data.mediaGroupId}${update::class.simpleName}" to update as BaseMessageUpdate)
else -> output(update)
}
}
}
launch {
for ((_, mediaGroup) in mediaGroupAccumulatedChannel) {
mediaGroup.convertWithMediaGroupUpdates().forEach {
output(it)
}
}
}
}
return { updatesChannel.send(it) }
}

View File

@@ -5,6 +5,22 @@ import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.FileId
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.webhook.SetWebhook
/**
* Use this method to send information about webhook (like [url])
*/
suspend fun RequestsExecutor.setWebhookInfo(
url: String,
maxAllowedConnections: Int? = null,
allowedUpdates: List<String>? = null
) = execute(
SetWebhook(
url, maxAllowedConnections, allowedUpdates
)
)
/**
* Use this method to send information about webhook (like [url] and [certificate])
*/
suspend fun RequestsExecutor.setWebhookInfo(
url: String,
certificate: FileId,
@@ -16,6 +32,9 @@ suspend fun RequestsExecutor.setWebhookInfo(
)
)
/**
* Use this method to send information about webhook (like [url] and [certificate])
*/
suspend fun RequestsExecutor.setWebhookInfo(
url: String,
certificate: MultipartFile,

View File

@@ -0,0 +1,289 @@
# TelegramBotAPI Util Extensions
- [TelegramBotAPI Util Extensions](#telegrambotapi-util--extensions)
* [What is it?](#what-is-it-)
* [How to implement library?](#how-to-implement-library-)
+ [Maven](#maven)
+ [Gradle](#gradle)
* [How to use?](#how-to-use-)
+ [Updates](#updates)
- [Long polling](#long-polling)
- [WebHooks (currently JVM-only)](#webhooks--currently-jvm-only-)
+ [Filters](#filters)
- [Sent messages](#sent-messages)
* [Common messages](#common-messages)
* [Chat actions](#chat-actions)
+ [Shortcuts](#shortcuts)
- [ScheduledCloseInfo](#scheduledcloseinfo)
<small><i><a href='http://ecotrust-canada.github.io/markdown-toc/'>Table of contents generated with markdown-toc</a></i></small>
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI-extensions-utils)
## What is it?
It is wrapper library for [TelegramBotAPI](../TelegramBotAPI/README.md). Currently, this library contains some usefull filters for commands, updates types and different others.
## How to implement library?
Common ways to implement this library are presented here. In some cases it will require additional steps
like inserting of additional libraries (like `kotlin stdlib`). In the examples will be used variable
`telegrambotapi-extensions-utils_version`, which must be set up by developer. Available versions are presented on
[bintray](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils), next version is last published:
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI-extensions-utils/_latestVersion)
### Maven
Dependency config presented here:
```xml
<dependency>
<groupId>com.github.insanusmokrassar</groupId>
<artifactId>TelegramBotAPI-extensions-utils</artifactId>
<version>${telegrambotapi-extensions-utils_version}</version>
</dependency>
```
### Gradle
To use last versions you will need to add one line in repositories block of your `build.gradle`:
`jcenter()` or `mavenCentral()`
And add next line to your dependencies block:
```groovy
implementation "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$telegrambotapi-extensions-utils_version"
```
or for old gradle:
```groovy
compile "com.github.insanusmokrassar:TelegramBotAPI-extensions-utils:$telegrambotapi-extensions-utils_version"
```
## How to use?
Here will be presented several examples of usage. In all cases it is expected that you have created your bot and filter:
```kotlin
val bot: RequestsExecutor = KtorRequestsExecutor(
TelegramAPIUrlsKeeper(BOT_TOKEN)
)
val filter = FlowsUpdatesFilter(64)
```
Alternative way to use the things below:
```kotlin
val filter = bot.startGettingFlowsUpdatesByLongPolling(
scope = CoroutineScope(Dispatchers.Default)
) {
// place code from examples here with replacing of `filter` by `this`
}
```
### Updates
As mentioned in [Telegram Bot API reference](https://core.telegram.org/bots/api#getting-updates), there are two ways for
updates retrieving:
* Webhooks
* Long Polling
Both of them you could use in your project using [TelegramBotAPI](../TelegramBotAPI/README.md), but here there are
several useful extensions for both of them.
Anyway, in both of ways it will be useful to know that it is possible to create `UpdateReceiver` object using function
`flowsUpdatesFilter`:
```kotlin
val internalChannelsSizes = 128
flowsUpdatesFilter(internalChannelsSizes/* default is 64 */) {
/* ... */
}
```
#### Long polling
The most simple way is Long Polling and one of the usages was mentioned above:
```kotlin
val filter = bot.startGettingFlowsUpdatesByLongPolling(
scope = CoroutineScope(Dispatchers.Default)
) {
// place code from examples here with replacing of `filter` by `this`
}
```
Extension `startGettingFlowsUpdatesByLongPolling` was used in this example, but there are a lot of variations of
`startGettingOfUpdatesByLongPolling` and others for getting the same result. Usually, it is supposed that you already
have created `filter` object (or something like this) and will pass it into extension:
```kotlin
val filter = FlowsUpdatesFilter(64)
bot.startGettingOfUpdatesByLongPolling(
filter
)
```
But also there are extensions which allow to pass lambdas directly:
```kotlin
bot.startGettingOfUpdatesByLongPolling(
{
println("Received message update: $it")
}
)
```
Anyway, it is strictly recommended to pass your `CoroutineScope` object to this method at least for more comfortable
management of updates.
#### WebHooks (currently JVM-only)
For webhooks there are less number of functions and extensions than for Long Polling (but it is still fully automated):
```kotlin
startListenWebhooks(
8081,
CIO // require to implement this engine dependency
) {
// here will be all updates one by one in $it
}
```
Besides, there are two additional opportunities:
* Extension `Route#includeWebhookHandlingInRoute`, which allow you to include webhook processing inside your ktor
application without creating of new one server (as it is happening in `startListenWebhooks`)
* Extension `RequestsExecutor#setWebhookInfoAndStartListenWebhooks`. It is allow to set up full server (in fact, with
`startListenWebhooks`), but also send `SetWebhook` request before and check that it was successful
### Filters
There are several filters for flows.
#### Updates
In the next table it is supposed that you are using some `Flow` with type from `Base type of update` and apply
extension `Extension` and will get `Flow` with type from `Result type of update` column.
| Base type of update | Extension | Result type of update |
| ------------------- | --------- | --------------------- |
| `Update` | `onlyBaseMessageUpdates` | `BaseMessageUpdate` |
| | | |
| `BaseMessageUpdate` | `onlySentMessageUpdates` | `BaseSentMessageUpdate` |
| `BaseMessageUpdate` | `onlyEditMessageUpdates` | `BaseEditMessageUpdate` |
| `BaseMessageUpdate` | `onlyMediaGroupsUpdates` | `MediaGroupUpdate` |
| | | |
| `MediaGroupUpdate` | `onlySentMediaGroupUpdates` | `SentMediaGroupUpdate` |
| `MediaGroupUpdate` | `onlyEditMediaGroupUpdates` | `EditMediaGroupUpdate` |
All of these extensions was made for more simple work with the others:
```kotlin
val flow: Flow<BaseMessageUpdate> = ...; // here we are getting flow from somewhere,
// for example, FlowsUpdatesFilter#messageFlow
flow.onlySentMessageUpdates().filterExactCommands(Regex("start"))
```
Here we have used filter `filterExactCommands` which will pass only `ContentMessage` with only one command `start`
#### Sent messages
All sent messages can be filtered for three types:
| Type | Description | Flow extension |
|:---- |:----------- |:-------------- |
| Common messages | Simple messages with text, media, location, etc. | `asContentMessagesFlow` |
| Chat actions | New chat member, rename of chat, etc. | `asChatEventsFlow` |
| Unknown events | Any other messages, that contain unsupported data | `asUnknownMessagesFlow` |
##### Common messages
Unfortunately, due to the erasing of generic types, when you are using `asContentMessagesFlow` you will retrieve
data with type `ContentMessage<*>`. For correct filtering of content type for retrieved objects, was created special
filters:
| Content type | Result type | Flow extension |
|:---- |:----------- |:-------------- |
| Animation | `ContentMessage<AnimationContent>`| `onlyAnimationContentMessages` |
| Audio | `ContentMessage<AudioContent>` | `onlyAudioContentMessages` |
| Contact | `ContentMessage<ContactContent>` | `onlyContactContentMessages` |
| Dice | `ContentMessage<DiceContent>` | `onlyDiceContentMessages` |
| Document | `ContentMessage<DocumentContent>` | `onlyDocumentContentMessages` |
| Game | `ContentMessage<GameContent>` | `onlyGameContentMessages` |
| Invoice | `ContentMessage<InvoiceContent>` | `onlyInvoiceContentMessages` |
| Location | `ContentMessage<LocationContent>` | `onlyLocationContentMessages` |
| Photo | `ContentMessage<PhotoContent>` | `onlyPhotoContentMessages` |
| Poll | `ContentMessage<PollContent>` | `onlyPollContentMessages` |
| Sticker | `ContentMessage<StickerContent>` | `onlyStickerContentMessages` |
| Text | `ContentMessage<TextContent>` | `onlyTextContentMessages` |
| Venue | `ContentMessage<VenueContent>` | `onlyVenueContentMessages` |
| Video | `ContentMessage<VideoContent>` | `onlyVideoContentMessages` |
| VideoNote | `ContentMessage<VideoNoteContent>` | `onlyVideoNoteContentMessages` |
| Voice | `ContentMessage<VoiceContent>` | `onlyVoiceContentMessages` |
For example, if you wish to get only photo messages from private chats of groups, you should call next code:
```kotlin
filter.messageFlow.asContentMessagesFlow().onlyPhotoContentMessages().onEach {
println(it.content)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
```
##### Chat actions
Chat actions can be divided for three types of events source:
| Type | Flow extension |
|:---- |:-------------- |
| Channel events | `onlyChannelEvents` |
| Group events | `onlyGroupEvents` |
| Supergroup events | `onlySupergroupEvents` |
According to this table, if you want to add filtering by supergroup events, you will use code like this:
```kotlin
filter.messageFlow.asChatEventsFlow().onlySupergroupEvents().onEach {
println(it.chatEvent)
}.launchIn(
CoroutineScope(Dispatchers.Default)
)
```
### Shortcuts
With shortcuts you are able to use simple factories for several things.
#### ScheduledCloseInfo
In case if you are creating some poll, you able to use next shortcuts.
Next sample will use info with closing at the 10 seconds after now:
```kotlin
closePollExactAt(DateTime.now() + TimeSpan(10000.0))
```
In this example we will do the same, but in another way:
```kotlin
closePollExactAfter(10)
```
Here we have passed `10` seconds and will get the same result object.
In opposite to previous shortcuts, the next one will create `approximate` closing schedule:
```kotlin
closePollAfter(10)
```
The main difference here is that the last one will be closed after 10 seconds since the sending. With first samples
will be created **exact** time for closing of poll

View File

@@ -0,0 +1,48 @@
buildscript {
repositories {
mavenLocal()
jcenter()
mavenCentral()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradle_bintray_plugin_version"
}
}
plugins {
id "org.jetbrains.kotlin.multiplatform" version "$kotlin_version"
id "org.jetbrains.kotlin.plugin.serialization" version "$kotlin_version"
}
project.version = "$library_version"
project.group = "$library_group"
apply from: "publish.gradle"
repositories {
mavenLocal()
jcenter()
mavenCentral()
maven { url "https://kotlin.bintray.com/kotlinx" }
}
kotlin {
jvm()
js()
sourceSets {
commonMain {
dependencies {
implementation kotlin('stdlib')
if ((project.hasProperty('RELEASE_MODE') && project.property('RELEASE_MODE') == "true") || System.getenv('RELEASE_MODE') == "true") {
api "${project.group}:TelegramBotAPI:$library_version"
} else {
api project(":TelegramBotAPI")
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
apply plugin: 'maven-publish'
task javadocsJar(type: Jar) {
classifier = 'javadoc'
}
afterEvaluate {
project.publishing.publications.all {
// rename artifacts
groupId "${project.group}"
if (it.name.contains('kotlinMultiplatform')) {
artifactId = "${project.name}"
} else {
artifactId = "${project.name}-$name"
}
}
}
publishing {
publications.all {
artifact javadocsJar
pom {
description = "Util extensions for more useful work with updates and other things"
name = "Telegram Bot API Utility Extensions"
url = "https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}
}

View File

@@ -0,0 +1 @@
{"bintrayConfig":{"repo":"StandardRepository","packageName":"${project.name}","packageVcs":"https://github.com/InsanusMokrassar/TelegramBotAPI"},"licenses":[{"id":"Apache-2.0","title":"Apache Software License 2.0","url":"https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"}],"mavenConfig":{"name":"Telegram Bot API Utility Extensions","description":"Util extensions for more useful work with updates and other things","url":"https://insanusmokrassar.github.io/TelegramBotAPI/TelegramBotAPI-extensions-utils","vcsUrl":"https://github.com/insanusmokrassar/TelegramBotAPI.git","developers":[{"id":"InsanusMokrassar","name":"Ovsiannikov Aleksei","eMail":"ovsyannikov.alexey95@gmail.com"}]},"type":"Multiplatform"}

View File

@@ -0,0 +1,55 @@
apply plugin: 'com.jfrog.bintray'
apply from: "maven.publish.gradle"
bintray {
user = project.hasProperty('BINTRAY_USER') ? project.property('BINTRAY_USER') : System.getenv('BINTRAY_USER')
key = project.hasProperty('BINTRAY_KEY') ? project.property('BINTRAY_KEY') : System.getenv('BINTRAY_KEY')
filesSpec {
from "${buildDir}/publications/"
eachFile {
String directorySubname = it.getFile().parentFile.name
if (it.getName() == "module.json") {
if (directorySubname == "kotlinMultiplatform") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.module")
} else {
it.setPath("${project.name}-${directorySubname}/${project.version}/${project.name}-${directorySubname}-${project.version}.module")
}
} else {
if (directorySubname == "kotlinMultiplatform" && it.getName() == "pom-default.xml") {
it.setPath("${project.name}/${project.version}/${project.name}-${project.version}.pom")
} else {
it.exclude()
}
}
}
into "${project.group}".replace(".", "/")
}
pkg {
repo = "StandardRepository"
name = "${project.name}"
vcsUrl = "https://github.com/InsanusMokrassar/TelegramBotAPI"
licenses = ["Apache-2.0"]
version {
name = "${project.version}"
released = new Date()
vcsTag = "${project.version}"
gpg {
sign = true
passphrase = project.hasProperty('signing.gnupg.passphrase') ? project.property('signing.gnupg.passphrase') : System.getenv('signing.gnupg.passphrase')
}
}
}
}
bintrayUpload.doFirst {
publications = publishing.publications.collect {
if (it.name.contains('kotlinMultiplatform')) {
null
} else {
it.name
}
} - null
}
bintrayUpload.dependsOn publishToMavenLocal

View File

@@ -0,0 +1,12 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
fun <T : CallbackQuery> Flow<T>.onlyMessageDataCallbackQueries() = mapNotNull {
it as? MessageDataCallbackQuery
}
fun <T : CallbackQuery> Flow<T>.onlyInlineMessageIdDataCallbackQueries() = mapNotNull {
it as? InlineMessageIdDataCallbackQuery
}

View File

@@ -0,0 +1,36 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.abstracts.MessageContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.media.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.payments.InvoiceContent
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KClass
fun <T : MessageContent> Flow<ContentMessage<*>>.withContentType(contentType: KClass<T>) = mapNotNull {
if (contentType.isInstance(it.content)) {
@Suppress("UNCHECKED_CAST")
it as ContentMessage<T>
} else {
null
}
}
fun Flow<ContentMessage<*>>.onlyAnimationContentMessages() = withContentType(AnimationContent::class)
fun Flow<ContentMessage<*>>.onlyAudioContentMessages() = withContentType(AudioContent::class)
fun Flow<ContentMessage<*>>.onlyContactContentMessages() = withContentType(ContactContent::class)
fun Flow<ContentMessage<*>>.onlyDiceContentMessages() = withContentType(DiceContent::class)
fun Flow<ContentMessage<*>>.onlyDocumentContentMessages() = withContentType(DocumentContent::class)
fun Flow<ContentMessage<*>>.onlyGameContentMessages() = withContentType(GameContent::class)
fun Flow<ContentMessage<*>>.onlyInvoiceContentMessages() = withContentType(InvoiceContent::class)
fun Flow<ContentMessage<*>>.onlyLocationContentMessages() = withContentType(LocationContent::class)
fun Flow<ContentMessage<*>>.onlyPhotoContentMessages() = withContentType(PhotoContent::class)
fun Flow<ContentMessage<*>>.onlyPollContentMessages() = withContentType(PollContent::class)
fun Flow<ContentMessage<*>>.onlyStickerContentMessages() = withContentType(StickerContent::class)
fun Flow<ContentMessage<*>>.onlyTextContentMessages() = withContentType(TextContent::class)
fun Flow<ContentMessage<*>>.onlyVenueContentMessages() = withContentType(VenueContent::class)
fun Flow<ContentMessage<*>>.onlyVideoContentMessages() = withContentType(VideoContent::class)
fun Flow<ContentMessage<*>>.onlyVideoNoteContentMessages() = withContentType(VideoNoteContent::class)
fun Flow<ContentMessage<*>>.onlyVoiceContentMessages() = withContentType(VoiceContent::class)

View File

@@ -0,0 +1,11 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import kotlinx.serialization.json.Json
@Suppress("EXPERIMENTAL_API_USAGE")
internal val nonstrictJsonFormat = Json {
isLenient = true
ignoreUnknownKeys = true
serializeSpecialFloatingPointValues = true
useArrayPolymorphism = true
}

View File

@@ -0,0 +1,16 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import kotlinx.coroutines.CoroutineScope
/**
* Shortcut for [handleSafely]. It was created for more comfortable way of handling different things
*/
@PreviewFeature
suspend inline fun <T> safely(
noinline onException: ExceptionHandler<T> = { throw it },
noinline block: suspend CoroutineScope.() -> T
): T = handleSafely(
onException,
block
)

View File

@@ -0,0 +1,21 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.chat_events
import com.github.insanusmokrassar.TelegramBotAPI.types.message.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ChatEventMessage
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
import kotlin.reflect.KClass
fun <T : ChatEventMessage> Flow<ChatEventMessage>.divideBySource(contentType: KClass<T>) = mapNotNull {
if (contentType.isInstance(it)) {
@Suppress("UNCHECKED_CAST")
it as T
} else {
null
}
}
fun Flow<ChatEventMessage>.onlyChannelEvents() = divideBySource(ChannelEventMessage::class)
fun Flow<ChatEventMessage>.onlyGroupEvents() = divideBySource(GroupEventMessage::class)
fun Flow<ChatEventMessage>.onlySupergroupEvents() = divideBySource(SupergroupEventMessage::class)

View File

@@ -0,0 +1,80 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.formatting
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.types.StickerSetName
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.PrivateChat
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.UsernameChat
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.extended.ExtendedChat
import com.github.insanusmokrassar.TelegramBotAPI.utils.link
private const val internalLinkBeginning = "https://t.me"
fun makeLinkToMessage(
username: String,
messageId: MessageIdentifier
): String = "$internalLinkBeginning/$username/$messageId"
private val linkIdRedundantPartRegex = Regex("^-100")
private val usernameBeginSymbolRegex = Regex("^@")
fun makeLinkToMessage(
chat: ExtendedChat,
messageId: MessageIdentifier
): String? {
return when {
chat is UsernameChat && chat.username != null -> {
"$internalLinkBeginning/${chat.username ?.username ?.replace(
usernameBeginSymbolRegex, "")}/$messageId"
}
chat !is PrivateChat -> chat.id.chatId.toString().replace(
linkIdRedundantPartRegex,
""
).let { bareId ->
"$internalLinkBeginning/c/$bareId/$messageId"
}
else -> return null
}
}
private const val stickerSetAddingLinkPrefix = "$internalLinkBeginning/addstickers"
/**
* Create a link for adding of sticker set with name [stickerSetName]. Was added thanks to user Djaler and based on
* https://github.com/Djaler/evil-bot/blob/master/src/main/kotlin/com/github/djaler/evilbot/utils/StickerUtils.kt#L6-L8
*
* @see [makeLinkToAddStickerSetInMarkdownV2]
* @see [makeLinkToAddStickerSetInMarkdown]
* @see [makeLinkToAddStickerSetInHtml]
*/
fun makeLinkToAddStickerSet(
stickerSetName: StickerSetName,
parseMode: ParseMode
) = (stickerSetName to "$stickerSetAddingLinkPrefix/$stickerSetName").link(
parseMode
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [MarkdownV2]
*/
fun makeLinkToAddStickerSetInMarkdownV2(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
MarkdownV2
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [Markdown]
*/
fun makeLinkToAddStickerSetInMarkdown(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
Markdown
)
/**
* @return Link for adding of sticker set with name [stickerSetName] with formatting for [HTML]
*/
fun makeLinkToAddStickerSetInHtml(stickerSetName: StickerSetName) =
makeLinkToAddStickerSet(
stickerSetName,
HTML
)

View File

@@ -0,0 +1,121 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.formatting
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.TextContent
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
fun createFormattedText(
entities: FullTextSourcesList,
partLength: Int = textLength.last,
mode: ParseMode = MarkdownParseMode
): List<String> {
val texts = mutableListOf<String>()
val textBuilder = StringBuilder(partLength)
for (entity in entities) {
val string = when (mode) {
is MarkdownParseMode -> entity.asMarkdownSource
is MarkdownV2ParseMode -> entity.asMarkdownV2Source
is HTMLParseMode -> entity.asHtmlSource
}
if (textBuilder.length + string.length > partLength) {
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
val chunked = string.chunked(partLength)
val last = chunked.last()
textBuilder.append(last)
val listToAdd = if (chunked.size > 1) {
chunked.subList(0, chunked.size - 1)
} else {
emptyList()
}
listToAdd.forEach {
texts.add(it)
}
} else {
textBuilder.append(string)
}
}
if (textBuilder.isNotEmpty()) {
texts.add(textBuilder.toString())
textBuilder.clear()
}
return texts
}
fun createMarkdownText(
entities: FullTextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownParseMode)
fun FullTextSourcesList.toMarkdownCaptions(): List<String> = createMarkdownText(
this,
captionLength.last
)
fun CaptionedInput.toMarkdownCaptions(): List<String> = fullEntitiesList().toMarkdownCaptions()
fun FullTextSourcesList.toMarkdownTexts(): List<String> = createMarkdownText(
this,
textLength.last
)
fun TextContent.toMarkdownTexts(): List<String> = fullEntitiesList().toMarkdownTexts()
fun FullTextSourcesList.toMarkdownExplanations(): List<String> = createMarkdownText(
this,
explanationLimit.last
)
fun ExplainedInput.toMarkdownExplanations(): List<String> = fullEntitiesList().toMarkdownTexts()
fun createMarkdownV2Text(
entities: FullTextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, MarkdownV2ParseMode)
fun FullTextSourcesList.toMarkdownV2Captions(): List<String> = createMarkdownV2Text(
this,
captionLength.last
)
fun CaptionedInput.toMarkdownV2Captions(): List<String> = fullEntitiesList().toMarkdownV2Captions()
fun FullTextSourcesList.toMarkdownV2Texts(): List<String> = createMarkdownV2Text(
this,
textLength.last
)
fun TextContent.toMarkdownV2Texts(): List<String> = fullEntitiesList().toMarkdownV2Texts()
fun FullTextSourcesList.toMarkdownV2Explanations(): List<String> = createMarkdownV2Text(
this,
explanationLimit.last
)
fun ExplainedInput.toMarkdownV2Explanations(): List<String> = fullEntitiesList().toMarkdownV2Texts()
fun createHtmlText(
entities: FullTextSourcesList,
partLength: Int = textLength.last
): List<String> = createFormattedText(entities, partLength, HTMLParseMode)
fun FullTextSourcesList.toHtmlCaptions(): List<String> = createHtmlText(
this,
captionLength.last
)
fun CaptionedInput.toHtmlCaptions(): List<String> = fullEntitiesList().toHtmlCaptions()
fun FullTextSourcesList.toHtmlTexts(): List<String> = createHtmlText(
this,
textLength.last
)
fun TextContent.toHtmlTexts(): List<String> = fullEntitiesList().toHtmlTexts()
fun FullTextSourcesList.toHtmlExplanations(): List<String> = createHtmlText(
this,
explanationLimit.last
)
fun ExplainedInput.toHtmlExplanations(): List<String> = fullEntitiesList().toHtmlTexts()

View File

@@ -0,0 +1,243 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.formatting
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.*
const val markdownBoldControl = "*"
const val markdownItalicControl = "_"
const val markdownCodeControl = "`"
const val markdownPreControl = "```"
const val markdownV2ItalicUnderlineDelimiter = "\u0013"
const val markdownV2StrikethroughControl = "~"
const val markdownV2UnderlineControl = "__"
const val markdownV2UnderlineEndControl = "$markdownV2UnderlineControl$markdownV2ItalicUnderlineDelimiter"
const val markdownV2ItalicEndControl = "$markdownItalicControl$markdownV2ItalicUnderlineDelimiter"
const val htmlBoldControl = "b"
const val htmlItalicControl = "i"
const val htmlCodeControl = "code"
const val htmlPreControl = "pre"
const val htmlUnderlineControl = "u"
const val htmlStrikethroughControl = "s"
private fun String.markdownDefault(
openControlSymbol: String,
closeControlSymbol: String = openControlSymbol
) = "$openControlSymbol${toMarkdown()}$closeControlSymbol"
private fun String.markdownV2Default(
openControlSymbol: String,
closeControlSymbol: String = openControlSymbol,
escapeFun: String.() -> String = String::escapeMarkdownV2Common
) = "$openControlSymbol${escapeFun()}$closeControlSymbol"
private fun String.htmlDefault(
openControlSymbol: String,
closeControlSymbol: String = openControlSymbol
) = "<$openControlSymbol>${toHtml()}</$closeControlSymbol>"
fun String.linkMarkdown(link: String): String = "[${toMarkdown()}](${link.toMarkdown()})"
fun String.linkMarkdownV2(link: String): String = "[${escapeMarkdownV2Common()}](${link.escapeMarkdownV2Link()})"
fun String.linkHTML(link: String): String = "<a href=\"$link\">${toHtml()}</a>"
fun String.boldMarkdown(): String = markdownDefault(markdownBoldControl)
fun String.boldMarkdownV2(): String = markdownV2Default(markdownBoldControl)
fun String.boldHTML(): String = htmlDefault(htmlBoldControl)
fun String.italicMarkdown(): String = markdownDefault(markdownItalicControl)
fun String.italicMarkdownV2(): String = markdownV2Default(markdownItalicControl, markdownV2ItalicEndControl)
fun String.italicHTML(): String = htmlDefault(htmlItalicControl)
/**
* Crutch for support of strikethrough in default markdown. Simply add modifier, but it will not look like correct
*/
fun String.strikethroughMarkdown(): String = map { it + "\u0336" }.joinToString("")
fun String.strikethroughMarkdownV2(): String = markdownV2Default(markdownV2StrikethroughControl)
fun String.strikethroughHTML(): String = htmlDefault(htmlStrikethroughControl)
/**
* Crutch for support of underline in default markdown. Simply add modifier, but it will not look like correct
*/
fun String.underlineMarkdown(): String = map { it + "\u0347" }.joinToString("")
fun String.underlineMarkdownV2(): String = markdownV2Default(markdownV2UnderlineControl, markdownV2UnderlineEndControl)
fun String.underlineHTML(): String = htmlDefault(htmlUnderlineControl)
fun String.codeMarkdown(): String = markdownDefault(markdownCodeControl)
fun String.codeMarkdownV2(): String = markdownV2Default(markdownCodeControl, escapeFun = String::escapeMarkdownV2PreAndCode)
fun String.codeHTML(): String = htmlDefault(htmlCodeControl)
fun String.preMarkdown(language: String? = null): String = markdownDefault(
"$markdownPreControl${language ?: ""}\n",
"\n$markdownPreControl"
)
fun String.preMarkdownV2(language: String? = null): String = markdownV2Default(
"$markdownPreControl${language ?: ""}\n",
"\n$markdownPreControl",
String::escapeMarkdownV2PreAndCode
)
fun String.preHTML(language: String? = null): String = htmlDefault(
language ?.let {
"$htmlPreControl><$htmlCodeControl class=\"language-$language\""
} ?: htmlPreControl,
language ?.let {
"$htmlCodeControl></$htmlPreControl"
} ?: htmlPreControl
)
fun String.emailMarkdown(): String = linkMarkdown("mailto://$${toMarkdown()}")
fun String.emailMarkdownV2(): String = linkMarkdownV2("mailto://$${toMarkdown()}")
fun String.emailHTML(): String = linkHTML("mailto://$${toHtml()}")
private inline fun String.mention(adapt: String.() -> String): String = if (startsWith("@")) {
adapt()
} else {
"@${adapt()}"
}
private inline fun String.hashTag(adapt: String.() -> String): String = if (startsWith("#")) {
adapt()
} else {
"#${adapt()}"
}
fun String.textMentionMarkdown(userId: UserId): String = linkMarkdown(userId.link)
fun String.textMentionMarkdownV2(userId: UserId): String = linkMarkdownV2(userId.link)
fun String.textMentionHTML(userId: UserId): String = linkHTML(userId.link)
fun String.mentionMarkdown(): String = mention(String::toMarkdown)
fun String.mentionMarkdownV2(): String = mention(String::escapeMarkdownV2Common)
fun String.mentionHTML(): String = mention(String::toHtml)
fun String.hashTagMarkdown(): String = hashTag(String::toMarkdown)
fun String.hashTagMarkdownV2(): String = hashTag(String::escapeMarkdownV2Common).escapeMarkdownV2Common()
fun String.hashTagHTML(): String = hashTag(String::toHtml)
fun String.phoneMarkdown(): String = toMarkdown()
fun String.phoneMarkdownV2(): String = escapeMarkdownV2Common()
fun String.phoneHTML(): String = toHtml()
fun String.command(adapt: String.() -> String): String = if (startsWith("/")) {
adapt()
} else {
"/${adapt()}"
}
fun String.commandMarkdown(): String = command(String::toMarkdown)
fun String.commandMarkdownV2(): String = command(String::escapeMarkdownV2Common)
fun String.commandHTML(): String = command(String::toHtml)
fun String.regularMarkdown(): String = toMarkdown()
fun String.regularMarkdownV2(): String = escapeMarkdownV2Common()
fun String.regularHtml(): String = toHtml()
fun String.cashTagMarkdown(): String = toMarkdown()
fun String.cashTagMarkdownV2(): String = escapeMarkdownV2Common()
fun String.cashTagHtml(): String = toHtml()
infix fun String.bold(parseMode: ParseMode): String = when (parseMode) {
is HTML -> boldHTML()
is Markdown -> boldMarkdown()
is MarkdownV2 -> boldMarkdownV2()
}
infix fun String.italic(parseMode: ParseMode): String = when (parseMode) {
is HTML -> italicHTML()
is Markdown -> italicMarkdown()
is MarkdownV2 -> italicMarkdownV2()
}
infix fun String.hashTag(parseMode: ParseMode): String = when (parseMode) {
is HTML -> hashTagHTML()
is Markdown -> hashTagMarkdown()
is MarkdownV2 -> hashTagMarkdownV2()
}
infix fun String.code(parseMode: ParseMode): String = when (parseMode) {
is HTML -> codeHTML()
is Markdown -> codeMarkdown()
is MarkdownV2 -> codeMarkdownV2()
}
fun String.pre(parseMode: ParseMode, language: String? = null): String = when (parseMode) {
is HTML -> preHTML(language)
is Markdown -> preMarkdown(language)
is MarkdownV2 -> preMarkdownV2(language)
}
infix fun String.pre(parseMode: ParseMode): String = pre(parseMode, null)
infix fun String.email(parseMode: ParseMode): String = when (parseMode) {
is HTML -> emailHTML()
is Markdown -> emailMarkdown()
is MarkdownV2 -> emailMarkdownV2()
}
infix fun Pair<String, String>.link(parseMode: ParseMode): String = when (parseMode) {
is HTML -> first.linkHTML(second)
is Markdown -> first.linkMarkdown(second)
is MarkdownV2 -> first.linkMarkdownV2(second)
}
infix fun String.mention(parseMode: ParseMode): String = when (parseMode) {
is HTML -> mentionHTML()
is Markdown -> mentionMarkdown()
is MarkdownV2 -> mentionMarkdownV2()
}
infix fun Pair<String, ChatId>.mention(parseMode: ParseMode): String = when (parseMode) {
is HTML -> first.textMentionHTML(second)
is Markdown -> first.textMentionMarkdown(second)
is MarkdownV2 -> first.textMentionMarkdownV2(second)
}
infix fun String.phone(parseMode: ParseMode): String = when (parseMode) {
is HTML -> phoneHTML()
is Markdown -> phoneMarkdown()
is MarkdownV2 -> phoneMarkdownV2()
}
infix fun String.command(parseMode: ParseMode): String = when (parseMode) {
is HTML -> commandHTML()
is Markdown -> commandMarkdown()
is MarkdownV2 -> commandMarkdownV2()
}
infix fun String.underline(parseMode: ParseMode): String = when (parseMode) {
is HTML -> underlineHTML()
is Markdown -> underlineMarkdown()
is MarkdownV2 -> underlineMarkdownV2()
}
infix fun String.strikethrough(parseMode: ParseMode): String = when (parseMode) {
is HTML -> strikethroughHTML()
is Markdown -> strikethroughMarkdown()
is MarkdownV2 -> strikethroughMarkdownV2()
}
infix fun String.regular(parseMode: ParseMode): String = when (parseMode) {
is HTML -> regularHtml()
is Markdown -> regularMarkdown()
is MarkdownV2 -> regularMarkdownV2()
}
infix fun String.cashtag(parseMode: ParseMode): String = when (parseMode) {
is HTML -> cashTagHtml()
is Markdown -> cashTagMarkdown()
is MarkdownV2 -> cashTagMarkdownV2()
}

View File

@@ -0,0 +1,56 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.SendMediaGroup
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.message.ForwardInfo
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.SentMediaGroupUpdate
val List<MediaGroupMessage>.forwardInfo: ForwardInfo?
get() = firstOrNull() ?.forwardInfo
val List<MediaGroupMessage>.replyTo: Message?
get() = firstOrNull() ?.replyTo
val List<MediaGroupMessage>.chat: Chat?
get() = firstOrNull() ?.chat
val List<MediaGroupMessage>.mediaGroupId: MediaGroupIdentifier?
get() = firstOrNull() ?.mediaGroupId
val SentMediaGroupUpdate.forwardInfo: ForwardInfo?
get() = data.first().forwardInfo
val SentMediaGroupUpdate.replyTo: Message?
get() = data.first().replyTo
val SentMediaGroupUpdate.chat: Chat
get() = data.chat!!
val SentMediaGroupUpdate.mediaGroupId: MediaGroupIdentifier
get() = data.mediaGroupId!!
fun List<MediaGroupMessage>.createResend(
chatId: ChatId,
disableNotification: Boolean = false,
replyTo: MessageIdentifier? = null
) = SendMediaGroup(
chatId,
map { it.content.toMediaGroupMemberInputMedia() },
disableNotification,
replyTo
)
fun List<MediaGroupMessage>.createResend(
chat: Chat,
disableNotification: Boolean = false,
replyTo: MessageIdentifier? = null
) = createResend(
chat.id,
disableNotification,
replyTo
)
fun SentMediaGroupUpdate.createResend(
disableNotification: Boolean = false,
replyTo: MessageIdentifier? = null
) = data.createResend(
chat,
disableNotification,
replyTo
)

View File

@@ -0,0 +1,35 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
import com.github.insanusmokrassar.TelegramBotAPI.types.LongSeconds
import com.github.insanusmokrassar.TelegramBotAPI.types.Seconds
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ApproximateScheduledCloseInfo
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.ExactScheduledCloseInfo
import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
fun closePollExactAt(
dateTime: DateTime
) = ExactScheduledCloseInfo(
dateTime
)
fun closePollExactAfter(
seconds: LongSeconds
) = closePollExactAt(
DateTime.now() + TimeSpan(seconds.toDouble() * 1000L)
)
fun closePollExactAfter(
seconds: Seconds
) = closePollExactAfter(
seconds.toLong()
)
fun closePollAfter(
seconds: LongSeconds
) = ApproximateScheduledCloseInfo(
TimeSpan(seconds.toDouble() * 1000L)
)
fun closePollAfter(
seconds: Seconds
) = closePollAfter(seconds.toLong())

View File

@@ -0,0 +1,45 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
import kotlinx.coroutines.*
fun <T: Any> RequestsExecutor.executeAsync(
request: Request<T>,
scope: CoroutineScope
): Deferred<T> = scope.async {
handleSafely {
execute(request)
}
}
suspend fun <T: Any> RequestsExecutor.executeAsync(
request: Request<T>
): Deferred<T> = coroutineScope {
executeAsync(request, this)
}
suspend fun <T: Any> RequestsExecutor.executeUnsafe(
request: Request<T>,
retries: Int = 0,
retriesDelay: Long = 1000L,
onAllFailed: (suspend (exceptions: Array<Exception>) -> Unit)? = null
): T? {
var leftRetries = retries
val exceptions = onAllFailed ?.let { mutableListOf<Exception>() }
do {
return handleSafely(
{
leftRetries--
delay(retriesDelay)
exceptions ?.add(it)
null
}
) {
execute(request)
} ?: continue
} while(leftRetries >= 0)
onAllFailed ?.invoke(exceptions ?.toTypedArray() ?: emptyArray())
return null
}

View File

@@ -0,0 +1,49 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
fun Flow<Update>.onlyBaseMessageUpdates(): Flow<BaseMessageUpdate> = mapNotNull {
it as? BaseMessageUpdate
}
/**
* Converts flow to [Flow] of [BaseSentMessageUpdate]
*/
fun Flow<BaseMessageUpdate>.onlySentMessageUpdates(): Flow<BaseSentMessageUpdate> = mapNotNull {
it as? BaseSentMessageUpdate
}
/**
* Converts flow to [Flow] of [BaseSentMessageUpdate]
*/
fun Flow<BaseMessageUpdate>.onlyEditMessageUpdates(): Flow<BaseEditMessageUpdate> = mapNotNull {
it as? BaseEditMessageUpdate
}
/**
* Converts flow to [Flow] of [MediaGroupUpdate]. Please, remember that it could be either [EditMediaGroupUpdate]
* or [SentMediaGroupUpdate]
*
* @see onlySentMediaGroupUpdates
* @see onlyEditMediaGroupUpdates
*/
fun Flow<BaseMessageUpdate>.onlyMediaGroupsUpdates(): Flow<MediaGroupUpdate> = mapNotNull {
it as? MediaGroupUpdate
}
/**
* Converts flow to [Flow] of [SentMediaGroupUpdate]
*/
fun Flow<MediaGroupUpdate>.onlySentMediaGroupUpdates(): Flow<SentMediaGroupUpdate> = mapNotNull {
it as? SentMediaGroupUpdate
}
/**
* Converts flow to [Flow] of [EditMediaGroupUpdate]
*/
fun Flow<MediaGroupUpdate>.onlyEditMediaGroupUpdates(): Flow<EditMediaGroupUpdate> = mapNotNull {
it as? EditMediaGroupUpdate
}

View File

@@ -0,0 +1,25 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.CallbackQueryUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
/**
* @return New [Flow] with [DataCallbackQuery] type, got from [CallbackQueryUpdate.data] field
*/
fun Flow<CallbackQueryUpdate>.asDataCallbackQueryFlow() = mapNotNull {
it.data as? DataCallbackQuery
}
/**
* @return New [Flow] with [GameShortNameCallbackQuery] type, got from [CallbackQueryUpdate.data] field
*/
fun Flow<CallbackQueryUpdate>.asGameShortNameCallbackQueryFlow() = mapNotNull {
it.data as? GameShortNameCallbackQuery
}
/**
* @return New [Flow] with [UnknownCallbackQueryType] type, got from [CallbackQueryUpdate.data] field
*/
fun Flow<CallbackQueryUpdate>.asUnknownCallbackQueryFlow() = mapNotNull {
it.data as? UnknownCallbackQueryType
}

View File

@@ -0,0 +1,86 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.onlyTextContentMessages
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.BotCommandTextSource
import com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.fullEntitiesList
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.*
/**
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
* messages with [fullEntitiesList] and check that incoming message contains ONLY ONE [TextSource] and that is
* [BotCommandTextSource]. Besides, it is checking that [BotCommandTextSource.command] [Regex.matches] with incoming
* [commandRegex]
*
* @return The same message in case if it contains only [BotCommandTextSource] with [Regex.matches]
* [BotCommandTextSource.command]
*
* @see fullEntitiesList
* @see asContentMessagesFlow
* @see onlyTextContentMessages
*/
fun <T : BaseSentMessageUpdate> Flow<T>.filterExactCommands(
commandRegex: Regex
) = asContentMessagesFlow().onlyTextContentMessages().filter { contentMessage ->
(contentMessage.content.fullEntitiesList().singleOrNull() as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
/**
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
* messages with [fullEntitiesList] and check that incoming message contains [BotCommandTextSource]. Besides, it is
* checking that [BotCommandTextSource.command] [Regex.matches] with incoming [commandRegex]
*
* @return The same message in case if it contains somewhere in text [BotCommandTextSource] with [Regex.matches]
* [BotCommandTextSource.command]
*
* @see fullEntitiesList
* @see asContentMessagesFlow
* @see onlyTextContentMessages
*/
fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsInsideTextMessages(
commandRegex: Regex
) = asContentMessagesFlow().onlyTextContentMessages().filter { contentMessage ->
contentMessage.content.fullEntitiesList().any {
(it as? BotCommandTextSource) ?.let { commandRegex.matches(it.command) } == true
}
}
/**
* Convert incoming [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage.content] of
* messages with [fullEntitiesList] and check that incoming message contains first [TextSource] as
* [BotCommandTextSource]. Besides, it is checking that [BotCommandTextSource.command] [Regex.matches] with incoming
* [commandRegex] and for other [TextSource] objects used next rules: all incoming text sources will be passed as is,
* [RegularTextSource] will be split by " " for several [RegularTextSource] which will contains not empty args without
* spaces.
*
* @return Converted list with first entity [BotCommandTextSource] and than all others according to rules in description
*
* @see fullEntitiesList
* @see asContentMessagesFlow
* @see onlyTextContentMessages
*/
fun <T : BaseSentMessageUpdate> Flow<T>.filterCommandsWithArgs(
commandRegex: Regex
): Flow<List<TextSource>> = asContentMessagesFlow().onlyTextContentMessages().mapNotNull { contentMessage ->
val allEntities = contentMessage.content.fullEntitiesList()
(allEntities.firstOrNull() as? BotCommandTextSource) ?.let {
if (commandRegex.matches(it.command)) {
allEntities.flatMap {
when (it) {
is RegularTextSource -> it.source.split(" ").mapNotNull { regularTextSourcePart ->
if (regularTextSourcePart.isNotBlank()) {
RegularTextSource(regularTextSourcePart)
} else {
null
}
}
else -> listOf(it)
}
}
} else {
null
}
}
}

View File

@@ -0,0 +1,17 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter
/**
* Non-suspendable function for easy-to-use creating of [FlowsUpdatesFilter] and applying the block to it
*
* @see flowsUpdatesFilter
*/
inline fun flowsUpdatesFilter(
internalChannelsSizes: Int = 64,
block: FlowsUpdatesFilter.() -> Unit
): FlowsUpdatesFilter {
val filter = FlowsUpdatesFilter(internalChannelsSizes)
filter.block()
return filter
}

View File

@@ -0,0 +1,27 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseSentMessageUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.mapNotNull
/**
* Will map incoming [BaseSentMessageUpdate]s to [ContentMessage] from [BaseSentMessageUpdate.data]
*/
fun <T : BaseSentMessageUpdate> Flow<T>.asContentMessagesFlow() = mapNotNull {
it.data as? ContentMessage<*>
}
/**
* Will map incoming [BaseSentMessageUpdate]s to [ChatEventMessage] from [BaseSentMessageUpdate.data]
*/
fun <T : BaseSentMessageUpdate> Flow<T>.asChatEventsFlow() = mapNotNull {
it.data as? ChatEventMessage
}
/**
* Will map incoming [BaseSentMessageUpdate]s to [UnknownMessageType] from [BaseSentMessageUpdate.data]
*/
fun <T : BaseSentMessageUpdate> Flow<T>.asUnknownMessagesFlow() = mapNotNull {
it.data as? UnknownMessageType
}

View File

@@ -0,0 +1,31 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.nonstrictJsonFormat
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateDeserializationStrategy
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
/**
* @return Deserialize [source] as [com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update]
*/
fun Json.toTelegramUpdate(source: String) = parse(UpdateDeserializationStrategy, source)
/**
* @return Deserialize [source] as [com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update]
*/
fun Json.toTelegramUpdate(source: JsonElement) = fromJson(UpdateDeserializationStrategy, source)
/**
* @return Deserialize [this] as [com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update]. In fact,
* it is must be JSON
*
* @see Json.toTelegramUpdate
*/
fun String.toTelegramUpdate() = nonstrictJsonFormat.toTelegramUpdate(this)
/**
* @return Deserialize [this] as [com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update]
*
* @see Json.toTelegramUpdate
*/
fun JsonElement.toTelegramUpdate() = nonstrictJsonFormat.toTelegramUpdate(this)

View File

@@ -0,0 +1,47 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.ChatId
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.SentMediaGroupUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
/**
* [Flow.filter] incoming [BaseMessageUpdate]s by their [ChatId]
*/
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdatesByChatId(chatId: ChatId): Flow<T> = filter { it.data.chat.id == chatId }
/**
* [Flow.filter] incoming [BaseMessageUpdate]s by their [ChatId] using [Chat.id] of [chat]
*/
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdatesByChat(chat: Chat): Flow<T> = filterBaseMessageUpdatesByChatId(chat.id)
/**
* [Flow.filter] incoming [BaseMessageUpdate]s by their [ChatId]
*/
@Deprecated("Renamed", ReplaceWith("filterBaseMessageUpdatesByChatId"))
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdates(chatId: ChatId): Flow<T> = filterBaseMessageUpdatesByChatId(chatId)
/**
* [Flow.filter] incoming [BaseMessageUpdate]s by their [ChatId] using [Chat.id] of [chat]
*/
@Deprecated("Renamed", ReplaceWith("filterBaseMessageUpdatesByChat"))
fun <T : BaseMessageUpdate> Flow<T>.filterBaseMessageUpdates(chat: Chat): Flow<T> = filterBaseMessageUpdatesByChatId(chat.id)
/**
* [Flow.filter] incoming [SentMediaGroupUpdate]s by their [ChatId]
*/
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdatesByChatId(chatId: ChatId): Flow<T> = filter { it.data.first().chat.id == chatId }
/**
* [Flow.filter] incoming [SentMediaGroupUpdate]s by their [ChatId] using [Chat.id] of [chat]
*/
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdatesByChat(chat: Chat): Flow<T> = filterSentMediaGroupUpdatesByChatId(chat.id)
/**
* [Flow.filter] incoming [SentMediaGroupUpdate]s by their [ChatId]
*/
@Deprecated("Renamed", ReplaceWith("filterSentMediaGroupUpdatesByChatId"))
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdates(chatId: ChatId): Flow<T> = filterSentMediaGroupUpdatesByChatId(chatId)
/**
* [Flow.filter] incoming [SentMediaGroupUpdate]s by their [ChatId] using [Chat.id] of [chat]
*/
@Deprecated("Renamed", ReplaceWith("filterSentMediaGroupUpdatesByChat"))
fun <T : SentMediaGroupUpdate> Flow<T>.filterSentMediaGroupUpdates(chat: Chat): Flow<T> = filterSentMediaGroupUpdatesByChatId(chat.id)

View File

@@ -0,0 +1,93 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates
import com.github.insanusmokrassar.TelegramBotAPI.types.MediaGroupIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.*
/**
* @return If [this] is [SentMediaGroupUpdate] - [Update.updateId] of [last] element, or its own [Update.updateId]
*/
fun Update.lastUpdateIdentifier(): UpdateIdentifier {
return if (this is SentMediaGroupUpdate) {
origins.last().updateId
} else {
updateId
}
}
/**
* @return The biggest [UpdateIdentifier] OR null
*
* @see [Update.lastUpdateIdentifier]
*/
fun List<Update>.lastUpdateIdentifier(): UpdateIdentifier? {
return maxBy { it.updateId } ?.lastUpdateIdentifier()
}
/**
* Will convert incoming list of updates to list with [MediaGroupUpdate]s
*/
fun List<Update>.convertWithMediaGroupUpdates(): List<Update> {
val resultUpdates = mutableListOf<Update>()
val mediaGroups = mutableMapOf<MediaGroupIdentifier, MutableList<BaseSentMessageUpdate>>()
for (update in this) {
val data = (update.data as? MediaGroupMessage)
if (data == null) {
resultUpdates.add(update)
continue
}
when (update) {
is BaseEditMessageUpdate -> resultUpdates.add(
update.toEditMediaGroupUpdate()
)
is BaseSentMessageUpdate -> {
mediaGroups.getOrPut(data.mediaGroupId) {
mutableListOf()
}.add(update)
}
else -> resultUpdates.add(update)
}
}
mediaGroups.values.map {
it.toSentMediaGroupUpdate() ?.let { mediaGroupUpdate ->
resultUpdates.add(mediaGroupUpdate)
}
}
resultUpdates.sortBy { it.updateId }
return resultUpdates
}
/**
* @receiver List of [BaseSentMessageUpdate] where [BaseSentMessageUpdate.data] is [MediaGroupMessage] and all messages
* have the same [MediaGroupMessage.mediaGroupId]
* @return [MessageMediaGroupUpdate] in case if [first] object of [this] is [MessageUpdate]. When [first] object is
* [ChannelPostUpdate] instance - will return [ChannelPostMediaGroupUpdate]. Otherwise will be returned null
*/
fun List<BaseSentMessageUpdate>.toSentMediaGroupUpdate(): SentMediaGroupUpdate? = (this as? SentMediaGroupUpdate) ?: let {
if (isEmpty()) {
return@let null
}
val resultList = sortedBy { it.updateId }
when (first()) {
is MessageUpdate -> MessageMediaGroupUpdate(resultList)
is ChannelPostUpdate -> ChannelPostMediaGroupUpdate(resultList)
else -> null
}
}
/**
* @return [EditMessageMediaGroupUpdate] in case if [this] is [EditMessageUpdate]. When [this] object is
* [EditChannelPostUpdate] instance - will return [EditChannelPostMediaGroupUpdate]
*
* @throws IllegalStateException
*/
fun BaseEditMessageUpdate.toEditMediaGroupUpdate(): EditMediaGroupUpdate = (this as? EditMediaGroupUpdate) ?: let {
when (this) {
is EditMessageUpdate -> EditMessageMediaGroupUpdate(this)
is EditChannelPostUpdate -> EditChannelPostMediaGroupUpdate(this)
else -> error("Unsupported type of ${BaseEditMessageUpdate::class.simpleName}")
}
}

View File

@@ -0,0 +1,180 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.retrieving
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.RequestException
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.convertWithMediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.lastUpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.*
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import kotlinx.coroutines.*
fun RequestsExecutor.startGettingOfUpdatesByLongPolling(
timeoutSeconds: Seconds = 30,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: (ExceptionHandler<Unit>)? = null,
allowedUpdates: List<String>? = null,
updatesReceiver: UpdateReceiver<Update>
): Job = scope.launch {
var lastUpdateIdentifier: UpdateIdentifier? = null
while (isActive) {
handleSafely(
{ e ->
exceptionsHandler ?.invoke(e)
if (e is RequestException) {
delay(1000L)
}
}
) {
val updates = execute(
GetUpdates(
offset = lastUpdateIdentifier?.plus(1),
timeout = timeoutSeconds,
allowed_updates = allowedUpdates
)
).let { originalUpdates ->
val converted = originalUpdates.convertWithMediaGroupUpdates()
/**
* Dirty hack for cases when the media group was retrieved not fully:
*
* We are throw out the last media group and will reretrieve it again in the next get updates
* and it will guarantee that it is full
*/
if (originalUpdates.size == getUpdatesLimit.last && converted.last() is SentMediaGroupUpdate) {
converted - converted.last()
} else {
converted
}
}
handleSafely {
for (update in updates) {
updatesReceiver(update)
lastUpdateIdentifier = update.lastUpdateIdentifier()
}
}
}
}
}
/**
* This method will create a new one [FlowsUpdatesFilter]. This method could be unsafe due to the fact that it will start
* getting updates IMMEDIATELY. That means that your bot will be able to skip some of them until you will call
* [kotlinx.coroutines.flow.Flow.collect] on one of [FlowsUpdatesFilter] flows. To avoid it, you can pass
* [flowUpdatesPreset] lambda - it will be called BEFORE starting updates getting
*/
@FlowPreview
@PreviewFeature
@Suppress("unused")
fun RequestsExecutor.startGettingFlowsUpdatesByLongPolling(
timeoutSeconds: Seconds = 30,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default),
exceptionsHandler: ExceptionHandler<Unit>? = null,
flowsUpdatesFilterUpdatesKeeperCount: Int = 64,
flowUpdatesPreset: FlowsUpdatesFilter.() -> Unit = {}
): FlowsUpdatesFilter = FlowsUpdatesFilter(flowsUpdatesFilterUpdatesKeeperCount).apply {
flowUpdatesPreset()
startGettingOfUpdatesByLongPolling(timeoutSeconds, scope, exceptionsHandler, allowedUpdates, asUpdateReceiver)
}
fun RequestsExecutor.startGettingOfUpdatesByLongPolling(
updatesFilter: UpdatesFilter,
timeoutSeconds: Seconds = 30,
exceptionsHandler: ExceptionHandler<Unit>? = null,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
): Job = startGettingOfUpdatesByLongPolling(
timeoutSeconds,
scope,
exceptionsHandler,
updatesFilter.allowedUpdates,
updatesFilter.asUpdateReceiver
)
fun RequestsExecutor.startGettingOfUpdatesByLongPolling(
messageCallback: UpdateReceiver<MessageUpdate>? = null,
messageMediaGroupCallback: UpdateReceiver<MessageMediaGroupUpdate>? = null,
editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
editedMessageMediaGroupCallback: UpdateReceiver<EditMessageMediaGroupUpdate>? = null,
channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
channelPostMediaGroupCallback: UpdateReceiver<ChannelPostMediaGroupUpdate>? = null,
editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
editedChannelPostMediaGroupCallback: UpdateReceiver<EditChannelPostMediaGroupUpdate>? = null,
chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null,
pollCallback: UpdateReceiver<PollUpdate>? = null,
pollAnswerCallback: UpdateReceiver<PollAnswerUpdate>? = null,
timeoutSeconds: Seconds = 30,
exceptionsHandler: ExceptionHandler<Unit>? = null,
scope: CoroutineScope = GlobalScope
): Job {
return startGettingOfUpdatesByLongPolling(
SimpleUpdatesFilter(
messageCallback,
messageMediaGroupCallback,
editedMessageCallback,
editedMessageMediaGroupCallback,
channelPostCallback,
channelPostMediaGroupCallback,
editedChannelPostCallback,
editedChannelPostMediaGroupCallback,
chosenInlineResultCallback,
inlineQueryCallback,
callbackQueryCallback,
shippingQueryCallback,
preCheckoutQueryCallback,
pollCallback,
pollAnswerCallback
),
timeoutSeconds,
exceptionsHandler,
scope
)
}
@Suppress("unused")
fun RequestsExecutor.startGettingOfUpdatesByLongPolling(
messageCallback: UpdateReceiver<MessageUpdate>? = null,
mediaGroupCallback: UpdateReceiver<MediaGroupUpdate>? = null,
editedMessageCallback: UpdateReceiver<EditMessageUpdate>? = null,
channelPostCallback: UpdateReceiver<ChannelPostUpdate>? = null,
editedChannelPostCallback: UpdateReceiver<EditChannelPostUpdate>? = null,
chosenInlineResultCallback: UpdateReceiver<ChosenInlineResultUpdate>? = null,
inlineQueryCallback: UpdateReceiver<InlineQueryUpdate>? = null,
callbackQueryCallback: UpdateReceiver<CallbackQueryUpdate>? = null,
shippingQueryCallback: UpdateReceiver<ShippingQueryUpdate>? = null,
preCheckoutQueryCallback: UpdateReceiver<PreCheckoutQueryUpdate>? = null,
pollCallback: UpdateReceiver<PollUpdate>? = null,
pollAnswerCallback: UpdateReceiver<PollAnswerUpdate>? = null,
timeoutSeconds: Seconds = 30,
exceptionsHandler: ExceptionHandler<Unit>? = null,
scope: CoroutineScope = CoroutineScope(Dispatchers.Default)
): Job = startGettingOfUpdatesByLongPolling(
messageCallback = messageCallback,
messageMediaGroupCallback = mediaGroupCallback,
editedMessageCallback = editedMessageCallback,
editedMessageMediaGroupCallback = mediaGroupCallback,
channelPostCallback = channelPostCallback,
channelPostMediaGroupCallback = mediaGroupCallback,
editedChannelPostCallback = editedChannelPostCallback,
editedChannelPostMediaGroupCallback = mediaGroupCallback,
chosenInlineResultCallback = chosenInlineResultCallback,
inlineQueryCallback = inlineQueryCallback,
callbackQueryCallback = callbackQueryCallback,
shippingQueryCallback = shippingQueryCallback,
preCheckoutQueryCallback = preCheckoutQueryCallback,
pollCallback = pollCallback,
pollAnswerCallback = pollAnswerCallback,
timeoutSeconds = timeoutSeconds,
exceptionsHandler = exceptionsHandler,
scope = scope
)

View File

@@ -0,0 +1,60 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.retrieving
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.convertWithMediaGroupUpdates
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.BaseMessageUpdate
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver
import com.github.insanusmokrassar.TelegramBotAPI.utils.extensions.accumulateByKey
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
/**
* Create [UpdateReceiver] object which will correctly accumulate updates and send into output updates which INCLUDE
* [com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.MediaGroupUpdate]s.
*
* @see UpdateReceiver
*/
fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
output: UpdateReceiver<Update>,
debounceTimeMillis: Long = 1000L
): UpdateReceiver<Update> {
val updatesChannel = Channel<Update>(Channel.UNLIMITED)
val mediaGroupChannel = Channel<Pair<String, BaseMessageUpdate>>(Channel.UNLIMITED)
val mediaGroupAccumulatedChannel = mediaGroupChannel.accumulateByKey(
debounceTimeMillis,
scope = this
)
launch {
launch {
for (update in updatesChannel) {
when (val data = update.data) {
is MediaGroupMessage -> mediaGroupChannel.send("${data.mediaGroupId}${update::class.simpleName}" to update as BaseMessageUpdate)
else -> output(update)
}
}
}
launch {
for ((_, mediaGroup) in mediaGroupAccumulatedChannel) {
mediaGroup.convertWithMediaGroupUpdates().forEach {
output(it)
}
}
}
}
return { updatesChannel.send(it) }
}
/**
* Create [UpdateReceiver] object which will correctly accumulate updates and send into output updates which INCLUDE
* [com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.MediaGroupUpdate]s.
*
* @see UpdateReceiver
*/
fun CoroutineScope.updateHandlerWithMediaGroupsAdaptation(
output: UpdateReceiver<Update>
) = updateHandlerWithMediaGroupsAdaptation(output, 1000L)

View File

@@ -0,0 +1,196 @@
package com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.retrieving
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.nonstrictJsonFormat
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.MultipartFile
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.media.base.MultipartRequestImpl
import com.github.insanusmokrassar.TelegramBotAPI.requests.webhook.SetWebhook
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateDeserializationStrategy
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdateReceiver
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.UpdatesFilter
import com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.webhook.WebhookPrivateKeyConfig
import com.github.insanusmokrassar.TelegramBotAPI.utils.ExceptionHandler
import com.github.insanusmokrassar.TelegramBotAPI.utils.handleSafely
import io.ktor.application.call
import io.ktor.request.receiveText
import io.ktor.response.respond
import io.ktor.routing.*
import io.ktor.server.engine.*
import kotlinx.coroutines.*
import java.util.concurrent.Executors
/**
* Allows to include webhook in custom route everywhere in your server
*
* @param [scope] Will be used for mapping of media groups
* @param [exceptionsHandler] Pass this parameter to set custom exception handler for getting updates
* @param [block] Some receiver block like [com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter]
*
* @see com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter
* @see UpdatesFilter
* @see UpdatesFilter.asUpdateReceiver
*/
fun Route.includeWebhookHandlingInRoute(
scope: CoroutineScope,
exceptionsHandler: ExceptionHandler<Unit>? = null,
block: UpdateReceiver<Update>
) {
val transformer = scope.updateHandlerWithMediaGroupsAdaptation(block)
post {
handleSafely(
exceptionsHandler ?: {}
) {
val asJson =
nonstrictJsonFormat.parseJson(call.receiveText())
val update = nonstrictJsonFormat.fromJson(
UpdateDeserializationStrategy,
asJson
)
transformer(update)
}
call.respond("Ok")
}
}
/**
* Setting up ktor server, set webhook info via [SetWebhook] request.
*
* @param listenPort port which will be listen by bot
* @param listenRoute address to listen by bot. If null - will be set up in root of host
* @param scope Scope which will be used for
* @param privateKeyConfig If configured - server will be created with [sslConnector]. [connector] will be used otherwise
*
* @see com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter
* @see UpdatesFilter
* @see UpdatesFilter.asUpdateReceiver
*/
fun startListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
exceptionsHandler: ExceptionHandler<Unit>,
listenHost: String = "0.0.0.0",
listenRoute: String? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
block: UpdateReceiver<Update>
): ApplicationEngine {
val env = applicationEngineEnvironment {
module {
routing {
listenRoute ?.also {
createRouteFromPath(it).includeWebhookHandlingInRoute(scope, exceptionsHandler, block)
} ?: includeWebhookHandlingInRoute(scope, exceptionsHandler, block)
}
}
privateKeyConfig ?.let {
sslConnector(
privateKeyConfig.keyStore,
privateKeyConfig.aliasName,
privateKeyConfig::keyStorePassword,
privateKeyConfig::aliasPassword
) {
host = listenHost
port = listenPort
}
} ?: connector {
host = listenHost
port = listenPort
}
}
return embeddedServer(engineFactory, env).also {
it.start(false)
}
}
private suspend fun RequestsExecutor.internalSetWebhookInfoAndStartListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
setWebhookRequest: Request<Boolean>,
exceptionsHandler: ExceptionHandler<Unit> = {},
listenHost: String = "0.0.0.0",
listenRoute: String? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
block: UpdateReceiver<Update>
): ApplicationEngine {
return try {
execute(setWebhookRequest)
startListenWebhooks(listenPort, engineFactory, exceptionsHandler, listenHost, listenRoute, privateKeyConfig, scope, block)
} catch (e: Exception) {
throw e
}
}
/**
* Setting up ktor server, set webhook info via [SetWebhook] request.
*
* @param listenPort port which will be listen by bot
* @param listenRoute address to listen by bot
* @param scope Scope which will be used for
*
* @see com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter
* @see UpdatesFilter
* @see UpdatesFilter.asUpdateReceiver
*/
@Suppress("unused")
suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
setWebhookRequest: SetWebhook,
exceptionsHandler: ExceptionHandler<Unit> = {},
listenHost: String = "0.0.0.0",
listenRoute: String = "/",
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
block: UpdateReceiver<Update>
): ApplicationEngine = internalSetWebhookInfoAndStartListenWebhooks(
listenPort,
engineFactory,
setWebhookRequest as Request<Boolean>,
exceptionsHandler,
listenHost,
listenRoute,
privateKeyConfig,
scope,
block
)
/**
* Setting up ktor server, set webhook info via [SetWebhook] request.
*
* @param listenPort port which will be listen by bot
* @param listenRoute address to listen by bot
* @param scope Scope which will be used for
*
* @see com.github.insanusmokrassar.TelegramBotAPI.updateshandlers.FlowsUpdatesFilter
* @see UpdatesFilter
* @see UpdatesFilter.asUpdateReceiver
*/
@Suppress("unused")
suspend fun RequestsExecutor.setWebhookInfoAndStartListenWebhooks(
listenPort: Int,
engineFactory: ApplicationEngineFactory<*, *>,
setWebhookRequest: MultipartRequestImpl<SetWebhook, Map<String, MultipartFile>, Boolean>,
exceptionsHandler: ExceptionHandler<Unit> = {},
listenHost: String = "0.0.0.0",
listenRoute: String? = null,
privateKeyConfig: WebhookPrivateKeyConfig? = null,
scope: CoroutineScope = CoroutineScope(Executors.newFixedThreadPool(4).asCoroutineDispatcher()),
block: UpdateReceiver<Update>
): ApplicationEngine = internalSetWebhookInfoAndStartListenWebhooks(
listenPort,
engineFactory,
setWebhookRequest as Request<Boolean>,
exceptionsHandler,
listenHost,
listenRoute,
privateKeyConfig,
scope,
block
)

View File

@@ -1,9 +1,7 @@
# TelegramBotAPI
[![Awesome Kotlin Badge](https://kotlin.link/awesome-kotlin.svg)](https://github.com/KotlinBy/awesome-kotlin)
[![Download](https://api.bintray.com/packages/insanusmokrassar/StandardRepository/TelegramBotAPI/images/download.svg) ](https://bintray.com/insanusmokrassar/StandardRepository/TelegramBotAPI/_latestVersion)
[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.insanusmokrassar/TelegramBotAPI)
[![Build Status](https://jenkins.insanusmokrassar.com/buildStatus/icon?job=TelegramBotAPI_master__publishing)](https://jenkins.insanusmokrassar.com/job/TelegramBotAPI_master__publishing/)
## What is it?
@@ -12,11 +10,10 @@ moments are describing by official [Telegram Bot API](https://core.telegram.org/
## Compatibility
This version compatible with [23th of January 2020 update of TelegramBotAPI (version 4.6)](https://core.telegram.org/bots/api#january-23-2020).
There is Telegram Passport API exception of implemented functionality, which was presented in
This version compatible with [24th of April 2020 update of TelegramBotAPI (version 4.8)](https://core.telegram.org/bots/api#april-24-2020).
There is only one exception of implemented functionality - Telegram Passport API, which was presented in
[August 2018 update of TelegramBotAPI](https://core.telegram.org/bots/api-changelog#august-27-2018) update. It will be implemented
as soon as possible. All APIs that are not included are presented
[wiki](https://github.com/InsanusMokrassar/TelegramBotAPI/wiki/Not-included-API).
as soon as possible.
## How to implement library?
@@ -69,9 +66,9 @@ compile "com.github.insanusmokrassar:TelegramBotAPI:$telegrambotapi_version"
For now, this library have no some API god-object. Instead of this, this library has several
important objects:
* [RequestsExecutor](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/RequestsExecutor.kt)
* [Requests](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests)
* [Types](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types)
* [RequestsExecutor](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/bot/RequestsExecutor.kt)
* [Requests](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests)
* [Types](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types)
### Types
@@ -98,16 +95,12 @@ val requestsExecutor: RequestsExecutor = ...
requestsExecutor.execute(GetMe())
```
Or you can use new syntax:
Also there is an alternative syntax for requests (like `requestsExecutor.getMe()` in project
[TelegramBotAPI-extensions-api](../TelegramBotAPI-extensions-api/README.md))
```kotlin
val bot: RequestsExecutor = ...
bot.getMe()
```
The result type of [GetMe (and getMe extension)](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests/GetMe.kt)
The result type of [GetMe (and getMe extension)](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/requests/GetMe.kt)
request is
[ExtendedBot](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types/User.kt).
[ExtendedBot](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/TelegramBotAPI/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/types/User.kt).
### RequestsExecutor
@@ -156,53 +149,3 @@ Here was used `okhttp` realisation of client, but there are several others engin
available on ktor.io site for [client](https://ktor.io/clients/http-client/engines.html) and [server](https://ktor.io/quickstart/artifacts.html)
engines.
## Getting updates
In this library currently realised two ways to get updates from telegram:
* Polling - in this case bot will request updates from time to time (you can set up delay between requests)
* Webhook via reverse proxy or something like this
### Updates filters
Currently webhook method contains `UpdatesFilter` as necessary argument for getting updates.
`UpdatesFilter` will sort updates and throw their into different callbacks. Currently supporting
separate getting updates for media groups - they are accumulating with debounce in one second
(for being sure that all objects of media group was received).
Updates polling also support `UpdatesFilter` but it is not required to use it and you can get updates directly
in `UpdateReceiver`, which you will provide to `startGettingOfUpdates` method
### Webhook set up
If you wish to use webhook method, you will need:
* White IP - your IP address or host, which available for calling. [TelegramBotAPI](https://core.telegram.org/bots/api#setwebhook)
recommend to use some unique address for each bot which you are using
* SSL certificate. Usually you can obtain the certificate using your domain provider, [Let'sEncrypt](https://letsencrypt.org/) or [create it](https://core.telegram.org/bots/self-signed)
* Nginx or something like this
Template for Nginx server config you can find in [this gist](https://gist.github.com/InsanusMokrassar/fcc6e09cebd07e46e8f0fdec234750c4#file-nginxssl-conf).
For webhook you can provide `File` with public part of certificate, `URL` where bot will be available and inner `PORT` which
will be used to start receiving of updates. Actually, you can skip passing of `File` when you have something like
nginx for proxy forwarding.
In case of using `nginx` with reverse-proxy config, setting up of Webhook will look like:
```kotlin
requestsExecutor.setWebhook(
WEBHOOK_URL,
INTERNAL_PORT,
filter,
ENGINE_FACTORY
)
```
Here:
* `WEBHOOK_URL` - the url which will be used by Telegram system to send updates
* `INTERNAL_PORT` - the port which will be used in bot for listening of updates
* `filter` - instance of [UpdatesFilter](https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/src/commonMain/kotlin/com/github/insanusmokrassar/TelegramBotAPI/updateshandlers/UpdatesFilter.kt),
which will be used to filter incoming updates
* `ENGINE_FACTORY` - used factory name, for example, `CIO` in case of usage `io.ktor:ktor-server-cio` as server engine

View File

@@ -18,7 +18,7 @@ plugins {
}
project.version = "$library_version"
project.group = "com.github.insanusmokrassar"
project.group = "$library_group"
apply from: "publish.gradle"
@@ -39,6 +39,7 @@ kotlin {
implementation kotlin('stdlib')
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-common:$kotlin_coroutines_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$kotlin_serialisation_runtime_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-properties-common:$kotlin_serialisation_runtime_version"
api "com.soywiz.korlibs.klock:klock:$klock_version"
api "com.benasher44:uuid:$uuid_version"
@@ -56,12 +57,15 @@ kotlin {
jvmMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime:$kotlin_serialisation_runtime_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-properties:$kotlin_serialisation_runtime_version"
api "io.ktor:ktor-client:$ktor_version"
api "io.ktor:ktor-server:$ktor_version"
api "io.ktor:ktor-server-host-common:$ktor_version"
api "io.ktor:ktor-client-cio:$ktor_version"
api "javax.activation:activation:$javax_activation_version"
}
}
jvmTest {
@@ -73,9 +77,18 @@ kotlin {
jsMain {
dependencies {
api "org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$kotlin_serialisation_runtime_version"
api "org.jetbrains.kotlinx:kotlinx-serialization-properties-js:$kotlin_serialisation_runtime_version"
api "org.jetbrains.kotlinx:kotlinx-coroutines-core-js:$kotlin_coroutines_version"
api "io.ktor:ktor-client-js:$ktor_version"
}
}
}
targets.all {
compilations.all {
kotlinOptions {
freeCompilerArgs += ["-Xuse-experimental=kotlinx.coroutines.ExperimentalCoroutinesApi", "-Xopt-in=kotlin.RequiresOptIn"]
}
}
}
}

View File

@@ -20,37 +20,33 @@ publishing {
publications.all {
artifact javadocsJar
pom.withXml {
asNode().children().last() + {
resolveStrategy = Closure.DELEGATE_FIRST
pom {
description = "Library for Object-Oriented and type-safe work with Telegram Bot API"
name = "Telegram Bot API"
url = "https://insanusmokrassar.github.io/TelegramBotAPI"
description "Library for Object-Oriented and type-safe work with Telegram Bot API"
name "Telegram Bot API"
url "https://insanusmokrassar.github.io/TelegramBotAPI"
scm {
developerConnection = "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url = "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
scm {
developerConnection "scm:git:[fetch=]https://github.com/insanusmokrassar/TelegramBotAPI.git[push=]https://github.com/insanusmokrassar/TelegramBotAPI.git"
url "https://github.com/insanusmokrassar/TelegramBotAPI.git"
}
developers {
developer {
id = "InsanusMokrassar"
name = "Ovsiannikov Aleksei"
email = "ovsyannikov.alexey95@gmail.com"
}
}
developers {
developer {
id "InsanusMokrassar"
name "Ovsiannikov Aleksei"
email "ovsyannikov.alexey95@gmail.com"
}
}
licenses {
license {
name "Apache Software License 2.0"
url "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
licenses {
license {
name = "Apache Software License 2.0"
url = "https://github.com/InsanusMokrassar/TelegramBotAPI/blob/master/LICENSE"
}
}
}
}

View File

@@ -12,7 +12,15 @@ interface CaptionedOutput : Captioned {
}
interface CaptionedInput : Captioned {
/**
* Not full list of entities. This list WILL NOT contain [TextPart]s with [com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource]
* @see [CaptionedInput.fullEntitiesList]
*/
val captionEntities: List<TextPart>
}
fun CaptionedInput.fullEntitiesList() = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()
/**
* Convert its [CaptionedInput.captionEntities] to list of [com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource]
* with [com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource]
*/
fun CaptionedInput.fullEntitiesList(): FullTextSourcesList = caption ?.fullListOfSubSource(captionEntities) ?.map { it.source } ?: emptyList()

View File

@@ -0,0 +1,26 @@
package com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts
import com.github.insanusmokrassar.TelegramBotAPI.types.ParseMode.ParseMode
import com.github.insanusmokrassar.TelegramBotAPI.utils.fullListOfSubSource
interface Explained {
val explanation: String?
}
interface ExplainedOutput : Explained {
val parseMode: ParseMode?
}
interface ExplainedInput : Explained {
/**
* Not full list of entities. This list WILL NOT contain [TextPart]s with [com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource]
* @see [ExplainedInput.fullEntitiesList]
*/
val explanationEntities: List<TextPart>
}
/**
* Convert its [ExplainedInput.explanationEntities] to list of [com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.TextSource]
* with [com.github.insanusmokrassar.TelegramBotAPI.types.MessageEntity.textsources.RegularTextSource]
*/
fun ExplainedInput.fullEntitiesList(): FullTextSourcesList = explanation ?.fullListOfSubSource(explanationEntities) ?.map { it.source } ?: emptyList()

View File

@@ -1,5 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts
import com.github.insanusmokrassar.TelegramBotAPI.utils.MimeType
interface MimeTyped {
val mimeType: String? // TODO::replace by something like enum or interface
val mimeType: MimeType?
}

View File

@@ -1,9 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts
typealias FullTextSourcesList = List<TextSource>
typealias FullTextPartsList = List<TextPart>
interface TextSource {
val asMarkdownSource: String
val asMarkdownV2Source: String
val asHtmlSource: String
val source: String
}
@@ -15,3 +19,5 @@ data class TextPart(
val range: IntRange,
val source: TextSource
)
fun List<TextPart>.justTextSources() = map { it.source }

View File

@@ -9,10 +9,10 @@ import com.github.insanusmokrassar.TelegramBotAPI.bot.settings.limiters.RequestL
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import com.github.insanusmokrassar.TelegramBotAPI.types.RetryAfterError
import com.github.insanusmokrassar.TelegramBotAPI.utils.TelegramAPIUrlsKeeper
import com.github.insanusmokrassar.TelegramBotAPI.utils.*
import io.ktor.client.HttpClient
import io.ktor.client.call.receive
import io.ktor.client.features.ClientRequestException
import io.ktor.client.features.*
import io.ktor.client.statement.HttpStatement
import io.ktor.client.statement.readText
import kotlinx.coroutines.delay
@@ -20,11 +20,11 @@ import kotlinx.serialization.json.Json
class KtorRequestsExecutor(
telegramAPIUrlsKeeper: TelegramAPIUrlsKeeper,
private val client: HttpClient = HttpClient(),
client: HttpClient = HttpClient(),
callsFactories: List<KtorCallFactory> = emptyList(),
excludeDefaultFactories: Boolean = false,
private val requestsLimiter: RequestLimiter = EmptyLimiter,
private val jsonFormatter: Json = Json.nonstrict
private val jsonFormatter: Json = nonstrictJsonFormat
) : BaseRequestsExecutor(telegramAPIUrlsKeeper) {
private val callsFactories: List<KtorCallFactory> = callsFactories.run {
if (!excludeDefaultFactories) {
@@ -34,21 +34,42 @@ class KtorRequestsExecutor(
}
}
private val client = client.config {
if (client.feature(HttpTimeout) == null) {
install(HttpTimeout)
}
}
override suspend fun <T : Any> execute(request: Request<T>): T {
return requestsLimiter.limit {
var statement: HttpStatement? = null
for (factory in callsFactories) {
statement = factory.prepareCall(
client,
telegramAPIUrlsKeeper.commonAPIUrl,
request
)
if (statement != null) {
break
return handleSafely(
{ e ->
throw if (e is ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
} else {
e
}
}
try {
val response = statement ?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
) {
requestsLimiter.limit {
var statement: HttpStatement? = null
for (factory in callsFactories) {
statement = factory.prepareCall(
client,
telegramAPIUrlsKeeper.commonAPIUrl,
request
)
if (statement != null) {
break
}
}
val response = statement?.execute() ?: throw IllegalArgumentException("Can't execute request: $request")
val content = response.receive<String>()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
@@ -69,14 +90,6 @@ class KtorRequestsExecutor(
"Can't get result object from $content"
)
})
} catch (e: ClientRequestException) {
val content = e.response.readText()
val responseObject = jsonFormatter.parse(Response.serializer(), content)
throw newRequestException(
responseObject,
content,
"Can't get result object from $content"
)
}
}
}

View File

@@ -1,8 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.base
import com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorCallFactory
import com.github.insanusmokrassar.TelegramBotAPI.requests.GetUpdates
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import io.ktor.client.HttpClient
import io.ktor.client.features.timeout
import io.ktor.client.request.*
import io.ktor.client.statement.HttpStatement
import io.ktor.http.ContentType
@@ -28,6 +30,17 @@ abstract class AbstractRequestCallFactory : KtorCallFactory {
method = HttpMethod.Post
accept(ContentType.Application.Json)
if (request is GetUpdates) {
request.timeout ?.times(1000L) ?.let { customTimeoutMillis ->
if (customTimeoutMillis > 0) {
timeout {
requestTimeoutMillis = customTimeoutMillis
socketTimeoutMillis = customTimeoutMillis
}
}
}
}
body = preparedBody
},
client

View File

@@ -3,9 +3,20 @@ package com.github.insanusmokrassar.TelegramBotAPI.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.Request
import io.ktor.utils.io.core.Closeable
/**
* Interface for making requests to Telegram Bot API. Currently, there is only one built-in implementation -
* [com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorRequestsExecutor]
*
* @see Request
* @see com.github.insanusmokrassar.TelegramBotAPI.bot.Ktor.KtorRequestsExecutor
*/
interface RequestsExecutor : Closeable {
/**
* @throws com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions.RequestException
* Unsafe execution of incoming [request]. Can throw almost any exception. So, it is better to use
* something like [com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts.executeAsync] or
* [com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.shortcuts.executeUnsafe]
*
* @throws Exception
*/
suspend fun <T : Any> execute(request: Request<T>): T
}

View File

@@ -1,9 +0,0 @@
package com.github.insanusmokrassar.TelegramBotAPI.bot
import io.ktor.utils.io.core.Closeable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
interface UpdatesPoller : Closeable {
fun start(scope: CoroutineScope = CoroutineScope(Dispatchers.Default))
}

View File

@@ -1,7 +1,7 @@
package com.github.insanusmokrassar.TelegramBotAPI.bot.exceptions
import com.github.insanusmokrassar.TelegramBotAPI.types.Response
import kotlinx.io.IOException
import io.ktor.utils.io.errors.IOException
fun newRequestException(
response: Response,
@@ -14,6 +14,7 @@ fun newRequestException(
description == "Bad Request: message to edit not found" -> MessageToEditNotFoundException(response, plainAnswer, message, cause)
description.contains("Bad Request: message is not modified") -> MessageIsNotModifiedException(response, plainAnswer, message, cause)
description == "Unauthorized" -> UnauthorizedException(response, plainAnswer, message, cause)
description.contains("PHOTO_INVALID_DIMENSIONS") -> InvalidPhotoDimensionsException(response, plainAnswer, message, cause)
else -> null
}
} ?: CommonRequestException(response, plainAnswer, message, cause)
@@ -41,3 +42,6 @@ class MessageIsNotModifiedException(response: Response, plainAnswer: String, mes
class MessageToEditNotFoundException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)
class InvalidPhotoDimensionsException(response: Response, plainAnswer: String, message: String?, cause: Throwable?) :
RequestException(response, plainAnswer, message, cause)

View File

@@ -1,13 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.MessageAction
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message
import kotlinx.serialization.*
import kotlinx.serialization.internal.BooleanSerializer
import kotlinx.serialization.builtins.serializer
@Serializable
data class DeleteMessage(
@@ -19,30 +16,7 @@ data class DeleteMessage(
override fun method(): String = "deleteMessage"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = BooleanSerializer
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.deleteMessage(
chatId: ChatIdentifier,
messageId: MessageIdentifier
) = execute(
DeleteMessage(chatId, messageId)
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.deleteMessage(
chat: Chat,
messageId: MessageIdentifier
) = deleteMessage(chat.id, messageId)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.deleteMessage(
message: Message
) = deleteMessage(message.chat, message.messageId)
suspend fun Message.delete(
requestsExecutor: RequestsExecutor
) = requestsExecutor.deleteMessage(this)

View File

@@ -1,11 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.MessageAction
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.*
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.PossiblyForwardedMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.TelegramBotAPIMessageDeserializationStrategyClass
import kotlinx.serialization.*
private val AbleToBeForwardedMessageDeserializer = TelegramBotAPIMessageDeserializationStrategyClass<PossiblyForwardedMessage>()
@@ -31,51 +30,3 @@ data class ForwardMessage(
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
fromChatId: ChatIdentifier,
toChatId: ChatIdentifier,
messageId: MessageIdentifier,
disableNotification: Boolean = false
) = execute(
ForwardMessage(fromChatId, toChatId, messageId, disableNotification)
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
fromChat: Chat,
toChatId: ChatIdentifier,
messageId: MessageIdentifier,
disableNotification: Boolean = false
) = forwardMessage(fromChat.id, toChatId, messageId, disableNotification)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
fromChatId: ChatIdentifier,
toChat: Chat,
messageId: MessageIdentifier,
disableNotification: Boolean = false
) = forwardMessage(fromChatId, toChat.id, messageId, disableNotification)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
fromChat: Chat,
toChat: Chat,
messageId: MessageIdentifier,
disableNotification: Boolean = false
) = forwardMessage(fromChat.id, toChat.id, messageId, disableNotification)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
toChatId: ChatIdentifier,
message: Message,
disableNotification: Boolean = false
) = forwardMessage(message.chat, toChatId, message.messageId, disableNotification)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.forwardMessage(
toChat: Chat,
message: Message,
disableNotification: Boolean = false
) = forwardMessage(message.chat, toChat, message.messageId, disableNotification)

View File

@@ -1,18 +1,11 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.ExtendedBot
import kotlinx.serialization.*
import com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe
@Serializable
class GetMe : SimpleRequest<ExtendedBot> {
override fun method(): String = "getMe"
override val resultDeserializer: DeserializationStrategy<ExtendedBot>
get() = ExtendedBot.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.getMe() = execute(GetMe())
@Deprecated(
"Replaced",
ReplaceWith(
"GetMe", "com.github.insanusmokrassar.TelegramBotAPI.requests.bot.GetMe"
)
)
typealias GetMe = GetMe

View File

@@ -1,23 +1,30 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.ALL_UPDATES_LIST
import com.github.insanusmokrassar.TelegramBotAPI.types.UpdateIdentifier
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.Update
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateSerializerWithoutDeserialization
import com.github.insanusmokrassar.TelegramBotAPI.types.update.abstracts.UpdateSerializerWithoutSerialization
import kotlinx.serialization.*
import kotlinx.serialization.internal.ArrayListSerializer
import kotlinx.serialization.builtins.ListSerializer
private val updatesListSerializer = ArrayListSerializer(
UpdateSerializerWithoutDeserialization
private val updatesListSerializer = ListSerializer(
UpdateSerializerWithoutSerialization
)
/**
* Request updates from Telegram Bot API system. It is important, that the result updates WILL NOT include
* [com.github.insanusmokrassar.TelegramBotAPI.types.update.MediaGroupUpdates.MediaGroupUpdate] objects due to the fact,
* that it is internal abstraction and in fact any [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.MediaGroupMessage]
* is just a common [com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message]
*
* @see com.github.insanusmokrassar.TelegramBotAPI.extensions.utils.updates.retrieving.updateHandlerWithMediaGroupsAdaptation
* @see com.github.insanusmokrassar.TelegramBotAPI.utils.convertWithMediaGroupUpdates
*/
@Serializable
data class GetUpdates(
val offset: UpdateIdentifier? = null,// set `last update id + 1` to receive next part of updates
val limit: Int? = null,
val timeout: Int? = null,
val limit: Int = getUpdatesLimit.last,
val timeout: Seconds? = null,
val allowed_updates: List<String>? = ALL_UPDATES_LIST
): SimpleRequest<List<Update>> {
override fun method(): String = "getUpdates"
@@ -27,26 +34,10 @@ data class GetUpdates(
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
init {
if (limit !in getUpdatesLimit) {
error("GetUpdates request can be called only with limit in range $getUpdatesLimit (actual value is $limit)")
}
}
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.getUpdates(
offset: UpdateIdentifier? = null,
limit: Int? = null,
timeout: Int? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST
) = execute(
GetUpdates(
offset, limit, timeout, allowed_updates
)
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.getUpdates(
lastUpdate: Update,
limit: Int? = null,
timeout: Int? = null,
allowed_updates: List<String>? = ALL_UPDATES_LIST
) = getUpdates(
lastUpdate.updateId + 1, limit, timeout, allowed_updates
)

View File

@@ -1,140 +0,0 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.edit.LiveLocation.editLiveLocation
import com.github.insanusmokrassar.TelegramBotAPI.requests.edit.LiveLocation.stopLiveLocation
import com.github.insanusmokrassar.TelegramBotAPI.requests.send.SendLocation
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.KeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.ContentMessage
import com.github.insanusmokrassar.TelegramBotAPI.types.message.content.LocationContent
import com.soywiz.klock.DateTime
import com.soywiz.klock.TimeSpan
import io.ktor.utils.io.core.Closeable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlin.math.ceil
private val livePeriodDelayMillis = (livePeriodLimit.last - 60L) * 1000L
@Deprecated("Deprecated due to extracting into separated library")
class LiveLocation internal constructor(
private val requestsExecutor: RequestsExecutor,
scope: CoroutineScope,
autoCloseTimeDelay: Double,
initMessage: ContentMessage<LocationContent>
) : Closeable {
private val doWhenClose = {
scope.launch {
requestsExecutor.stopLiveLocation(message)
}
}
private val autoCloseTime = DateTime.now() + TimeSpan(autoCloseTimeDelay)
val leftUntilCloseMillis: TimeSpan
get() = autoCloseTime - DateTime.now()
var isClosed: Boolean = false
private set
get() = field || leftUntilCloseMillis.millisecondsLong < 0L
private var message: ContentMessage<LocationContent> = initMessage
val lastLocation: Location
get() = message.content.location
suspend fun updateLocation(
location: Location,
replyMarkup: InlineKeyboardMarkup? = null
): Location {
if (!isClosed) {
message = requestsExecutor.editLiveLocation(
message,
location,
replyMarkup
)
return lastLocation
} else {
error("LiveLocation is closed")
}
}
override fun close() {
if (isClosed) {
return
}
isClosed = true
doWhenClose()
}
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.startLiveLocation(
scope: CoroutineScope,
chatId: ChatIdentifier,
latitude: Double,
longitude: Double,
liveTimeMillis: Long = livePeriodDelayMillis,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
): LiveLocation {
val liveTimeAsDouble = liveTimeMillis.toDouble()
val locationMessage = execute(
SendLocation(
chatId,
latitude,
longitude,
ceil(liveTimeAsDouble / 1000).toLong(),
disableNotification,
replyToMessageId,
replyMarkup
)
)
return LiveLocation(
this,
scope,
liveTimeAsDouble,
locationMessage
)
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.startLiveLocation(
scope: CoroutineScope,
chat: Chat,
latitude: Double,
longitude: Double,
liveTimeMillis: Long = livePeriodDelayMillis,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
): LiveLocation = startLiveLocation(
scope, chat.id, latitude, longitude, liveTimeMillis, disableNotification, replyToMessageId, replyMarkup
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.startLiveLocation(
scope: CoroutineScope,
chatId: ChatId,
location: Location,
liveTimeMillis: Long = livePeriodDelayMillis,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
): LiveLocation = startLiveLocation(
scope, chatId, location.latitude, location.longitude, liveTimeMillis, disableNotification, replyToMessageId, replyMarkup
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.startLiveLocation(
scope: CoroutineScope,
chat: Chat,
location: Location,
liveTimeMillis: Long = livePeriodDelayMillis,
disableNotification: Boolean = false,
replyToMessageId: MessageIdentifier? = null,
replyMarkup: KeyboardMarkup? = null
): LiveLocation = startLiveLocation(
scope, chat.id, location.latitude, location.longitude, liveTimeMillis, disableNotification, replyToMessageId, replyMarkup
)

View File

@@ -2,12 +2,9 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.MessageAction
import com.github.insanusmokrassar.TelegramBotAPI.CommonAbstracts.types.ReplyMarkup
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.buttons.InlineKeyboardMarkup
import com.github.insanusmokrassar.TelegramBotAPI.types.chat.abstracts.Chat
import com.github.insanusmokrassar.TelegramBotAPI.types.message.abstracts.Message
import com.github.insanusmokrassar.TelegramBotAPI.types.polls.Poll
import kotlinx.serialization.*
@@ -26,33 +23,3 @@ data class StopPoll(
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.stopPoll(
chatId: ChatIdentifier,
messageId: MessageIdentifier,
replyMarkup: InlineKeyboardMarkup? = null
) = execute(
StopPoll(chatId, messageId, replyMarkup)
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.stopPoll(
chat: Chat,
messageId: MessageIdentifier,
replyMarkup: InlineKeyboardMarkup? = null
) = stopPoll(chat.id, messageId, replyMarkup)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.stopPoll(
chatId: ChatId,
message: Message,
replyMarkup: InlineKeyboardMarkup? = null
) = stopPoll(chatId, message.messageId, replyMarkup)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.stopPoll(
chat: Chat,
message: Message,
replyMarkup: InlineKeyboardMarkup? = null
) = stopPoll(chat.id, message.messageId, replyMarkup)

View File

@@ -2,7 +2,6 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts
import com.github.insanusmokrassar.TelegramBotAPI.utils.StorageFile
import kotlinx.serialization.*
import kotlinx.serialization.internal.StringDescriptor
@Serializable(InputFileSerializer::class)
sealed class InputFile {
@@ -22,8 +21,8 @@ fun String.toInputFile() = FileId(this)
@Serializer(InputFile::class)
internal object InputFileSerializer : KSerializer<InputFile> {
override val descriptor: SerialDescriptor = StringDescriptor.withName(FileId::class.toString())
override fun serialize(encoder: Encoder, obj: InputFile) = encoder.encodeString(obj.fileId)
override val descriptor: SerialDescriptor = PrimitiveDescriptor(FileId::class.toString(), PrimitiveKind.STRING)
override fun serialize(encoder: Encoder, value: InputFile) = encoder.encodeString(value.fileId)
override fun deserialize(decoder: Decoder): FileId = FileId(decoder.decodeString())
}
@@ -34,8 +33,8 @@ internal object InputFileSerializer : KSerializer<InputFile> {
@Serializable(InputFileSerializer::class)
data class MultipartFile (
val file: StorageFile,
val mimeType: String = file.contentType,
val filename: String = file.fileName
val mimeType: String = file.storageFileInfo.contentType,
val filename: String = file.storageFileInfo.fileName
) : InputFile() {
override val fileId: String = file.generateCustomName()
override val fileId: String = file.storageFileInfo.generateCustomName()
}

View File

@@ -9,4 +9,4 @@ interface SimpleRequest<T: Any> : Request<T> {
}
@Suppress("UNCHECKED_CAST")
inline fun <T: Any, K: SimpleRequest<T>> K.json(): JsonObject = toJsonWithoutNulls(requestSerializer as SerializationStrategy<K>)
internal fun <T: Any, K: SimpleRequest<T>> K.json(): JsonObject = toJsonWithoutNulls(requestSerializer as SerializationStrategy<K>)

View File

@@ -1,11 +1,10 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.answers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.CallbackQuery.CallbackQuery
import kotlinx.serialization.*
import kotlinx.serialization.internal.BooleanSerializer
import kotlinx.serialization.builtins.serializer
@Serializable
data class AnswerCallbackQuery(
@@ -22,7 +21,7 @@ data class AnswerCallbackQuery(
) : SimpleRequest<Boolean> {
override fun method(): String = "answerCallbackQuery"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = BooleanSerializer
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@@ -33,21 +32,3 @@ fun CallbackQuery.createAnswer(
url: String? = null,
cachedTimeSeconds: Int? = null
): AnswerCallbackQuery = AnswerCallbackQuery(id, text, showAlert, url, cachedTimeSeconds)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerCallbackQuery(
callbackQueryId: CallbackQueryIdentifier,
text: String? = null,
showAlert: Boolean? = null,
url: String? = null,
cachedTimeSeconds: Int? = null
) = execute(AnswerCallbackQuery(callbackQueryId, text, showAlert, url, cachedTimeSeconds))
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerCallbackQuery(
callbackQuery: CallbackQuery,
text: String? = null,
showAlert: Boolean? = null,
url: String? = null,
cachedTimeSeconds: Int? = null
) = answerCallbackQuery(callbackQuery.id, text, showAlert, url, cachedTimeSeconds)

View File

@@ -1,14 +1,13 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.answers
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult.abstracts.InlineQueryResult
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.InlineQueryResult.serializers.InlineQueryResultSerializer
import com.github.insanusmokrassar.TelegramBotAPI.types.InlineQueries.abstracts.InlineQuery
import kotlinx.serialization.*
import kotlinx.serialization.internal.ArrayListSerializer
import kotlinx.serialization.internal.BooleanSerializer
import kotlinx.serialization.builtins.ListSerializer
import kotlinx.serialization.builtins.serializer
@Serializable
data class AnswerInlineQuery(
@@ -30,7 +29,7 @@ data class AnswerInlineQuery(
): SimpleRequest<Boolean> {
override fun method(): String = "answerInlineQuery"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = BooleanSerializer
get() = Boolean.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}
@@ -52,30 +51,6 @@ fun InlineQuery.createAnswer(
switchPmParameter
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerInlineQuery(
inlineQueryID: InlineQueryIdentifier,
results: List<InlineQueryResult> = emptyList(),
cachedTime: Int? = null,
isPersonal: Boolean? = null,
nextOffset: String? = null,
switchPmText: String? = null,
switchPmParameter: String? = null
) = execute(
AnswerInlineQuery(inlineQueryID, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerInlineQuery(
inlineQuery: InlineQuery,
results: List<InlineQueryResult> = emptyList(),
cachedTime: Int? = null,
isPersonal: Boolean? = null,
nextOffset: String? = null,
switchPmText: String? = null,
switchPmParameter: String? = null
) = answerInlineQuery(inlineQuery.id, results, cachedTime, isPersonal, nextOffset, switchPmText, switchPmParameter)
internal object InlineQueryAnswersResultsSerializer: KSerializer<List<InlineQueryResult>> by ArrayListSerializer(
internal object InlineQueryAnswersResultsSerializer: KSerializer<List<InlineQueryResult>> by ListSerializer(
InlineQueryResultSerializer
)

View File

@@ -1,6 +1,5 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments.abstracts.AnswerPreCheckoutQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.PreCheckoutQuery
@@ -41,23 +40,3 @@ fun PreCheckoutQuery.createAnswerError(
id,
error
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerPreCheckoutQueryOk(
id: PreCheckoutQueryId
) = execute(AnswerPreCheckoutQueryOk(id))
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerPreCheckoutQueryOk(
preCheckoutQuery: PreCheckoutQuery
) = answerPreCheckoutQueryOk(preCheckoutQuery.id)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerPreCheckoutQueryError(
id: PreCheckoutQueryId,
error: String
) = execute(AnswerPreCheckoutQueryError(id, error))
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerPreCheckoutQueryError(
preCheckoutQuery: PreCheckoutQuery,
error: String
) = answerPreCheckoutQueryError(preCheckoutQuery.id, error)

View File

@@ -1,12 +1,11 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments
import com.github.insanusmokrassar.TelegramBotAPI.bot.RequestsExecutor
import com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments.abstracts.AnswerShippingQuery
import com.github.insanusmokrassar.TelegramBotAPI.types.*
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingOption
import com.github.insanusmokrassar.TelegramBotAPI.types.payments.ShippingQuery
import kotlinx.serialization.*
import kotlinx.serialization.internal.ArrayListSerializer
import kotlinx.serialization.builtins.ListSerializer
@Serializable
data class AnswerShippingQueryOk(
@@ -22,7 +21,7 @@ data class AnswerShippingQueryOk(
get() = serializer()
}
internal object ShippingOptionsSerializer : KSerializer<List<ShippingOption>> by ArrayListSerializer(
internal object ShippingOptionsSerializer : KSerializer<List<ShippingOption>> by ListSerializer(
ShippingOption.serializer()
)
@@ -52,27 +51,3 @@ fun ShippingQuery.createAnswerError(
id,
error
)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerShippingQueryOk(
id: ShippingQueryIdentifier,
shippingOptions: List<ShippingOption>
) = execute(AnswerShippingQueryOk(id, shippingOptions))
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerShippingQueryOk(
shippingQuery: ShippingQuery,
shippingOptions: List<ShippingOption>
) = answerShippingQueryOk(shippingQuery.id, shippingOptions)
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerShippingQueryError(
id: ShippingQueryIdentifier,
error: String
) = execute(AnswerShippingQueryError(id, error))
@Deprecated("Deprecated due to extracting into separated library")
suspend fun RequestsExecutor.answerShippingQueryError(
shippingQuery: ShippingQuery,
error: String
) = answerShippingQueryError(shippingQuery.id, error)

View File

@@ -3,12 +3,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments.abs
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.PreCheckoutQueryId
import kotlinx.serialization.KSerializer
import kotlinx.serialization.internal.BooleanSerializer
import kotlinx.serialization.builtins.serializer
interface AnswerPreCheckoutQuery : SimpleRequest<Boolean> {
override fun method(): String = "answerPreCheckoutQuery"
override val resultDeserializer: KSerializer<Boolean>
get() = BooleanSerializer
get() = Boolean.serializer()
val preCheckoutQueryId: PreCheckoutQueryId
val isOk: Boolean

View File

@@ -3,12 +3,12 @@ package com.github.insanusmokrassar.TelegramBotAPI.requests.answers.payments.abs
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.ShippingQueryIdentifier
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.internal.BooleanSerializer
import kotlinx.serialization.builtins.serializer
interface AnswerShippingQuery : SimpleRequest<Boolean> {
override fun method(): String = "answerShippingQuery"
override val resultDeserializer: DeserializationStrategy<Boolean>
get() = BooleanSerializer
get() = Boolean.serializer()
val shippingQueryId: ShippingQueryIdentifier
val isOk: Boolean

View File

@@ -0,0 +1,14 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.ExtendedBot
import kotlinx.serialization.*
@Serializable
object GetMe : SimpleRequest<ExtendedBot> {
override fun method(): String = "getMe"
override val resultDeserializer: DeserializationStrategy<ExtendedBot>
get() = ExtendedBot.serializer()
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

View File

@@ -0,0 +1,17 @@
package com.github.insanusmokrassar.TelegramBotAPI.requests.bot
import com.github.insanusmokrassar.TelegramBotAPI.requests.abstracts.SimpleRequest
import com.github.insanusmokrassar.TelegramBotAPI.types.BotCommand
import kotlinx.serialization.*
import kotlinx.serialization.builtins.ListSerializer
private val getMyCommandsSerializer = ListSerializer(BotCommand.serializer())
@Serializable
object GetMyCommands : SimpleRequest<List<BotCommand>> {
override fun method(): String = "getMyCommands"
override val resultDeserializer: DeserializationStrategy<List<BotCommand>>
get() = getMyCommandsSerializer
override val requestSerializer: SerializationStrategy<*>
get() = serializer()
}

Some files were not shown because too many files have changed in this diff Show More