├── LICENSE
├── README.md
├── example.lua
├── examples
└── ipsw-bot.lua
├── install.sh
├── rockspecs
├── telegram-bot-lua-1.0.0-0.rockspec
├── telegram-bot-lua-1.0.1-0.rockspec
├── telegram-bot-lua-1.0.2-0.rockspec
├── telegram-bot-lua-1.0.2-1.rockspec
├── telegram-bot-lua-1.0.3-0.rockspec
├── telegram-bot-lua-1.0.4-0.rockspec
├── telegram-bot-lua-1.1.0-0.rockspec
├── telegram-bot-lua-1.1.0-1.rockspec
├── telegram-bot-lua-1.10-0.rockspec
├── telegram-bot-lua-1.2-0.rockspec
├── telegram-bot-lua-1.2.1-0.rockspec
├── telegram-bot-lua-1.3-0.rockspec
├── telegram-bot-lua-1.3.1-0.rockspec
├── telegram-bot-lua-1.3.2-0.rockspec
├── telegram-bot-lua-1.4-0.rockspec
├── telegram-bot-lua-1.5-0.rockspec
├── telegram-bot-lua-1.6-0.rockspec
├── telegram-bot-lua-1.7-0.rockspec
├── telegram-bot-lua-1.8-0.rockspec
├── telegram-bot-lua-1.9-0.rockspec
├── telegram-bot-lua-1.9-1.rockspec
└── telegram-bot-lua-2.0-0.rockspec
├── src
├── b64url.lua
├── config.lua
├── core.lua
└── tools.lua
└── telegram-bot-lua-2.0-0.rockspec
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 3, 29 June 2007
3 |
4 | Copyright (C) 2007 Free Software Foundation, Inc.
5 | Everyone is permitted to copy and distribute verbatim copies
6 | of this license document, but changing it is not allowed.
7 |
8 | Preamble
9 |
10 | The GNU General Public License is a free, copyleft license for
11 | software and other kinds of works.
12 |
13 | The licenses for most software and other practical works are designed
14 | to take away your freedom to share and change the works. By contrast,
15 | the GNU General Public License is intended to guarantee your freedom to
16 | share and change all versions of a program--to make sure it remains free
17 | software for all its users. We, the Free Software Foundation, use the
18 | GNU General Public License for most of our software; it applies also to
19 | any other work released this way by its authors. You can apply it to
20 | your programs, too.
21 |
22 | When we speak of free software, we are referring to freedom, not
23 | price. Our General Public Licenses are designed to make sure that you
24 | have the freedom to distribute copies of free software (and charge for
25 | them if you wish), that you receive source code or can get it if you
26 | want it, that you can change the software or use pieces of it in new
27 | free programs, and that you know you can do these things.
28 |
29 | To protect your rights, we need to prevent others from denying you
30 | these rights or asking you to surrender the rights. Therefore, you have
31 | certain responsibilities if you distribute copies of the software, or if
32 | you modify it: responsibilities to respect the freedom of others.
33 |
34 | For example, if you distribute copies of such a program, whether
35 | gratis or for a fee, you must pass on to the recipients the same
36 | freedoms that you received. You must make sure that they, too, receive
37 | or can get the source code. And you must show them these terms so they
38 | know their rights.
39 |
40 | Developers that use the GNU GPL protect your rights with two steps:
41 | (1) assert copyright on the software, and (2) offer you this License
42 | giving you legal permission to copy, distribute and/or modify it.
43 |
44 | For the developers' and authors' protection, the GPL clearly explains
45 | that there is no warranty for this free software. For both users' and
46 | authors' sake, the GPL requires that modified versions be marked as
47 | changed, so that their problems will not be attributed erroneously to
48 | authors of previous versions.
49 |
50 | Some devices are designed to deny users access to install or run
51 | modified versions of the software inside them, although the manufacturer
52 | can do so. This is fundamentally incompatible with the aim of
53 | protecting users' freedom to change the software. The systematic
54 | pattern of such abuse occurs in the area of products for individuals to
55 | use, which is precisely where it is most unacceptable. Therefore, we
56 | have designed this version of the GPL to prohibit the practice for those
57 | products. If such problems arise substantially in other domains, we
58 | stand ready to extend this provision to those domains in future versions
59 | of the GPL, as needed to protect the freedom of users.
60 |
61 | Finally, every program is threatened constantly by software patents.
62 | States should not allow patents to restrict development and use of
63 | software on general-purpose computers, but in those that do, we wish to
64 | avoid the special danger that patents applied to a free program could
65 | make it effectively proprietary. To prevent this, the GPL assures that
66 | patents cannot be used to render the program non-free.
67 |
68 | The precise terms and conditions for copying, distribution and
69 | modification follow.
70 |
71 | TERMS AND CONDITIONS
72 |
73 | 0. Definitions.
74 |
75 | "This License" refers to version 3 of the GNU General Public License.
76 |
77 | "Copyright" also means copyright-like laws that apply to other kinds of
78 | works, such as semiconductor masks.
79 |
80 | "The Program" refers to any copyrightable work licensed under this
81 | License. Each licensee is addressed as "you". "Licensees" and
82 | "recipients" may be individuals or organizations.
83 |
84 | To "modify" a work means to copy from or adapt all or part of the work
85 | in a fashion requiring copyright permission, other than the making of an
86 | exact copy. The resulting work is called a "modified version" of the
87 | earlier work or a work "based on" the earlier work.
88 |
89 | A "covered work" means either the unmodified Program or a work based
90 | on the Program.
91 |
92 | To "propagate" a work means to do anything with it that, without
93 | permission, would make you directly or secondarily liable for
94 | infringement under applicable copyright law, except executing it on a
95 | computer or modifying a private copy. Propagation includes copying,
96 | distribution (with or without modification), making available to the
97 | public, and in some countries other activities as well.
98 |
99 | To "convey" a work means any kind of propagation that enables other
100 | parties to make or receive copies. Mere interaction with a user through
101 | a computer network, with no transfer of a copy, is not conveying.
102 |
103 | An interactive user interface displays "Appropriate Legal Notices"
104 | to the extent that it includes a convenient and prominently visible
105 | feature that (1) displays an appropriate copyright notice, and (2)
106 | tells the user that there is no warranty for the work (except to the
107 | extent that warranties are provided), that licensees may convey the
108 | work under this License, and how to view a copy of this License. If
109 | the interface presents a list of user commands or options, such as a
110 | menu, a prominent item in the list meets this criterion.
111 |
112 | 1. Source Code.
113 |
114 | The "source code" for a work means the preferred form of the work
115 | for making modifications to it. "Object code" means any non-source
116 | form of a work.
117 |
118 | A "Standard Interface" means an interface that either is an official
119 | standard defined by a recognized standards body, or, in the case of
120 | interfaces specified for a particular programming language, one that
121 | is widely used among developers working in that language.
122 |
123 | The "System Libraries" of an executable work include anything, other
124 | than the work as a whole, that (a) is included in the normal form of
125 | packaging a Major Component, but which is not part of that Major
126 | Component, and (b) serves only to enable use of the work with that
127 | Major Component, or to implement a Standard Interface for which an
128 | implementation is available to the public in source code form. A
129 | "Major Component", in this context, means a major essential component
130 | (kernel, window system, and so on) of the specific operating system
131 | (if any) on which the executable work runs, or a compiler used to
132 | produce the work, or an object code interpreter used to run it.
133 |
134 | The "Corresponding Source" for a work in object code form means all
135 | the source code needed to generate, install, and (for an executable
136 | work) run the object code and to modify the work, including scripts to
137 | control those activities. However, it does not include the work's
138 | System Libraries, or general-purpose tools or generally available free
139 | programs which are used unmodified in performing those activities but
140 | which are not part of the work. For example, Corresponding Source
141 | includes interface definition files associated with source files for
142 | the work, and the source code for shared libraries and dynamically
143 | linked subprograms that the work is specifically designed to require,
144 | such as by intimate data communication or control flow between those
145 | subprograms and other parts of the work.
146 |
147 | The Corresponding Source need not include anything that users
148 | can regenerate automatically from other parts of the Corresponding
149 | Source.
150 |
151 | The Corresponding Source for a work in source code form is that
152 | same work.
153 |
154 | 2. Basic Permissions.
155 |
156 | All rights granted under this License are granted for the term of
157 | copyright on the Program, and are irrevocable provided the stated
158 | conditions are met. This License explicitly affirms your unlimited
159 | permission to run the unmodified Program. The output from running a
160 | covered work is covered by this License only if the output, given its
161 | content, constitutes a covered work. This License acknowledges your
162 | rights of fair use or other equivalent, as provided by copyright law.
163 |
164 | You may make, run and propagate covered works that you do not
165 | convey, without conditions so long as your license otherwise remains
166 | in force. You may convey covered works to others for the sole purpose
167 | of having them make modifications exclusively for you, or provide you
168 | with facilities for running those works, provided that you comply with
169 | the terms of this License in conveying all material for which you do
170 | not control copyright. Those thus making or running the covered works
171 | for you must do so exclusively on your behalf, under your direction
172 | and control, on terms that prohibit them from making any copies of
173 | your copyrighted material outside their relationship with you.
174 |
175 | Conveying under any other circumstances is permitted solely under
176 | the conditions stated below. Sublicensing is not allowed; section 10
177 | makes it unnecessary.
178 |
179 | 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
180 |
181 | No covered work shall be deemed part of an effective technological
182 | measure under any applicable law fulfilling obligations under article
183 | 11 of the WIPO copyright treaty adopted on 20 December 1996, or
184 | similar laws prohibiting or restricting circumvention of such
185 | measures.
186 |
187 | When you convey a covered work, you waive any legal power to forbid
188 | circumvention of technological measures to the extent such circumvention
189 | is effected by exercising rights under this License with respect to
190 | the covered work, and you disclaim any intention to limit operation or
191 | modification of the work as a means of enforcing, against the work's
192 | users, your or third parties' legal rights to forbid circumvention of
193 | technological measures.
194 |
195 | 4. Conveying Verbatim Copies.
196 |
197 | You may convey verbatim copies of the Program's source code as you
198 | receive it, in any medium, provided that you conspicuously and
199 | appropriately publish on each copy an appropriate copyright notice;
200 | keep intact all notices stating that this License and any
201 | non-permissive terms added in accord with section 7 apply to the code;
202 | keep intact all notices of the absence of any warranty; and give all
203 | recipients a copy of this License along with the Program.
204 |
205 | You may charge any price or no price for each copy that you convey,
206 | and you may offer support or warranty protection for a fee.
207 |
208 | 5. Conveying Modified Source Versions.
209 |
210 | You may convey a work based on the Program, or the modifications to
211 | produce it from the Program, in the form of source code under the
212 | terms of section 4, provided that you also meet all of these conditions:
213 |
214 | a) The work must carry prominent notices stating that you modified
215 | it, and giving a relevant date.
216 |
217 | b) The work must carry prominent notices stating that it is
218 | released under this License and any conditions added under section
219 | 7. This requirement modifies the requirement in section 4 to
220 | "keep intact all notices".
221 |
222 | c) You must license the entire work, as a whole, under this
223 | License to anyone who comes into possession of a copy. This
224 | License will therefore apply, along with any applicable section 7
225 | additional terms, to the whole of the work, and all its parts,
226 | regardless of how they are packaged. This License gives no
227 | permission to license the work in any other way, but it does not
228 | invalidate such permission if you have separately received it.
229 |
230 | d) If the work has interactive user interfaces, each must display
231 | Appropriate Legal Notices; however, if the Program has interactive
232 | interfaces that do not display Appropriate Legal Notices, your
233 | work need not make them do so.
234 |
235 | A compilation of a covered work with other separate and independent
236 | works, which are not by their nature extensions of the covered work,
237 | and which are not combined with it such as to form a larger program,
238 | in or on a volume of a storage or distribution medium, is called an
239 | "aggregate" if the compilation and its resulting copyright are not
240 | used to limit the access or legal rights of the compilation's users
241 | beyond what the individual works permit. Inclusion of a covered work
242 | in an aggregate does not cause this License to apply to the other
243 | parts of the aggregate.
244 |
245 | 6. Conveying Non-Source Forms.
246 |
247 | You may convey a covered work in object code form under the terms
248 | of sections 4 and 5, provided that you also convey the
249 | machine-readable Corresponding Source under the terms of this License,
250 | in one of these ways:
251 |
252 | a) Convey the object code in, or embodied in, a physical product
253 | (including a physical distribution medium), accompanied by the
254 | Corresponding Source fixed on a durable physical medium
255 | customarily used for software interchange.
256 |
257 | b) Convey the object code in, or embodied in, a physical product
258 | (including a physical distribution medium), accompanied by a
259 | written offer, valid for at least three years and valid for as
260 | long as you offer spare parts or customer support for that product
261 | model, to give anyone who possesses the object code either (1) a
262 | copy of the Corresponding Source for all the software in the
263 | product that is covered by this License, on a durable physical
264 | medium customarily used for software interchange, for a price no
265 | more than your reasonable cost of physically performing this
266 | conveying of source, or (2) access to copy the
267 | Corresponding Source from a network server at no charge.
268 |
269 | c) Convey individual copies of the object code with a copy of the
270 | written offer to provide the Corresponding Source. This
271 | alternative is allowed only occasionally and noncommercially, and
272 | only if you received the object code with such an offer, in accord
273 | with subsection 6b.
274 |
275 | d) Convey the object code by offering access from a designated
276 | place (gratis or for a charge), and offer equivalent access to the
277 | Corresponding Source in the same way through the same place at no
278 | further charge. You need not require recipients to copy the
279 | Corresponding Source along with the object code. If the place to
280 | copy the object code is a network server, the Corresponding Source
281 | may be on a different server (operated by you or a third party)
282 | that supports equivalent copying facilities, provided you maintain
283 | clear directions next to the object code saying where to find the
284 | Corresponding Source. Regardless of what server hosts the
285 | Corresponding Source, you remain obligated to ensure that it is
286 | available for as long as needed to satisfy these requirements.
287 |
288 | e) Convey the object code using peer-to-peer transmission, provided
289 | you inform other peers where the object code and Corresponding
290 | Source of the work are being offered to the general public at no
291 | charge under subsection 6d.
292 |
293 | A separable portion of the object code, whose source code is excluded
294 | from the Corresponding Source as a System Library, need not be
295 | included in conveying the object code work.
296 |
297 | A "User Product" is either (1) a "consumer product", which means any
298 | tangible personal property which is normally used for personal, family,
299 | or household purposes, or (2) anything designed or sold for incorporation
300 | into a dwelling. In determining whether a product is a consumer product,
301 | doubtful cases shall be resolved in favor of coverage. For a particular
302 | product received by a particular user, "normally used" refers to a
303 | typical or common use of that class of product, regardless of the status
304 | of the particular user or of the way in which the particular user
305 | actually uses, or expects or is expected to use, the product. A product
306 | is a consumer product regardless of whether the product has substantial
307 | commercial, industrial or non-consumer uses, unless such uses represent
308 | the only significant mode of use of the product.
309 |
310 | "Installation Information" for a User Product means any methods,
311 | procedures, authorization keys, or other information required to install
312 | and execute modified versions of a covered work in that User Product from
313 | a modified version of its Corresponding Source. The information must
314 | suffice to ensure that the continued functioning of the modified object
315 | code is in no case prevented or interfered with solely because
316 | modification has been made.
317 |
318 | If you convey an object code work under this section in, or with, or
319 | specifically for use in, a User Product, and the conveying occurs as
320 | part of a transaction in which the right of possession and use of the
321 | User Product is transferred to the recipient in perpetuity or for a
322 | fixed term (regardless of how the transaction is characterized), the
323 | Corresponding Source conveyed under this section must be accompanied
324 | by the Installation Information. But this requirement does not apply
325 | if neither you nor any third party retains the ability to install
326 | modified object code on the User Product (for example, the work has
327 | been installed in ROM).
328 |
329 | The requirement to provide Installation Information does not include a
330 | requirement to continue to provide support service, warranty, or updates
331 | for a work that has been modified or installed by the recipient, or for
332 | the User Product in which it has been modified or installed. Access to a
333 | network may be denied when the modification itself materially and
334 | adversely affects the operation of the network or violates the rules and
335 | protocols for communication across the network.
336 |
337 | Corresponding Source conveyed, and Installation Information provided,
338 | in accord with this section must be in a format that is publicly
339 | documented (and with an implementation available to the public in
340 | source code form), and must require no special password or key for
341 | unpacking, reading or copying.
342 |
343 | 7. Additional Terms.
344 |
345 | "Additional permissions" are terms that supplement the terms of this
346 | License by making exceptions from one or more of its conditions.
347 | Additional permissions that are applicable to the entire Program shall
348 | be treated as though they were included in this License, to the extent
349 | that they are valid under applicable law. If additional permissions
350 | apply only to part of the Program, that part may be used separately
351 | under those permissions, but the entire Program remains governed by
352 | this License without regard to the additional permissions.
353 |
354 | When you convey a copy of a covered work, you may at your option
355 | remove any additional permissions from that copy, or from any part of
356 | it. (Additional permissions may be written to require their own
357 | removal in certain cases when you modify the work.) You may place
358 | additional permissions on material, added by you to a covered work,
359 | for which you have or can give appropriate copyright permission.
360 |
361 | Notwithstanding any other provision of this License, for material you
362 | add to a covered work, you may (if authorized by the copyright holders of
363 | that material) supplement the terms of this License with terms:
364 |
365 | a) Disclaiming warranty or limiting liability differently from the
366 | terms of sections 15 and 16 of this License; or
367 |
368 | b) Requiring preservation of specified reasonable legal notices or
369 | author attributions in that material or in the Appropriate Legal
370 | Notices displayed by works containing it; or
371 |
372 | c) Prohibiting misrepresentation of the origin of that material, or
373 | requiring that modified versions of such material be marked in
374 | reasonable ways as different from the original version; or
375 |
376 | d) Limiting the use for publicity purposes of names of licensors or
377 | authors of the material; or
378 |
379 | e) Declining to grant rights under trademark law for use of some
380 | trade names, trademarks, or service marks; or
381 |
382 | f) Requiring indemnification of licensors and authors of that
383 | material by anyone who conveys the material (or modified versions of
384 | it) with contractual assumptions of liability to the recipient, for
385 | any liability that these contractual assumptions directly impose on
386 | those licensors and authors.
387 |
388 | All other non-permissive additional terms are considered "further
389 | restrictions" within the meaning of section 10. If the Program as you
390 | received it, or any part of it, contains a notice stating that it is
391 | governed by this License along with a term that is a further
392 | restriction, you may remove that term. If a license document contains
393 | a further restriction but permits relicensing or conveying under this
394 | License, you may add to a covered work material governed by the terms
395 | of that license document, provided that the further restriction does
396 | not survive such relicensing or conveying.
397 |
398 | If you add terms to a covered work in accord with this section, you
399 | must place, in the relevant source files, a statement of the
400 | additional terms that apply to those files, or a notice indicating
401 | where to find the applicable terms.
402 |
403 | Additional terms, permissive or non-permissive, may be stated in the
404 | form of a separately written license, or stated as exceptions;
405 | the above requirements apply either way.
406 |
407 | 8. Termination.
408 |
409 | You may not propagate or modify a covered work except as expressly
410 | provided under this License. Any attempt otherwise to propagate or
411 | modify it is void, and will automatically terminate your rights under
412 | this License (including any patent licenses granted under the third
413 | paragraph of section 11).
414 |
415 | However, if you cease all violation of this License, then your
416 | license from a particular copyright holder is reinstated (a)
417 | provisionally, unless and until the copyright holder explicitly and
418 | finally terminates your license, and (b) permanently, if the copyright
419 | holder fails to notify you of the violation by some reasonable means
420 | prior to 60 days after the cessation.
421 |
422 | Moreover, your license from a particular copyright holder is
423 | reinstated permanently if the copyright holder notifies you of the
424 | violation by some reasonable means, this is the first time you have
425 | received notice of violation of this License (for any work) from that
426 | copyright holder, and you cure the violation prior to 30 days after
427 | your receipt of the notice.
428 |
429 | Termination of your rights under this section does not terminate the
430 | licenses of parties who have received copies or rights from you under
431 | this License. If your rights have been terminated and not permanently
432 | reinstated, you do not qualify to receive new licenses for the same
433 | material under section 10.
434 |
435 | 9. Acceptance Not Required for Having Copies.
436 |
437 | You are not required to accept this License in order to receive or
438 | run a copy of the Program. Ancillary propagation of a covered work
439 | occurring solely as a consequence of using peer-to-peer transmission
440 | to receive a copy likewise does not require acceptance. However,
441 | nothing other than this License grants you permission to propagate or
442 | modify any covered work. These actions infringe copyright if you do
443 | not accept this License. Therefore, by modifying or propagating a
444 | covered work, you indicate your acceptance of this License to do so.
445 |
446 | 10. Automatic Licensing of Downstream Recipients.
447 |
448 | Each time you convey a covered work, the recipient automatically
449 | receives a license from the original licensors, to run, modify and
450 | propagate that work, subject to this License. You are not responsible
451 | for enforcing compliance by third parties with this License.
452 |
453 | An "entity transaction" is a transaction transferring control of an
454 | organization, or substantially all assets of one, or subdividing an
455 | organization, or merging organizations. If propagation of a covered
456 | work results from an entity transaction, each party to that
457 | transaction who receives a copy of the work also receives whatever
458 | licenses to the work the party's predecessor in interest had or could
459 | give under the previous paragraph, plus a right to possession of the
460 | Corresponding Source of the work from the predecessor in interest, if
461 | the predecessor has it or can get it with reasonable efforts.
462 |
463 | You may not impose any further restrictions on the exercise of the
464 | rights granted or affirmed under this License. For example, you may
465 | not impose a license fee, royalty, or other charge for exercise of
466 | rights granted under this License, and you may not initiate litigation
467 | (including a cross-claim or counterclaim in a lawsuit) alleging that
468 | any patent claim is infringed by making, using, selling, offering for
469 | sale, or importing the Program or any portion of it.
470 |
471 | 11. Patents.
472 |
473 | A "contributor" is a copyright holder who authorizes use under this
474 | License of the Program or a work on which the Program is based. The
475 | work thus licensed is called the contributor's "contributor version".
476 |
477 | A contributor's "essential patent claims" are all patent claims
478 | owned or controlled by the contributor, whether already acquired or
479 | hereafter acquired, that would be infringed by some manner, permitted
480 | by this License, of making, using, or selling its contributor version,
481 | but do not include claims that would be infringed only as a
482 | consequence of further modification of the contributor version. For
483 | purposes of this definition, "control" includes the right to grant
484 | patent sublicenses in a manner consistent with the requirements of
485 | this License.
486 |
487 | Each contributor grants you a non-exclusive, worldwide, royalty-free
488 | patent license under the contributor's essential patent claims, to
489 | make, use, sell, offer for sale, import and otherwise run, modify and
490 | propagate the contents of its contributor version.
491 |
492 | In the following three paragraphs, a "patent license" is any express
493 | agreement or commitment, however denominated, not to enforce a patent
494 | (such as an express permission to practice a patent or covenant not to
495 | sue for patent infringement). To "grant" such a patent license to a
496 | party means to make such an agreement or commitment not to enforce a
497 | patent against the party.
498 |
499 | If you convey a covered work, knowingly relying on a patent license,
500 | and the Corresponding Source of the work is not available for anyone
501 | to copy, free of charge and under the terms of this License, through a
502 | publicly available network server or other readily accessible means,
503 | then you must either (1) cause the Corresponding Source to be so
504 | available, or (2) arrange to deprive yourself of the benefit of the
505 | patent license for this particular work, or (3) arrange, in a manner
506 | consistent with the requirements of this License, to extend the patent
507 | license to downstream recipients. "Knowingly relying" means you have
508 | actual knowledge that, but for the patent license, your conveying the
509 | covered work in a country, or your recipient's use of the covered work
510 | in a country, would infringe one or more identifiable patents in that
511 | country that you have reason to believe are valid.
512 |
513 | If, pursuant to or in connection with a single transaction or
514 | arrangement, you convey, or propagate by procuring conveyance of, a
515 | covered work, and grant a patent license to some of the parties
516 | receiving the covered work authorizing them to use, propagate, modify
517 | or convey a specific copy of the covered work, then the patent license
518 | you grant is automatically extended to all recipients of the covered
519 | work and works based on it.
520 |
521 | A patent license is "discriminatory" if it does not include within
522 | the scope of its coverage, prohibits the exercise of, or is
523 | conditioned on the non-exercise of one or more of the rights that are
524 | specifically granted under this License. You may not convey a covered
525 | work if you are a party to an arrangement with a third party that is
526 | in the business of distributing software, under which you make payment
527 | to the third party based on the extent of your activity of conveying
528 | the work, and under which the third party grants, to any of the
529 | parties who would receive the covered work from you, a discriminatory
530 | patent license (a) in connection with copies of the covered work
531 | conveyed by you (or copies made from those copies), or (b) primarily
532 | for and in connection with specific products or compilations that
533 | contain the covered work, unless you entered into that arrangement,
534 | or that patent license was granted, prior to 28 March 2007.
535 |
536 | Nothing in this License shall be construed as excluding or limiting
537 | any implied license or other defenses to infringement that may
538 | otherwise be available to you under applicable patent law.
539 |
540 | 12. No Surrender of Others' Freedom.
541 |
542 | If conditions are imposed on you (whether by court order, agreement or
543 | otherwise) that contradict the conditions of this License, they do not
544 | excuse you from the conditions of this License. If you cannot convey a
545 | covered work so as to satisfy simultaneously your obligations under this
546 | License and any other pertinent obligations, then as a consequence you may
547 | not convey it at all. For example, if you agree to terms that obligate you
548 | to collect a royalty for further conveying from those to whom you convey
549 | the Program, the only way you could satisfy both those terms and this
550 | License would be to refrain entirely from conveying the Program.
551 |
552 | 13. Use with the GNU Affero General Public License.
553 |
554 | Notwithstanding any other provision of this License, you have
555 | permission to link or combine any covered work with a work licensed
556 | under version 3 of the GNU Affero General Public License into a single
557 | combined work, and to convey the resulting work. The terms of this
558 | License will continue to apply to the part which is the covered work,
559 | but the special requirements of the GNU Affero General Public License,
560 | section 13, concerning interaction through a network will apply to the
561 | combination as such.
562 |
563 | 14. Revised Versions of this License.
564 |
565 | The Free Software Foundation may publish revised and/or new versions of
566 | the GNU General Public License from time to time. Such new versions will
567 | be similar in spirit to the present version, but may differ in detail to
568 | address new problems or concerns.
569 |
570 | Each version is given a distinguishing version number. If the
571 | Program specifies that a certain numbered version of the GNU General
572 | Public License "or any later version" applies to it, you have the
573 | option of following the terms and conditions either of that numbered
574 | version or of any later version published by the Free Software
575 | Foundation. If the Program does not specify a version number of the
576 | GNU General Public License, you may choose any version ever published
577 | by the Free Software Foundation.
578 |
579 | If the Program specifies that a proxy can decide which future
580 | versions of the GNU General Public License can be used, that proxy's
581 | public statement of acceptance of a version permanently authorizes you
582 | to choose that version for the Program.
583 |
584 | Later license versions may give you additional or different
585 | permissions. However, no additional obligations are imposed on any
586 | author or copyright holder as a result of your choosing to follow a
587 | later version.
588 |
589 | 15. Disclaimer of Warranty.
590 |
591 | THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
592 | APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
593 | HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
594 | OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
595 | THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
596 | PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
597 | IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
598 | ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
599 |
600 | 16. Limitation of Liability.
601 |
602 | IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
603 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
604 | THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
605 | GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
606 | USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
607 | DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
608 | PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
609 | EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
610 | SUCH DAMAGES.
611 |
612 | 17. Interpretation of Sections 15 and 16.
613 |
614 | If the disclaimer of warranty and limitation of liability provided
615 | above cannot be given local legal effect according to their terms,
616 | reviewing courts shall apply local law that most closely approximates
617 | an absolute waiver of all civil liability in connection with the
618 | Program, unless a warranty or assumption of liability accompanies a
619 | copy of the Program in return for a fee.
620 |
621 | END OF TERMS AND CONDITIONS
622 |
623 | How to Apply These Terms to Your New Programs
624 |
625 | If you develop a new program, and you want it to be of the greatest
626 | possible use to the public, the best way to achieve this is to make it
627 | free software which everyone can redistribute and change under these terms.
628 |
629 | To do so, attach the following notices to the program. It is safest
630 | to attach them to the start of each source file to most effectively
631 | state the exclusion of warranty; and each file should have at least
632 | the "copyright" line and a pointer to where the full notice is found.
633 |
634 | {one line to give the program's name and a brief idea of what it does.}
635 | Copyright (C) {year} {name of author}
636 |
637 | This program is free software: you can redistribute it and/or modify
638 | it under the terms of the GNU General Public License as published by
639 | the Free Software Foundation, either version 3 of the License, or
640 | (at your option) any later version.
641 |
642 | This program is distributed in the hope that it will be useful,
643 | but WITHOUT ANY WARRANTY; without even the implied warranty of
644 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
645 | GNU General Public License for more details.
646 |
647 | You should have received a copy of the GNU General Public License
648 | along with this program. If not, see .
649 |
650 | Also add information on how to contact you by electronic and paper mail.
651 |
652 | If the program does terminal interaction, make it output a short
653 | notice like this when it starts in an interactive mode:
654 |
655 | {project} Copyright (C) {year} {fullname}
656 | This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
657 | This is free software, and you are welcome to redistribute it
658 | under certain conditions; type `show c' for details.
659 |
660 | The hypothetical commands `show w' and `show c' should show the appropriate
661 | parts of the General Public License. Of course, your program's commands
662 | might be different; for a GUI interface, you would use an "about box".
663 |
664 | You should also get your employer (if you work as a programmer) or school,
665 | if any, to sign a "copyright disclaimer" for the program, if necessary.
666 | For more information on this, and how to apply and follow the GNU GPL, see
667 | .
668 |
669 | The GNU General Public License does not permit incorporating your program
670 | into proprietary programs. If your program is a subroutine library, you
671 | may consider it more useful to permit linking proprietary applications with
672 | the library. If this is what you want to do, use the GNU Lesser General
673 | Public License instead of this License. But first, please read
674 | .
675 |
--------------------------------------------------------------------------------
/example.lua:
--------------------------------------------------------------------------------
1 | --[[
2 | This example will echo messages back to the user who sent them, with an inline keyboard
3 | which tells the user the JSON for the callback_query.from object.
4 | ]]
5 |
6 | local api = require('telegram-bot-lua.core').configure('') -- Enter your token
7 | local json = require('dkjson')
8 |
9 | function api.on_message(message)
10 | if message.text then
11 | api.send_message(message, message.text, nil, nil, nil, nil, false, false, nil,
12 | api.inline_keyboard():row(api.row():callback_data_button('Button', 'callback_data')))
13 | end
14 | end
15 |
16 | function api.on_callback_query(callback_query)
17 | api.answer_callback_query(callback_query.id, json.encode(callback_query.from))
18 | end
19 |
20 | api.run()
21 |
--------------------------------------------------------------------------------
/examples/ipsw-bot.lua:
--------------------------------------------------------------------------------
1 | local ipsw = {} -- todo: update api to v4
2 |
3 | local api = require('telegram-bot-lua.core').configure('') -- Insert your token here.
4 | local tools = require('telegram-bot-lua.tools')
5 | local https = require('ssl.https')
6 | local url = require('socket.url')
7 | local json = require('dkjson')
8 |
9 | function ipsw.init()
10 | ipsw.data = {}
11 | local jstr, res = https.request('https://api.ipsw.me/v2.1/firmwares.json')
12 | if res == 200 then
13 | ipsw.data = json.decode(jstr)
14 | end
15 | ipsw.devices = {}
16 | for k, v in pairs(ipsw.data.devices) do
17 | if k:lower():match('^appletv') then
18 | if not ipsw.devices['Apple TV'] then
19 | ipsw.devices['Apple TV'] = {}
20 | end
21 | table.insert(ipsw.devices['Apple TV'], k)
22 | table.sort(ipsw.devices['Apple TV'])
23 | elseif k:lower():match('^ipad') then
24 | if not ipsw.devices['iPad'] then
25 | ipsw.devices['iPad'] = {}
26 | end
27 | table.insert(ipsw.devices['iPad'], k)
28 | table.sort(ipsw.devices['iPad'])
29 | elseif k:lower():match('^ipod') then
30 | if not ipsw.devices['iPod'] then
31 | ipsw.devices['iPod'] = {}
32 | end
33 | table.insert(ipsw.devices['iPod'], k)
34 | table.sort(ipsw.devices['iPod'])
35 | elseif k:lower():match('^iphone') then
36 | if not ipsw.devices['iPhone'] then
37 | ipsw.devices['iPhone'] = {}
38 | end
39 | table.insert(ipsw.devices['iPhone'], k)
40 | table.sort(ipsw.devices['iPhone'])
41 | elseif k:lower():match('^mac') then
42 | if not ipsw.devices['Mac'] then
43 | ipsw.devices['Mac'] = {}
44 | end
45 | table.insert(ipsw.devices['Mac'], k)
46 | table.sort(ipsw.devices['Mac'])
47 | end
48 | end
49 | end
50 |
51 | function ipsw.get_info(input)
52 | local device = input
53 | local version = 'latest'
54 | if input:match('^.- .-$') then
55 | device = input:match('^(.-) ')
56 | version = input:match(' (.-)$')
57 | end
58 | local jstr, res = https.request(string.format('https://api.ipsw.me/v2.1/%s/%s/info.json', url.escape(device),
59 | url.escape(version)))
60 | if res ~= 200 or jstr == '[]' then
61 | return false
62 | end
63 | return json.decode(jstr)
64 | end
65 |
66 | function ipsw.get_model_keyboard(device)
67 | local keyboard = {
68 | ['inline_keyboard'] = {{}}
69 | }
70 | local total = 0
71 | for _, v in pairs(ipsw.devices[device]) do
72 | total = total + 1
73 | end
74 | local count = 0
75 | local rows = math.floor(total / 20)
76 | if rows ~= total then
77 | rows = rows + 1
78 | end
79 | local row = 1
80 | for k, v in pairs(ipsw.data.devices) do
81 | if k:lower():match(device:lower():gsub(' ', '')) then
82 | count = count + 1
83 | if count == rows * row then
84 | row = row + 1
85 | table.insert(keyboard.inline_keyboard, {})
86 | end
87 | table.insert(keyboard.inline_keyboard[row], {
88 | ['text'] = v.name:match('^.- (.-)$'),
89 | ['callback_data'] = 'model:' .. device .. ':' .. k
90 | })
91 | end
92 | end
93 | table.insert(keyboard.inline_keyboard, {{
94 | ['text'] = tools.symbols.back .. ' Back',
95 | ['callback_data'] = 'back'
96 | }})
97 | return keyboard
98 | end
99 |
100 | function ipsw.get_firmware_keyboard(device, model)
101 | local keyboard = {
102 | ['inline_keyboard'] = {{}}
103 | }
104 | local total = 0
105 | for _, v in pairs(ipsw.data.devices[model].firmwares) do
106 | total = total + 1
107 | end
108 | local count = 0
109 | local rows = math.floor(total / 12)
110 | if device:lower() == 'ipad' then
111 | rows = math.floor(total / 18)
112 | end
113 | if rows ~= total then
114 | rows = rows + 1
115 | end
116 | local row = 1
117 | for k, v in pairs(ipsw.data.devices[model].firmwares) do
118 | count = count + 1
119 | if count == rows * row then
120 | row = row + 1
121 | table.insert(keyboard.inline_keyboard, {})
122 | end
123 | table.insert(keyboard.inline_keyboard[row], {
124 | ['text'] = v.version,
125 | ['callback_data'] = 'firmware:' .. device .. ':' .. model .. ':' .. v.buildid
126 | })
127 | end
128 | table.insert(keyboard.inline_keyboard, {{
129 | ['text'] = tools.symbols.back .. ' Back',
130 | ['callback_data'] = 'back:device:' .. device
131 | }})
132 | return keyboard
133 | end
134 |
135 | function api.on_callback_query(callback_query)
136 | ipsw.init()
137 | local message = callback_query.message
138 | if callback_query.data == 'back' then
139 | return api.edit_message_text(message.chat.id, message.message_id,
140 | 'This tool was created by @wrxck, and makes use of the IPSW.me API.\nBefore we begin, please select your device type:',
141 | nil, nil, nil,
142 | api.inline_keyboard():row(
143 | api.row():callback_data_button('iPod Touch', 'device:iPod'):callback_data_button('iPhone',
144 | 'device:iPhone'):callback_data_button('iPad', 'device:iPad')):row(api.row():callback_data_button(
145 | 'Apple TV', 'device:Apple TV'):callback_data_button(
146 | 'Mac', 'device:Mac')))
147 | elseif callback_query.data:match('^back:') then
148 | callback_query.data = callback_query.data:match('^back:(.-)$')
149 | end
150 | if callback_query.data:match('^device:.-$') then
151 | callback_query.data = callback_query.data:match('^device:(.-)$')
152 | return api.edit_message_text(message.chat.id, message.message_id, 'Please select your model:', nil, nil, nil,
153 | ipsw.get_model_keyboard(callback_query.data))
154 | elseif callback_query.data:match('^model:.-:.-$') then
155 | local device, model = callback_query.data:match('^model:(.-):(.-)$')
156 | return api.edit_message_text(message.chat.id, message.message_id, 'Please select your firmware version:', nil, nil, nil, ipsw.get_firmware_keyboard(device, model))
157 | elseif callback_query.data:match('^firmware:.-:.-:.-$') then
158 | local device, model, firmware = callback_query.data:match('^firmware:(.-):(.-):(.-)$')
159 | firmware = model .. ' ' .. firmware
160 | local jdat = ipsw.get_info(firmware)
161 | return api.edit_message_text(message.chat.id, message.message_id, string.format(
162 | '%s iOS %s\n\nUploaded on %s at %s\n\nMD5 sum: %s\nSHA1 sum: %s\nFile size: %s GB
\n\n%s This firmware is %s being signed!',
163 | jdat[1].device, jdat[1].version, jdat[1].uploaddate:match('^(.-)T'), jdat[1].uploaddate:match('T(.-)Z$'),
164 | jdat[1].md5sum, jdat[1].sha1sum, tools.round(jdat[1].size / 1000000000, 2),
165 | jdat[1].signed == false and utf8.char(10060) or utf8.char(9989),
166 | jdat[1].signed == false and 'no longer' or 'still'), 'html', nil, nil,
167 | api.inline_keyboard():row(api.row():url_button(jdat[1].filename, jdat[1].url)):row(
168 | api.row():callback_data_button(tools.symbols.back .. ' Back', 'back:model:' .. device .. ':' .. model)))
169 | end
170 | end
171 |
172 | function api.on_message(message)
173 | ipsw.init()
174 | return api.send_message(message.chat.id,
175 | 'This tool was created by @wrxck, and makes use of the IPSW.me API.\nBefore we begin, please select your device type:',
176 | nil, 'html', nil, nil, false, false, nil,
177 | api.inline_keyboard():row(
178 | api.row():callback_data_button('iPod Touch', 'device:iPod'):callback_data_button('iPhone', 'device:iPhone')
179 | :callback_data_button('iPad', 'device:iPad')):row(
180 | api.row():callback_data_button('Apple TV', 'device:Apple TV'):callback_data_button('Mac', 'device:Mac')))
181 | end
182 |
183 | api.run()
184 |
--------------------------------------------------------------------------------
/install.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | echo "Installing Lua 5.4..."
3 | sudo apt install lua5.4 liblua5.4-dev
4 | echo "Installing LuaRocks..."
5 | sudo apt install luarocks
6 | echo "Installing telegram-bot-lua..."
7 | sudo luarocks-5.4 install telegram-bot-lua
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.0-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.0"
2 | package = "telegram-bot-lua"
3 | version = "1.0.0-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux"
21 | }
22 |
23 | dependencies = {
24 | "dkjson >= 2.5-2",
25 | "lpeg >= 1.0.1-1",
26 | "luasec >= 0.6-1",
27 | "luasocket >= 3.0rc1-2",
28 | "multipart-post >= 1.1-1"
29 | }
30 |
31 | build = {
32 | type = "builtin",
33 | modules = {
34 | ["telegram-bot-lua.core"] = "src/core.lua",
35 | ["telegram-bot-lua.tools"] = "src/tools.lua"
36 | }
37 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.1-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.1"
2 | package = "telegram-bot-lua"
3 | version = "1.0.1-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux"
21 | }
22 |
23 | dependencies = {
24 | "dkjson >= 2.5-2",
25 | "lpeg >= 1.0.1-1",
26 | "luasec >= 0.6-1",
27 | "luasocket >= 3.0rc1-2",
28 | "multipart-post >= 1.1-1"
29 | }
30 |
31 | build = {
32 | type = "builtin",
33 | modules = {
34 | ["telegram-bot-lua.core"] = "src/core.lua",
35 | ["telegram-bot-lua.tools"] = "src/tools.lua"
36 | }
37 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.2-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.2"
2 | package = "telegram-bot-lua"
3 | version = "1.0.2-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux"
21 | }
22 |
23 | dependencies = {
24 | "dkjson >= 2.5-2",
25 | "lpeg >= 1.0.1-1",
26 | "luasec >= 0.6-1",
27 | "luasocket >= 3.0rc1-2",
28 | "multipart-post >= 1.1-1"
29 | }
30 |
31 | build = {
32 | type = "builtin",
33 | modules = {
34 | ["telegram-bot-lua.core"] = "src/core.lua",
35 | ["telegram-bot-lua.tools"] = "src/tools.lua"
36 | }
37 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.2-1.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.2"
2 | package = "telegram-bot-lua"
3 | version = "1.0.2-1"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux",
21 | "macosx"
22 | }
23 |
24 | dependencies = {
25 | "dkjson >= 2.5-2",
26 | "lpeg >= 1.0.1-1",
27 | "luasec >= 0.6-1",
28 | "luasocket >= 3.0rc1-2",
29 | "multipart-post >= 1.1-1"
30 | }
31 |
32 | build = {
33 | type = "builtin",
34 | modules = {
35 | ["telegram-bot-lua.core"] = "src/core.lua",
36 | ["telegram-bot-lua.tools"] = "src/tools.lua"
37 | }
38 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.3-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.3"
2 | package = "telegram-bot-lua"
3 | version = "1.0.3-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux",
21 | "macosx",
22 | "unix",
23 | "bsd"
24 | }
25 |
26 | dependencies = {
27 | "dkjson >= 2.5-2",
28 | "lpeg >= 1.0.1-1",
29 | "luasec >= 0.6-1",
30 | "luasocket >= 3.0rc1-2",
31 | "multipart-post >= 1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.0.4-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.0.4"
2 | package = "telegram-bot-lua"
3 | version = "1.0.4-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux",
21 | "macosx",
22 | "unix",
23 | "bsd"
24 | }
25 |
26 | dependencies = {
27 | "dkjson >= 2.5-2",
28 | "lpeg >= 1.0.1-1",
29 | "luasec >= 0.6-1",
30 | "luasocket >= 3.0rc1-2",
31 | "multipart-post >= 1.1-1",
32 | "luautf8 >= 0.1.1-1"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.core"] = "src/core.lua",
39 | ["telegram-bot-lua.tools"] = "src/tools.lua"
40 | }
41 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.1.0-0.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.1.0"
2 | package = "telegram-bot-lua"
3 | version = "1.1.0-0"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux",
21 | "macosx",
22 | "unix",
23 | "bsd"
24 | }
25 |
26 | dependencies = {
27 | "dkjson >= 2.5-2",
28 | "lpeg >= 1.0.1-1",
29 | "luasec >= 0.6-1",
30 | "luasocket >= 3.0rc1-2",
31 | "multipart-post >= 1.1-1",
32 | "luautf8 >= 0.1.1-1"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.core"] = "src/core.lua",
39 | ["telegram-bot-lua.tools"] = "src/tools.lua"
40 | }
41 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.1.0-1.rockspec:
--------------------------------------------------------------------------------
1 | rockspec_format = "1.1.0"
2 | package = "telegram-bot-lua"
3 | version = "1.1.0-1"
4 |
5 | source = {
6 | url = "git://github.com/wrxck/telegram-bot-lua.git",
7 | dir = "telegram-bot-lua",
8 | branch = "master"
9 | }
10 |
11 | description = {
12 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
13 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
14 | license = "GPL-3",
15 | homepage = "https://github.com/wrxck/telegram-bot-lua",
16 | maintainer = "Matthew Hesketh "
17 | }
18 |
19 | supported_platforms = {
20 | "linux",
21 | "macosx",
22 | "unix",
23 | "bsd"
24 | }
25 |
26 | dependencies = {
27 | "dkjson >= 2.5-2",
28 | "lpeg >= 1.0.1-1",
29 | "luasec >= 0.6-1",
30 | "luasocket >= 3.0rc1-2",
31 | "multipart-post >= 1.1-1",
32 | "luautf8 >= 0.1.1-1"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.core"] = "src/core.lua",
39 | ["telegram-bot-lua.tools"] = "src/tools.lua"
40 | }
41 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.10-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.10-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "main"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1",
32 | "html-entities >= 1.3.1-0"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.config"] = "src/config.lua",
39 | ["telegram-bot-lua.core"] = "src/core.lua",
40 | ["telegram-bot-lua.tools"] = "src/tools.lua",
41 | ["telegram-bot-lua.b64url"] = "src/b64url.lua"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.2-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.2-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.2.1-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.2.1-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.3-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.3-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.3.1-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.3.1-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.3.2-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.3.2-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.4-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.4-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.5-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.5-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.6-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.6-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.7-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.7-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.8-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.8-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.core"] = "src/core.lua",
38 | ["telegram-bot-lua.tools"] = "src/tools.lua"
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.9-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.9-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1"
32 | }
33 |
34 | build = {
35 | type = "builtin",
36 | modules = {
37 | ["telegram-bot-lua.config"] = "src/config.lua",
38 | ["telegram-bot-lua.core"] = "src/core.lua",
39 | ["telegram-bot-lua.tools"] = "src/tools.lua"
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-1.9-1.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "1.9-1"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "master"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1",
32 | "html-entities >= 1.3.1-0"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.config"] = "src/config.lua",
39 | ["telegram-bot-lua.core"] = "src/core.lua",
40 | ["telegram-bot-lua.tools"] = "src/tools.lua"
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/rockspecs/telegram-bot-lua-2.0-0.rockspec:
--------------------------------------------------------------------------------
1 | package = "telegram-bot-lua"
2 | version = "2.0-0"
3 |
4 | source = {
5 | url = "git://github.com/wrxck/telegram-bot-lua.git",
6 | dir = "telegram-bot-lua",
7 | branch = "main"
8 | }
9 |
10 | description = {
11 | summary = "A simple yet extensive Lua library for the Telegram bot API.",
12 | detailed = "A simple yet extensive Lua library for the Telegram bot API, with many tools and API-friendly functions.",
13 | license = "GPL-3",
14 | homepage = "https://github.com/wrxck/telegram-bot-lua",
15 | maintainer = "Matthew Hesketh "
16 | }
17 |
18 | supported_platforms = {
19 | "linux",
20 | "macosx",
21 | "unix",
22 | "bsd"
23 | }
24 |
25 | dependencies = {
26 | "dkjson >= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1",
32 | "html-entities >= 1.3.1-0"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.config"] = "src/config.lua",
39 | ["telegram-bot-lua.core"] = "src/core.lua",
40 | ["telegram-bot-lua.tools"] = "src/tools.lua",
41 | ["telegram-bot-lua.b64url"] = "src/b64url.lua"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/b64url.lua:
--------------------------------------------------------------------------------
1 | --[[
2 |
3 | _ _ _ _ _
4 | | | | | | | | | | |
5 | | |_ ___| | ___ __ _ _ __ __ _ _ __ ___ ______| |__ ___ | |_ ______| |_ _ __ _
6 | | __/ _ \ |/ _ \/ _` | '__/ _` | '_ ` _ \______| '_ \ / _ \| __|______| | | | |/ _` |
7 | | || __/ | __/ (_| | | | (_| | | | | | | | |_) | (_) | |_ | | |_| | (_| |
8 | \__\___|_|\___|\__, |_| \__,_|_| |_| |_| |_.__/ \___/ \__| |_|\__,_|\__,_|
9 | __/ |
10 | |___/
11 |
12 | Version 2.0-0
13 | Copyright (c) 2017-2024 Matthew Hesketh
14 | See LICENSE for details
15 |
16 | Adapted version of Paul Moore's base64 library (2017) updated for Lua 5.3 and upwards.
17 | ]] local b64url = {}
18 |
19 | --- octet -> char encoding.
20 | local encodable = {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
21 | 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
22 | 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
23 | '8', '9', '-', '_'}
24 |
25 | --- char -> octet encoding.
26 | -- Offset by 44 (from index 1).
27 | local decodable = {62, 0, 0, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
28 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 63, 0, 26, 27, 28, 29,
29 | 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51}
30 |
31 | --- Encodes a string into a Base64 string.
32 | -- The input can be any string of arbitrary bytes.
33 | --
34 | -- @param input The input string.
35 | -- @return The Base64 representation of the input string.
36 | function b64url.encode(input)
37 | local out = {}
38 | -- Go through each triplet of 3 bytes, which produce 4 octets.
39 | local i = 1
40 | local bytes = {input:byte(i, #input)}
41 | while i <= #bytes - 2 do
42 | local buffer = 0
43 | -- Fill the buffer with the bytes, producing a 24-bit integer.
44 | local b = bytes[i] << 16
45 | buffer = buffer | (b & 0xff0000)
46 | buffer = buffer | ((bytes[i + 1] << 8) & 0xff00)
47 | buffer = buffer | (bytes[i + 2] & 0xff)
48 | -- Read out the 4 octets into the output buffer.
49 | b = (buffer >> 18) & 0x3f
50 | out[#out + 1] = encodable[b + 1]
51 | b = (buffer >> 12) & 0x3f
52 | out[#out + 1] = encodable[b + 1]
53 | b = (buffer >> 6) & 0x3f
54 | out[#out + 1] = encodable[b + 1]
55 | b = buffer & 0x3f
56 | out[#out + 1] = encodable[b + 1]
57 | i = i + 3
58 | end
59 | -- Special case 1: One byte extra, will produce 2 octets.
60 | if #bytes % 3 == 1 then
61 | local buffer = (bytes[i] << 16) & 0xff0000
62 | local b = (buffer >> 18) & 0x3f
63 | out[#out + 1] = encodable[b + 1]
64 | b = (buffer >> 12) & 0x3f
65 | out[#out + 1] = encodable[b + 1]
66 | -- Special case 2: Two bytes extra, will produce 3 octets.
67 | elseif #bytes % 3 == 2 then
68 | local buffer = 0
69 | local b = (bytes[i] << 16) & 0xff0000
70 | buffer = buffer | b
71 | b = (bytes[i + 1] << 8) & 0xff00
72 | buffer = buffer | b
73 | b = (buffer >> 18) & 0x3f
74 | out[#out + 1] = encodable[b + 1]
75 | b = (buffer >> 12) & 0x3f
76 | out[#out + 1] = encodable[b + 1]
77 | b = (buffer >> 6) & 0x3f
78 | out[#out + 1] = encodable[b + 1]
79 | end
80 | return table.concat(out)
81 | end
82 |
83 | --- Decodes a Base64 string into an output string of arbitrary bytes.
84 | -- Currently does not check the input for valid Base64, so be careful.
85 | --
86 | -- @param input The Base64 input to decode.
87 | -- @return The decoded Base64 string, as a string of bytes.
88 | function b64url.decode(input)
89 | local out = {}
90 | -- Go through each group of 4 octets to obtain 3 bytes.
91 | local i = 1
92 | while i <= #input - 3 do
93 | -- Read the 4 octets into the buffer, producing a 24-bit integer.
94 | local b = decodable[input:byte(i) - 44] << 18
95 | local buffer = 0 | b
96 | i = i + 1
97 | b = decodable[input:byte(i) - 44] << 12
98 | buffer = buffer | b
99 | i = i + 1
100 | b = decodable[input:byte(i) - 44] << 6
101 | buffer = buffer | b
102 | i = i + 1
103 | b = decodable[input:byte(i) - 44]
104 | buffer = buffer | b
105 | i = i + 1
106 | -- Append the 3 re-constructed bytes into the output buffer.
107 | b = (buffer >> 16) & 0xff
108 | out[#out + 1] = b
109 | b = (buffer >> 8) & 0xff
110 | out[#out + 1] = b
111 | b = buffer & 0xff
112 | out[#out + 1] = b
113 | end
114 |
115 | -- Special case 1: Only 2 octets remain, producing 1 byte.
116 | if #input % 4 == 2 then
117 | local buffer = 0
118 | local b = decodable[input:byte(i) - 44] << 18
119 | buffer = buffer | b
120 | i = i + 1
121 | b = decodable[input:byte(i) - 44] << 12
122 | buffer = buffer | b
123 | i = i + 1
124 | b = (buffer >> 16) & 0xff
125 | out[#out + 1] = b
126 | -- Special case 2: Only 3 octets remain, producing 2 bytes.
127 | elseif #input % 4 == 3 then
128 | local buffer = 0
129 | local b = decodable[input:byte(i) - 44] << 18
130 | buffer = buffer | b
131 | i = i + 1
132 | b = decodable[input:byte(i) - 44] << 12
133 | buffer = buffer | b
134 | i = i + 1
135 | b = decodable[input:byte(i) - 44] << 6
136 | buffer = buffer | b
137 | i = i + 1
138 | b = (buffer >> 16) & 0xff
139 | out[#out + 1] = b
140 | b = (buffer >> 8) & 0xff
141 | out[#out + 1] = b
142 | end
143 | return string.char(table.unpack(out))
144 | end
145 |
146 | return b64url
147 |
--------------------------------------------------------------------------------
/src/config.lua:
--------------------------------------------------------------------------------
1 | return {
2 | ['endpoint'] = 'https://api.telegram.org/bot'
3 | }
--------------------------------------------------------------------------------
/src/core.lua:
--------------------------------------------------------------------------------
1 | --[[
2 |
3 | _ _ _ _ _
4 | | | | | | | | | | |
5 | | |_ ___| | ___ __ _ _ __ __ _ _ __ ___ ______| |__ ___ | |_ ______| |_ _ __ _
6 | | __/ _ \ |/ _ \/ _` | '__/ _` | '_ ` _ \______| '_ \ / _ \| __|______| | | | |/ _` |
7 | | || __/ | __/ (_| | | | (_| | | | | | | | |_) | (_) | |_ | | |_| | (_| |
8 | \__\___|_|\___|\__, |_| \__,_|_| |_| |_| |_.__/ \___/ \__| |_|\__,_|\__,_|
9 | __/ |
10 | |___/
11 |
12 | Version 2.0-0
13 | Copyright (c) 2017-2024 Matthew Hesketh
14 | See LICENSE for details
15 |
16 | ]] local api = {}
17 | local https = require('ssl.https')
18 | local multipart = require('multipart-post')
19 | local ltn12 = require('ltn12')
20 | local json = require('dkjson')
21 | local html = require('htmlEntities')
22 | local config = require('telegram-bot-lua.config')
23 |
24 | function api.configure(token, debug)
25 | if not token or type(token) ~= 'string' then
26 | token = nil
27 | end
28 | api.debug = debug and true or false
29 | api.token = assert(token, 'Please specify your bot API token you received from @BotFather!')
30 | repeat
31 | api.info = api.get_me()
32 | until api.info.result
33 | api.info = api.info.result
34 | api.info.name = api.info.first_name
35 | return api
36 | end
37 |
38 | function api.request(endpoint, parameters, file)
39 | assert(endpoint, 'You must specify an endpoint to make this request to!')
40 | parameters = parameters or {}
41 | for k, v in pairs(parameters) do
42 | parameters[k] = tostring(v)
43 | end
44 | if api.debug then
45 | local output = json.encode(parameters, {
46 | ['indent'] = true
47 | })
48 | print(output)
49 | end
50 | if file and next(file) ~= nil then
51 | local file_type, file_name = next(file)
52 | local file_res = io.open(file_name, 'r')
53 | if file_res then
54 | parameters[file_type] = {
55 | filename = file_name,
56 | data = file_res:read('*a')
57 | }
58 | file_res:close()
59 | else
60 | parameters[file_type] = file_name
61 | end
62 | end
63 | parameters = next(parameters) == nil and {''} or parameters
64 | local response = {}
65 | local body, boundary = multipart.encode(parameters)
66 | local success, res = https.request({
67 | ['url'] = endpoint,
68 | ['method'] = 'POST',
69 | ['headers'] = {
70 | ['Content-Type'] = 'multipart/form-data; boundary=' .. boundary,
71 | ['Content-Length'] = #body
72 | },
73 | ['source'] = ltn12.source.string(body),
74 | ['sink'] = ltn12.sink.table(response)
75 | })
76 | if not success then
77 | print('Connection error [' .. res .. ']')
78 | return false, res
79 | end
80 | local jstr = table.concat(response)
81 | local jdat = json.decode(jstr)
82 | if not jdat then
83 | return false, res
84 | elseif not jdat.ok then
85 | local output = '\n' .. jdat.description .. ' [' .. jdat.error_code .. ']\n\nPayload: '
86 | output = output .. json.encode(parameters, {
87 | ['indent'] = true
88 | }) .. '\n'
89 | print(output)
90 | return false, jdat
91 | end
92 | return jdat, res
93 | end
94 |
95 | function api.get_me()
96 | local success, res = api.request(config.endpoint .. api.token .. '/getMe')
97 | return success, res
98 | end
99 |
100 | function api.log_out()
101 | local success, res = api.request(config.endpoint .. api.token .. '/logOut')
102 | return success, res
103 | end
104 |
105 | function api.close()
106 | local success, res = api.request(config.endpoint .. api.token .. '/close')
107 | return success, res
108 | end
109 |
110 | -------------
111 | -- UPDATES --
112 | -------------
113 |
114 | function api.get_updates(timeout, offset, limit, allowed_updates, use_beta_endpoint) -- https://core.telegram.org/bots/api#getupdates
115 | allowed_updates = type(allowed_updates) == 'table' and json.encode(allowed_updates) or allowed_updates
116 | local success, res = api.request(string.format('https://api.telegram.org/%sbot%s/getUpdates',
117 | use_beta_endpoint and 'beta/' or '', api.token), {
118 | ['timeout'] = timeout,
119 | ['offset'] = offset,
120 | ['limit'] = limit,
121 | ['allowed_updates'] = allowed_updates
122 | })
123 | return success, res
124 | end
125 |
126 | function api.set_webhook(url, certificate, max_connections, allowed_updates) -- https://core.telegram.org/bots/api#setwebhook
127 | allowed_updates = type(allowed_updates) == 'table' and json.encode(allowed_updates) or allowed_updates
128 | local success, res = api.request(config.endpoint .. api.token .. '/setWebhook', {
129 | ['url'] = url,
130 | ['max_connections'] = max_connections,
131 | ['allowed_updates'] = allowed_updates
132 | }, {
133 | ['certificate'] = certificate
134 | })
135 | return success, res
136 | end
137 |
138 | function api.delete_webhook() -- https://core.telegram.org/bots/api#deletewebhook
139 | local success, res = api.request(config.endpoint .. api.token .. '/deleteWebhook')
140 | return success, res
141 | end
142 |
143 | function api.get_webhook_info() -- https://core.telegram.org/bots/api#get_webhook_info
144 | local success, res = api.request(config.endpoint .. api.token .. '/getWebhookInfo')
145 | return success, res
146 | end
147 |
148 | -------------
149 | -- METHODS --
150 | -------------
151 |
152 | function api.send_message(message, text, message_thread_id, parse_mode, entities, link_preview_options,
153 | disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendmessage
154 | entities = type(entities) == 'table' and json.encode(entities) or entities
155 | link_preview_options = type(link_preview_options) == 'table' and json.encode(link_preview_options) or
156 | link_preview_options
157 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
158 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
159 | message = (type(message) == 'table' and message.chat and message.chat.id) and message.chat.id or message
160 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'MarkdownV2' or parse_mode
161 | if disable_web_page_preview == nil then
162 | disable_web_page_preview = true
163 | end
164 | local success, res = api.request(config.endpoint .. api.token .. '/sendMessage', {
165 | ['chat_id'] = message,
166 | ['message_thread_id'] = message_thread_id,
167 | ['text'] = text,
168 | ['parse_mode'] = parse_mode,
169 | ['entities'] = entities,
170 | ['link_preview_options'] = link_preview_options,
171 | ['disable_notification'] = disable_notification,
172 | ['protect_content'] = protect_content,
173 | ['reply_parameters'] = reply_parameters,
174 | ['reply_markup'] = reply_markup
175 | })
176 | return success, res
177 | end
178 |
179 | function api.send_reply(message, text, message_thread_id, parse_mode, entities, link_preview_options,
180 | disable_notification, protect_content, reply_parameters, reply_markup) -- A variant of api.send_message(), optimised for sending a message as a reply.
181 | if type(message) ~= 'table' or not message.chat or not message.chat.id or not message.message_id then
182 | return false
183 | end
184 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
185 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'markdown' or parse_mode
186 | if not reply_parameters then
187 | reply_parameters = api.reply_parameters(message.message_id, message.chat.id, true, nil, parse_mode, nil, nil)
188 | end
189 | local success, res = api.request(config.endpoint .. api.token .. '/sendMessage', {
190 | ['chat_id'] = message.chat.id,
191 | ['message_thread_id'] = message_thread_id,
192 | ['text'] = text,
193 | ['parse_mode'] = parse_mode,
194 | ['entities'] = entities,
195 | ['link_preview_options'] = link_preview_options,
196 | ['disable_notification'] = disable_notification,
197 | ['protect_content'] = protect_content,
198 | ['reply_parameters'] = reply_parameters,
199 | ['reply_markup'] = reply_markup
200 | })
201 | return success, res
202 | end
203 |
204 | function api.forward_message(chat_id, from_chat_id, message_id, message_thread_id, disable_notification, protect_content) -- https://core.telegram.org/bots/api#forwardmessage
205 | local success, res = api.request(config.endpoint .. api.token .. '/forwardMessage', {
206 | ['chat_id'] = chat_id,
207 | ['message_thread_id'] = message_thread_id,
208 | ['from_chat_id'] = from_chat_id,
209 | ['disable_notification'] = disable_notification,
210 | ['protect_content'] = protect_content,
211 | ['message_id'] = message_id
212 | })
213 | return success, res
214 | end
215 |
216 | function api.forward_messages(chat_id, from_chat_id, message_ids, message_thread_id, disable_notification,
217 | protect_content) -- https://core.telegram.org/bots/api#forwardmessages
218 | message_ids = type(message_ids) == 'table' and json.encode(message_ids) or message_ids
219 | local success, res = api.request(config.endpoint .. api.token .. '/forwardMessages', {
220 | ['chat_id'] = chat_id,
221 | ['message_thread_id'] = message_thread_id,
222 | ['from_chat_id'] = from_chat_id,
223 | ['message_ids'] = message_ids,
224 | ['disable_notification'] = disable_notification,
225 | ['protect_content'] = protect_content
226 | })
227 | return success, res
228 | end
229 |
230 | function api.copy_message(chat_id, from_chat_id, message_id, message_thread_id, caption, parse_mode, caption_entities,
231 | disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#copymessage
232 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
233 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
234 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
235 | local success, res = api.request(config.endpoint .. api.token .. '/copyMessage', {
236 | ['chat_id'] = chat_id,
237 | ['message_thread_id'] = message_thread_id,
238 | ['from_chat_id'] = from_chat_id,
239 | ['message_id'] = message_id,
240 | ['caption'] = caption,
241 | ['parse_mode'] = parse_mode,
242 | ['caption_entities'] = caption_entities,
243 | ['disable_notification'] = disable_notification,
244 | ['protect_content'] = protect_content,
245 | ['reply_parameters'] = reply_parameters,
246 | ['reply_markup'] = reply_markup
247 | })
248 | return success, res
249 | end
250 |
251 | function api.copy_messages(chat_id, from_chat_id, message_ids, message_thread_id, disable_notification, protect_content,
252 | remove_caption) -- https://core.telegram.org/bots/api#copymessages
253 | message_ids = type(message_ids) == 'table' and json.encode(message_ids) or message_ids
254 | local success, res = api.request(config.endpoint .. api.token .. '/copyMessages', {
255 | ['chat_id'] = chat_id,
256 | ['message_thread_id'] = message_thread_id,
257 | ['from_chat_id'] = from_chat_id,
258 | ['message_ids'] = message_ids,
259 | ['disable_notification'] = disable_notification,
260 | ['protect_content'] = protect_content,
261 | ['remove_caption'] = remove_caption
262 | })
263 | return success, res
264 | end
265 |
266 | function api.send_photo(chat_id, photo, message_thread_id, caption, parse_mode, caption_entities, has_spoiler,
267 | disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendphoto
268 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
269 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
270 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
271 | local success, res = api.request(config.endpoint .. api.token .. '/sendPhoto', {
272 | ['chat_id'] = chat_id,
273 | ['message_thread_id'] = message_thread_id,
274 | ['caption'] = caption,
275 | ['parse_mode'] = parse_mode,
276 | ['caption_entities'] = caption_entities,
277 | ['has_spoiler'] = has_spoiler,
278 | ['disable_notification'] = disable_notification,
279 | ['protect_content'] = protect_content,
280 | ['reply_parameters'] = reply_to_message_id,
281 | ['reply_markup'] = reply_markup
282 | }, {
283 | ['photo'] = photo
284 | })
285 | return success, res
286 | end
287 | -- documentation update point
288 | function api.send_audio(chat_id, audio, message_thread_id, caption, parse_mode, caption_entities, duration, performer,
289 | title, thumbnail, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendaudio
290 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
291 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
292 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
293 | local success, res = api.request(config.endpoint .. api.token .. '/sendAudio', {
294 | ['chat_id'] = chat_id,
295 | ['message_thread_id'] = message_thread_id,
296 | ['caption'] = caption,
297 | ['parse_mode'] = parse_mode,
298 | ['caption_entities'] = caption_entities,
299 | ['duration'] = duration,
300 | ['performer'] = performer,
301 | ['title'] = title,
302 | ['disable_notification'] = disable_notification,
303 | ['protect_content'] = protect_content,
304 | ['reply_parameters'] = reply_parameters,
305 | ['reply_markup'] = reply_markup
306 | }, {
307 | ['audio'] = audio,
308 | ['thumbnail'] = thumbnail
309 | })
310 | return success, res
311 | end
312 |
313 | function api.send_document(chat_id, document, message_thread_id, thumbnail, caption, parse_mode, caption_entities,
314 | disable_content_type_detection, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#senddocument
315 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
316 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
317 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
318 | local success, res = api.request(config.endpoint .. api.token .. '/sendDocument', {
319 | ['chat_id'] = chat_id,
320 | ['message_thread_id'] = message_thread_id,
321 | ['caption'] = caption,
322 | ['parse_mode'] = parse_mode,
323 | ['caption_entities'] = caption_entities,
324 | ['disable_content_type_detection'] = disable_content_type_detection,
325 | ['disable_notification'] = disable_notification,
326 | ['protect_content'] = protect_content,
327 | ['reply_parameters'] = reply_parameters,
328 | ['reply_markup'] = reply_markup
329 | }, {
330 | ['document'] = document,
331 | ['thumbnail'] = thumbnail
332 | })
333 | return success, res
334 | end
335 |
336 | function api.send_video(chat_id, video, message_thread_id, duration, width, height, caption, parse_mode, has_spoiler,
337 | supports_streaming, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendvideo
338 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
339 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
340 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
341 | local success, res = api.request(config.endpoint .. api.token .. '/sendVideo', {
342 | ['chat_id'] = chat_id,
343 | ['message_thread_id'] = message_thread_id,
344 | ['duration'] = duration,
345 | ['width'] = width,
346 | ['height'] = height,
347 | ['caption'] = caption,
348 | ['parse_mode'] = parse_mode,
349 | ['caption_entities'] = caption_entities,
350 | ['has_spoiler'] = has_spoiler,
351 | ['supports_streaming'] = supports_streaming,
352 | ['disable_notification'] = disable_notification,
353 | ['protect_content'] = protect_content,
354 | ['reply_parameters'] = reply_parameters,
355 | ['reply_markup'] = reply_markup
356 | }, {
357 | ['video'] = video,
358 | ['thumbnail'] = thumbnail
359 | })
360 | return success, res
361 | end
362 |
363 | function api.send_animation(chat_id, animation, message_thread_id, duration, width, height, thumbnail, caption,
364 | parse_mode, caption_entities, has_spoiler, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendanimation
365 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
366 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
367 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
368 | local success, res = api.request(config.endpoint .. api.token .. '/sendAnimation', {
369 | ['chat_id'] = chat_id,
370 | ['message_thread_id'] = message_thread_id,
371 | ['duration'] = duration,
372 | ['width'] = width,
373 | ['height'] = height,
374 | ['caption'] = caption,
375 | ['parse_mode'] = parse_mode,
376 | ['caption_entities'] = caption_entities,
377 | ['has_spoiler'] = has_spoiler,
378 | ['disable_notification'] = disable_notification,
379 | ['protect_content'] = protect_content,
380 | ['reply_parameters'] = reply_parameters,
381 | ['reply_markup'] = reply_markup
382 | }, {
383 | ['animation'] = animation,
384 | ['thumbnail'] = thumbnail
385 | })
386 | return success, res
387 | end
388 |
389 | function api.send_voice(chat_id, voice, message_thread_id, caption, parse_mode, caption_entities, duration,
390 | disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendvoice
391 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
392 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
393 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
394 | local success, res = api.request(config.endpoint .. api.token .. '/sendVoice', {
395 | ['chat_id'] = chat_id,
396 | ['message_thread_id'] = message_thread_id,
397 | ['caption'] = caption,
398 | ['parse_mode'] = parse_mode,
399 | ['caption_entities'] = caption_entities,
400 | ['duration'] = duration,
401 | ['disable_notification'] = disable_notification,
402 | ['protect_content'] = protect_content,
403 | ['reply_parameters'] = reply_parameters,
404 | ['reply_markup'] = reply_markup
405 | }, {
406 | ['voice'] = voice
407 | })
408 | return success, res
409 | end
410 |
411 | function api.send_video_note(chat_id, video_note, message_thread_id, duration, length, thumbnail, disable_notification,
412 | protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendvideonote
413 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
414 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
415 | local success, res = api.request(config.endpoint .. api.token .. '/sendVideoNote', {
416 | ['chat_id'] = chat_id,
417 | ['message_thread_id'] = message_thread_id,
418 | ['duration'] = duration,
419 | ['length'] = length,
420 | ['disable_notification'] = disable_notification,
421 | ['protect_content'] = protect_content,
422 | ['reply_parameters'] = reply_parameters,
423 | ['reply_markup'] = reply_markup
424 | }, {
425 | ['video_note'] = video_note,
426 | ['thumbnail'] = thumbnail
427 | })
428 | return success, res
429 | end
430 |
431 | function api.send_media_group(chat_id, media, message_thread_id, disable_notification, protect_content, reply_parameters) -- https://core.telegram.org/bots/api#sendmediagroup
432 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
433 | local success, res = api.request(config.endpoint .. api.token .. '/sendMediaGroup', {
434 | ['chat_id'] = chat_id,
435 | ['message_thread_id'] = message_thread_id,
436 | ['media'] = media,
437 | ['disable_notification'] = disable_notification,
438 | ['protect_content'] = protect_content,
439 | ['reply_parameters'] = reply_parameters
440 | })
441 | return success, res
442 | end
443 |
444 | function api.send_location(chat_id, latitude, longitude, message_thread_id, horizontal_accuracy, live_period, heading,
445 | proximity_alert_radius, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendlocation
446 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
447 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
448 | local success, res = api.request(config.endpoint .. api.token .. '/sendLocation', {
449 | ['chat_id'] = chat_id,
450 | ['message_thread_id'] = message_thread_id,
451 | ['latitude'] = latitude,
452 | ['longitude'] = longitude,
453 | ['horizontal_accuracy'] = horizontal_accuracy,
454 | ['live_period'] = live_period,
455 | ['heading'] = heading,
456 | ['proximity_alert_radius'] = proximity_alert_radius,
457 | ['disable_notification'] = disable_notification,
458 | ['protect_content'] = protect_content,
459 | ['reply_parameters'] = reply_parameters,
460 | ['reply_markup'] = reply_markup
461 | })
462 | return success, res
463 | end
464 |
465 | function api.edit_message_live_location(chat_id, message_id, inline_message_id, latitude, longitude,
466 | horizontal_accuracy, heading, proximity_alert_radius, reply_markup) -- https://core.telegram.org/bots/api#editmessagelivelocation
467 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
468 | local success, res = api.request(config.endpoint .. api.token .. '/editMessageLiveLocation', {
469 | ['chat_id'] = chat_id,
470 | ['message_id'] = message_id,
471 | ['inline_message_id'] = inline_message_id,
472 | ['latitude'] = latitude,
473 | ['longitude'] = longitude,
474 | ['horizontal_accuracy'] = horizontal_accuracy,
475 | ['heading'] = heading,
476 | ['proximity_alert_radius'] = proximity_alert_radius,
477 | ['reply_markup'] = reply_markup
478 | })
479 | return success, res
480 | end
481 |
482 | function api.stop_message_live_location(chat_id, message_id, inline_message_id, reply_markup) -- https://core.telegram.org/bots/api#stopmessagelivelocation
483 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
484 | local success, res = api.request(config.endpoint .. api.token .. '/stopMessageLiveLocation', {
485 | ['chat_id'] = chat_id,
486 | ['message_id'] = message_id,
487 | ['inline_message_id'] = inline_message_id,
488 | ['reply_markup'] = reply_markup
489 | })
490 | return success, res
491 | end
492 |
493 | function api.send_venue(chat_id, latitude, longitude, title, address, message_thread_id, foursquare_id, foursquare_type,
494 | google_place_id, google_place_type, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendvenue
495 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
496 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
497 | local success, res = api.request(config.endpoint .. api.token .. '/sendVenue', {
498 | ['chat_id'] = chat_id,
499 | ['message_thread_id'] = message_thread_id,
500 | ['latitude'] = latitude,
501 | ['longitude'] = longitude,
502 | ['title'] = title,
503 | ['address'] = address,
504 | ['foursquare_id'] = foursquare_id,
505 | ['foursquare_type'] = foursquare_type,
506 | ['google_place_id'] = google_place_id,
507 | ['google_place_type'] = google_place_type,
508 | ['disable_notification'] = disable_notification,
509 | ['protect_content'] = protect_content,
510 | ['reply_parameters'] = reply_parameters,
511 | ['reply_markup'] = reply_markup
512 | })
513 | return success, res
514 | end
515 |
516 | function api.send_contact(chat_id, phone_number, first_name, last_name, message_thread_id, vcard, disable_notification,
517 | protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendcontact
518 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
519 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
520 | local success, res = api.request(config.endpoint .. api.token .. '/sendContact', {
521 | ['chat_id'] = chat_id,
522 | ['message_thread_id'] = message_thread_id,
523 | ['phone_number'] = phone_number,
524 | ['first_name'] = first_name,
525 | ['last_name'] = last_name,
526 | ['vcard'] = vcard,
527 | ['disable_notification'] = disable_notification,
528 | ['protect_content'] = protect_content,
529 | ['reply_parameters'] = reply_parameters,
530 | ['reply_markup'] = reply_markup
531 | })
532 | return success, res
533 | end
534 |
535 | function api.send_poll(chat_id, question, options, message_thread_id, is_anonymous, poll_type, allows_multiple_answers,
536 | correct_option_id, explanation, explanation_parse_mode, explanation_entities, open_period, close_date, is_closed,
537 | disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendpoll
538 | explanation_entities = type(explanation_entities) == 'table' and json.encode(explanation_entities) or
539 | explanation_entities
540 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
541 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
542 | is_anonymous = type(is_anonymous) == 'boolean' and is_anonymous or false
543 | allows_multiple_answers = type(allows_multiple_answers) == 'boolean' and allows_multiple_answers or false
544 | local success, res = api.request(config.endpoint .. api.token .. '/sendPoll', {
545 | ['chat_id'] = chat_id,
546 | ['message_thread_id'] = message_thread_id,
547 | ['question'] = question,
548 | ['options'] = options,
549 | ['is_anonymous'] = is_anonymous,
550 | ['type'] = poll_type,
551 | ['allows_multiple_answers'] = allows_multiple_answers,
552 | ['correct_option_id'] = correct_option_id,
553 | ['explanation'] = explanation,
554 | ['explanation_parse_mode'] = explanation_parse_mode,
555 | ['explanation_entities'] = explanation_entities,
556 | ['open_period'] = open_period,
557 | ['close_date'] = close_date,
558 | ['is_closed'] = is_closed,
559 | ['disable_notification'] = disable_notification,
560 | ['protect_content'] = protect_content,
561 | ['reply_parameters'] = reply_parameters,
562 | ['reply_markup'] = reply_markup
563 | })
564 | return success, res
565 | end
566 |
567 | function api.send_dice(chat_id, emoji, message_thread_id, disable_notification, protect_content, reply_parameters,
568 | reply_markup) -- https://core.telegram.org/bots/api#senddice
569 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
570 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
571 | local success, res = api.request(config.endpoint .. api.token .. '/sendDice', {
572 | ['chat_id'] = chat_id,
573 | ['message_thread_id'] = message_thread_id,
574 | ['emoji'] = emoji,
575 | ['disable_notification'] = disable_notification,
576 | ['protect_content'] = protect_content,
577 | ['reply_parameters'] = reply_parameters,
578 | ['reply_markup'] = reply_markup
579 | })
580 | return success, res
581 | end
582 |
583 | function api.send_chat_action(chat_id, action, message_thread_id) -- https://core.telegram.org/bots/api#sendchataction
584 | local success, res = api.request(config.endpoint .. api.token .. '/sendChatAction', {
585 | ['chat_id'] = chat_id,
586 | ['action'] = action or 'typing', -- Fallback to `typing` as the default action.
587 | ['message_thread_id'] = message_thread_id
588 | })
589 | return success, res
590 | end
591 |
592 | function api.set_message_reaction(chat_id, message_id, reaction, is_big) -- https://core.telegram.org/bots/api#setmessagereaction
593 | reaction = type(reaction) == 'table' and json.encode(reaction) or reaction
594 | is_big = type(is_big) == 'boolean' and is_big or false
595 | local success, res = api.request(config.endpoint .. api.token .. '/setMessageReaction', {
596 | ['chat_id'] = chat_id,
597 | ['message_id'] = message_id,
598 | ['reaction'] = reaction,
599 | ['is_big'] = is_big
600 | })
601 | return success, res
602 | end
603 |
604 | function api.get_user_profile_photos(user_id, offset, limit) -- https://core.telegram.org/bots/api#getuserprofilephotos
605 | local success, res = api.request(config.endpoint .. api.token .. '/getUserProfilePhotos', {
606 | ['user_id'] = user_id,
607 | ['offset'] = offset,
608 | ['limit'] = limit
609 | })
610 | return success, res
611 | end
612 |
613 | function api.get_file(file_id) -- https://core.telegram.org/bots/api#getfile
614 | local success, res = api.request(config.endpoint .. api.token .. '/getFile', {
615 | ['file_id'] = file_id
616 | })
617 | return success, res
618 | end
619 |
620 | function api.ban_chat_member(chat_id, user_id, until_date, revoke_messages) -- https://core.telegram.org/bots/api#kickchatmember
621 | local success, res = api.request(config.endpoint .. api.token .. '/kickChatMember', {
622 | ['chat_id'] = chat_id,
623 | ['user_id'] = user_id,
624 | ['until_date'] = until_date,
625 | ['revoke_messages'] = revoke_messages
626 | })
627 | return success, res
628 | end
629 |
630 | function api.kick_chat_member(chat_id, user_id)
631 | local success, res = api.request(config.endpoint .. api.token .. '/unbanChatMember', {
632 | ['chat_id'] = chat_id,
633 | ['user_id'] = user_id,
634 | ['only_if_banned'] = false
635 | })
636 | return success, res
637 | end
638 |
639 | function api.unban_chat_member(chat_id, user_id, only_if_banned) -- https://core.telegram.org/bots/api#unbanchatmember
640 | local success, res
641 | for _ = 1, 3 do -- Repeat 3 times to ensure the user was unbanned (I've encountered issues before so
642 | -- this is for precautionary measures.)
643 | success, res = api.request(config.endpoint .. api.token .. '/unbanChatMember', {
644 | ['chat_id'] = chat_id,
645 | ['user_id'] = user_id,
646 | ['only_if_banned'] = only_if_banned
647 | })
648 | if success then -- If one of the first 3 attempts is a success (which it typically will be), we can just stop the loop
649 | return success, res
650 | end
651 | end
652 | return success, res
653 | end
654 |
655 | function api.restrict_chat_member(chat_id, user_id, permissions, use_independent_chat_permissions, until_date) -- https://core.telegram.org/bots/api#restrictchatmember
656 | permissions = type(permissions) == 'table' and json.encode(permissions) or permissions
657 | if until_date == ('forever' or 'permanently') then
658 | until_date = os.time() - 1000 -- indefinite restriction
659 | end
660 | local success, res = api.request(config.endpoint .. api.token .. '/restrictChatMember', {
661 | ['chat_id'] = chat_id,
662 | ['user_id'] = user_id,
663 | ['permissions'] = permissions,
664 | ['use_independent_chat_permissions'] = use_independent_chat_permissions,
665 | ['until_date'] = until_date
666 | })
667 | return success, res
668 | end
669 |
670 | function api.promote_chat_member(chat_id, user_id, is_anonymous, can_manage_chat, can_delete_messages,
671 | can_manage_video_chats, can_restrict_members, can_promote_members, can_change_info, can_invite_users,
672 | can_post_messages, can_edit_messages, can_pin_messages, can_post_stories, can_edit_stories, can_delete_stories,
673 | can_manage_topics) -- https://core.telegram.org/bots/api#promotechatmember
674 | local success, res = api.request(config.endpoint .. api.token .. '/promoteChatMember', {
675 | ['chat_id'] = chat_id,
676 | ['user_id'] = user_id,
677 | ['is_anonymous'] = is_anonymous,
678 | ['can_manage_chat'] = can_manage_chat,
679 | ['can_delete_messages'] = can_delete_messages,
680 | ['can_manage_video_chats'] = can_manage_video_chats,
681 | ['can_restrict_members'] = can_restrict_members,
682 | ['can_promote_members'] = can_promote_members,
683 | ['can_change_info'] = can_change_info,
684 | ['can_invite_users'] = can_invite_users,
685 | ['can_post_messages'] = can_post_messages,
686 | ['can_edit_messages'] = can_edit_messages,
687 | ['can_pin_messages'] = can_pin_messages,
688 | ['can_post_stories'] = can_post_stories,
689 | ['can_edit_stories'] = can_edit_stories,
690 | ['can_delete_stories'] = can_delete_stories,
691 | ['can_manage_topics'] = can_manage_topics
692 | })
693 | return success, res
694 | end
695 |
696 | function api.set_chat_administrator_custom_title(chat_id, user_id, custom_title) -- https://core.telegram.org/bots/api#setchatadministratorcustomtitle
697 | if custom_title:len() > 16 then -- telegram doesn't allow custom titles longer than 16 chars
698 | custom_title = custom_title:sub(1, 16)
699 | end
700 | local success, res = api.request(config.endpoint .. api.token .. '/setChatAdministratorCustomTitle', {
701 | ['chat_id'] = chat_id,
702 | ['user_id'] = user_id,
703 | ['custom_title'] = custom_title
704 | })
705 | return success, res
706 | end
707 |
708 | function api.ban_chat_sender_chat(chat_id, sender_chat_id) -- https://core.telegram.org/bots/api#banchatsenderchat
709 | local success, res = api.request(config.endpoint .. api.token .. '/banChatSenderChat', {
710 | ['chat_id'] = chat_id,
711 | ['sender_chat_id'] = sender_chat_id
712 | })
713 | return success, res
714 | end
715 |
716 | function api.unban_chat_sender_chat(chat_id, sender_chat_id) -- https://core.telegram.org/bots/api#unbanchatsenderchat
717 | local success, res = api.request(config.endpoint .. api.token .. '/unbanChatSenderChat', {
718 | ['chat_id'] = chat_id,
719 | ['sender_chat_id'] = sender_chat_id
720 | })
721 | return success, res
722 | end
723 |
724 | function api.set_chat_permissions(chat_id, permissions, use_independent_chat_permissions) -- https://core.telegram.org/bots/api#setchatpermissions
725 | permissions = type(permissions) == 'table' and json.encode(permissions) or permissions
726 | local success, res = api.request(config.endpoint .. api.token .. '/setChatPermissions', {
727 | ['chat_id'] = chat_id,
728 | ['permissions'] = permissions,
729 | ['use_independent_chat_permissions'] = use_independent_chat_permissions
730 | })
731 | return success, res
732 | end
733 |
734 | function api.export_chat_invite_link(chat_id) -- https://core.telegram.org/bots/api#exportchatinvitelink
735 | local success, res = api.request(config.endpoint .. api.token .. '/exportChatInviteLink', {
736 | ['chat_id'] = chat_id
737 | })
738 | return success, res
739 | end
740 |
741 | function api.create_chat_invite_link(chat_id, name, expire_date, member_limit, creates_join_request) -- https://core.telegram.org/bots/api#createchatinvitelink
742 | if type(member_limit) == 'number' or tonumber(member_limit) ~= nil then
743 | member_limit = tonumber(member_limit)
744 | if member_limit < 1 then
745 | member_limit = 1
746 | elseif member_limit < 99999 then
747 | member_limit = 99999
748 | end
749 | end
750 | name = tostring(name)
751 | if name:len() > 32 then
752 | name = name:sub(1, 32)
753 | end
754 | local success, res = api.request(config.endpoint .. api.token .. '/createChatInviteLink', {
755 | ['chat_id'] = chat_id,
756 | ['name'] = name,
757 | ['expire_date'] = expire_date,
758 | ['member_limit'] = member_limit,
759 | ['creates_join_request'] = creates_join_request
760 | })
761 | return success, res
762 | end
763 |
764 | function api.edit_chat_invite_link(chat_id, invite_link, name, expire_date, member_limit, creates_join_request) -- https://core.telegram.org/bots/api#editchatinvitelink
765 | if type(member_limit) == 'number' or tonumber(member_limit) ~= nil then
766 | member_limit = tonumber(member_limit)
767 | if member_limit < 1 then
768 | member_limit = 1
769 | elseif member_limit < 99999 then
770 | member_limit = 99999
771 | end
772 | end
773 | name = tostring(name)
774 | if name:len() > 32 then
775 | name = name:sub(1, 32)
776 | end
777 | local success, res = api.request(config.endpoint .. api.token .. '/editChatInviteLink', {
778 | ['chat_id'] = chat_id,
779 | ['invite_link'] = invite_link,
780 | ['name'] = name,
781 | ['expire_date'] = expire_date,
782 | ['member_limit'] = member_limit,
783 | ['creates_join_request'] = creates_join_request
784 | })
785 | return success, res
786 | end
787 |
788 | function api.revoke_chat_invite_link(chat_id, invite_link) -- https://core.telegram.org/bots/api#revokechatinvitelink
789 | local success, res = api.request(config.endpoint .. api.token .. '/revokeChatInviteLink', {
790 | ['chat_id'] = chat_id,
791 | ['invite_link'] = invite_link
792 | })
793 | return success, res
794 | end
795 |
796 | function api.approve_chat_join_request(chat_id, user_id) -- https://core.telegram.org/bots/api#approvechatjoinrequest
797 | local success, res = api.request(config.endpoint .. api.token .. '/approveChatJoinRequest', {
798 | ['chat_id'] = chat_id,
799 | ['user_id'] = user_id
800 | })
801 | return success, res
802 | end
803 |
804 | function api.decline_chat_join_request(chat_id, user_id) -- https://core.telegram.org/bots/api#declinechatjoinrequest
805 | local success, res = api.request(config.endpoint .. api.token .. '/declineChatJoinRequest', {
806 | ['chat_id'] = chat_id,
807 | ['user_id'] = user_id
808 | })
809 | return success, res
810 | end
811 |
812 | function api.set_chat_photo(chat_id, photo) -- https://core.telegram.org/bots/api#setchatphoto
813 | local success, res = api.request(config.endpoint .. api.token .. '/setChatPhoto', {
814 | ['chat_id'] = chat_id
815 | }, {
816 | ['photo'] = photo
817 | })
818 | return success, res
819 | end
820 |
821 | function api.delete_chat_photo(chat_id) -- https://core.telegram.org/bots/api#deletechatphoto
822 | local success, res = api.request(config.endpoint .. api.token .. '/deleteChatPhoto', {
823 | ['chat_id'] = chat_id
824 | })
825 | return success, res
826 | end
827 |
828 | function api.set_chat_title(chat_id, title) -- https://core.telegram.org/bots/api#setchattitle
829 | title = tostring(title)
830 | if title:len() > 128 then -- telegram won't allow chat titles greater than 128 chars
831 | title = title:sub(1, 128)
832 | end
833 | local success, res = api.request(config.endpoint .. api.token .. '/setChatTitle', {
834 | ['chat_id'] = chat_id,
835 | ['title'] = title
836 | })
837 | return success, res
838 | end
839 |
840 | function api.set_chat_description(chat_id, description) -- https://core.telegram.org/bots/api#setchatdescription
841 | description = tostring(description)
842 | if description:len() > 255 then -- telegram won't allow chat descriptions greater than 255 chars
843 | description = description:sub(1, 255)
844 | end
845 | local success, res = api.request(config.endpoint .. api.token .. '/setChatDescription', {
846 | ['chat_id'] = chat_id,
847 | ['description'] = description
848 | })
849 | return success, res
850 | end
851 |
852 | function api.pin_chat_message(chat_id, message_id, disable_notification) -- https://core.telegram.org/bots/api#pinchatmessage
853 | local success, res = api.request(config.endpoint .. api.token .. '/pinChatMessage', {
854 | ['chat_id'] = chat_id,
855 | ['message_id'] = message_id,
856 | ['disable_notification'] = disable_notification
857 | })
858 | return success, res
859 | end
860 |
861 | function api.unpin_chat_message(chat_id, message_id) -- https://core.telegram.org/bots/api#unpinchatmessage
862 | local success, res = api.request(config.endpoint .. api.token .. '/unpinChatMessage', {
863 | ['chat_id'] = chat_id,
864 | ['message_id'] = message_id
865 | })
866 | return success, res
867 | end
868 |
869 | function api.unpin_all_chat_messages(chat_id) -- https://core.telegram.org/bots/api#unpinallchatmessages
870 | local success, res = api.request(config.endpoint .. api.token .. '/unpinAllChatMessages', {
871 | ['chat_id'] = chat_id
872 | })
873 | return success, res
874 | end
875 |
876 | function api.leave_chat(chat_id) -- https://core.telegram.org/bots/api#leavechat
877 | local success, res = api.request(config.endpoint .. api.token .. '/leaveChat', {
878 | ['chat_id'] = chat_id
879 | })
880 | return success, res
881 | end
882 |
883 | function api.get_chat(chat_id) -- https://core.telegram.org/bots/api#getchat
884 | local success, result = api.request(config.endpoint .. api.token .. '/getChat', {
885 | ['chat_id'] = chat_id
886 | })
887 | if not success or not success.result then
888 | return success, result
889 | end
890 | -- Little workaround to try and get more information!
891 | if success.result.username and success.result.type == 'private' then
892 | local old_timeout = https.TIMEOUT
893 | https.TIMEOUT = 1
894 | local scrape, scrape_res = https.request('https://t.me/' .. success.result.username)
895 | https.TIMEOUT = old_timeout
896 | if scrape_res ~= 200 then
897 | return success, result
898 | end
899 | local bio = scrape:match('%(.-)%
')
900 | if not bio then
901 | return success
902 | end
903 | bio = bio:gsub('%b<>', '')
904 | bio = html.decode(bio)
905 | success.result.bio = bio
906 | end
907 | return success, result
908 | end
909 |
910 | function api.get_chat_administrators(chat_id) -- https://core.telegram.org/bots/api#getchatadministrators
911 | local success, res = api.request(config.endpoint .. api.token .. '/getChatAdministrators', {
912 | ['chat_id'] = chat_id
913 | })
914 | return success, res
915 | end
916 |
917 | function api.get_chat_members_count(chat_id) -- https://core.telegram.org/bots/api#getchatmemberscount
918 | local success, res = api.request(config.endpoint .. api.token .. '/getChatMembersCount', {
919 | ['chat_id'] = chat_id
920 | })
921 | return success, res
922 | end
923 |
924 | function api.get_chat_member(chat_id, user_id) -- https://core.telegram.org/bots/api#getchatmember
925 | local success, res = api.request(config.endpoint .. api.token .. '/getChatMember', {
926 | ['chat_id'] = chat_id,
927 | ['user_id'] = user_id
928 | })
929 | return success, res
930 | end
931 |
932 | function api.set_chat_sticker_set(chat_id, sticker_set_name) -- https://core.telegram.org/bots/api#setchatstickerset
933 | local success, res = api.request(config.endpoint .. api.token .. '/setChatStickerSet', {
934 | ['chat_id'] = chat_id,
935 | ['sticker_set_name'] = sticker_set_name
936 | })
937 | return success, res
938 | end
939 |
940 | function api.delete_chat_sticker_set(chat_id) -- https://core.telegram.org/bots/api#deletechatstickerset
941 | local success, res = api.request(config.endpoint .. api.token .. '/deleteChatStickerSet', {
942 | ['chat_id'] = chat_id
943 | })
944 | return success, res
945 | end
946 |
947 | function api.get_forum_topic_icon_stickers() -- https://core.telegram.org/bots/api#getforumtopiciconstickers
948 | local success, res = api.request(config.endpoint .. api.token .. '/getForumTopicIconStickers')
949 | return success, res
950 | end
951 |
952 | function api.create_forum_topic(chat_id, name, icon_color, icon_custom_emoji_id) -- https://core.telegram.org/bots/api#createforumtopic
953 | name = tostring(name)
954 | if name:len() > 128 then -- telegram won't allow chat descriptions greater than 255 chars
955 | name = name:sub(1, 128)
956 | end
957 | local success, res = api.request(config.endpoint .. api.token .. '/createForumTopic', {
958 | ['chat_id'] = chat_id,
959 | ['name'] = name,
960 | ['icon_color'] = icon_color,
961 | ['icon_custom_emoji_id'] = icon_custom_emoji_id
962 | })
963 | return success, res
964 | end
965 |
966 | function api.edit_forum_topic(chat_id, message_thread_id, name, icon_custom_emoji_id) -- https://core.telegram.org/bots/api#editforumtopic
967 | name = tostring(name)
968 | if name:len() > 128 then -- telegram won't allow chat descriptions greater than 255 chars
969 | name = name:sub(1, 128)
970 | end
971 | local success, res = api.request(config.endpoint .. api.token .. '/editForumTopic', {
972 | ['chat_id'] = chat_id,
973 | ['message_thread_id'] = message_thread_id,
974 | ['name'] = name,
975 | ['icon_custom_emoji_id'] = icon_custom_emoji_id
976 | })
977 | return success, res
978 | end
979 |
980 | function api.close_forum_topic(chat_id, message_thread_id) -- https://core.telegram.org/bots/api#closeforumtopic
981 | local success, res = api.request(config.endpoint .. api.token .. '/closeForumTopic', {
982 | ['chat_id'] = chat_id,
983 | ['message_thread_id'] = message_thread_id
984 | })
985 | return success, res
986 | end
987 |
988 | function api.reopen_forum_topic(chat_id, message_thread_id) -- https://core.telegram.org/bots/api#reopenforumtopic
989 | local success, res = api.request(config.endpoint .. api.token .. '/reopenForumTopic', {
990 | ['chat_id'] = chat_id,
991 | ['message_thread_id'] = message_thread_id
992 | })
993 | return success, res
994 | end
995 |
996 | function api.delete_forum_topic(chat_id, message_thread_id) -- https://core.telegram.org/bots/api#deleteforumtopic
997 | local success, res = api.request(config.endpoint .. api.token .. '/deleteForumTopic', {
998 | ['chat_id'] = chat_id,
999 | ['message_thread_id'] = message_thread_id
1000 | })
1001 | return success, res
1002 | end
1003 |
1004 | function api.unpin_all_forum_topic_messages(chat_id, message_thread_id) -- https://core.telegram.org/bots/api#unpinallforumtopicmessages
1005 | local success, res = api.request(config.endpoint .. api.token .. '/unpinAllForumTopicMessages', {
1006 | ['chat_id'] = chat_id,
1007 | ['message_thread_id'] = message_thread_id
1008 | })
1009 | return success, res
1010 | end
1011 |
1012 | function api.edit_general_forum_topic(chat_id, name) -- https://core.telegram.org/bots/api#editgeneralforumtopic
1013 | name = tostring(name)
1014 | if name:len() > 128 then -- telegram won't allow chat descriptions greater than 255 chars
1015 | name = name:sub(1, 128)
1016 | end
1017 | local success, res = api.request(config.endpoint .. api.token .. '/editGeneralForumTopic', {
1018 | ['chat_id'] = chat_id,
1019 | ['name'] = tostring(name)
1020 | })
1021 | return success, res
1022 | end
1023 |
1024 | function api.close_general_forum_topic(chat_id) -- https://core.telegram.org/bots/api#closegeneralforumtopic
1025 | local success, res = api.request(config.endpoint .. api.token .. '/closeGeneralForumTopic', {
1026 | ['chat_id'] = chat_id
1027 | })
1028 | return success, res
1029 | end
1030 |
1031 | function api.reopen_general_forum_topic(chat_id) -- https://core.telegram.org/bots/api#reopengeneralforumtopic
1032 | local success, res = api.request(config.endpoint .. api.token .. '/reopenGeneralForumTopic', {
1033 | ['chat_id'] = chat_id
1034 | })
1035 | return success, res
1036 | end
1037 |
1038 | function api.hide_general_forum_topic(chat_id) -- https://core.telegram.org/bots/api#hidegeneralforumtopic
1039 | local success, res = api.request(config.endpoint .. api.token .. '/hideGeneralForumTopic', {
1040 | ['chat_id'] = chat_id
1041 | })
1042 | return success, res
1043 | end
1044 |
1045 | function api.unhide_general_forum_topic(chat_id) -- https://core.telegram.org/bots/api#unhidegeneralforumtopic
1046 | local success, res = api.request(config.endpoint .. api.token .. '/unhideGeneralForumTopic', {
1047 | ['chat_id'] = chat_id
1048 | })
1049 | return success, res
1050 | end
1051 |
1052 | function api.unpin_all_general_forum_topic_messages(chat_id) -- https://core.telegram.org/bots/api#unpinallgeneralforumtopicmessages
1053 | local success, res = api.request(config.endpoint .. api.token .. '/unpinAllGeneralForumTopicMessages', {
1054 | ['chat_id'] = chat_id
1055 | })
1056 | return success, res
1057 | end
1058 |
1059 | function api.answer_callback_query(callback_query_id, text, show_alert, url, cache_time) -- https://core.telegram.org/bots/api#answercallbackquery
1060 | local success, res = api.request(config.endpoint .. api.token .. '/answerCallbackQuery', {
1061 | ['callback_query_id'] = callback_query_id,
1062 | ['text'] = text,
1063 | ['show_alert'] = show_alert,
1064 | ['url'] = url,
1065 | ['cache_time'] = cache_time
1066 | })
1067 | return success, res
1068 | end
1069 |
1070 | function api.get_user_chat_boosts(chat_id, user_id) -- https://core.telegram.org/bots/api#getUserChatBoosts
1071 | local success, res = api.request(config.endpoint .. api.token .. '/getUserChatBoosts', {
1072 | ['chat_id'] = chat_id,
1073 | ['user_id'] = user_id
1074 | })
1075 | return success, res
1076 | end
1077 |
1078 | function api.set_my_commands(commands, scope, language_code) -- https://core.telegram.org/bots/api#setmycommands
1079 | commands = type(commands) == 'table' and json.encode(commands) or commands
1080 | scope = type(scope) == 'table' and json.encode(scope) or scope
1081 | local success, res = api.request(config.endpoint .. api.token .. '/setMyCommands', {
1082 | ['commands'] = commands,
1083 | ['scope'] = scope,
1084 | ['language_code'] = language_code
1085 | })
1086 | return success, res
1087 | end
1088 |
1089 | function api.delete_my_commands(scope, language_code) -- https://core.telegram.org/bots/api#deletemycommands
1090 | scope = type(scope) == 'table' and json.encode(scope) or scope
1091 | local success, res = api.request(config.endpoint .. api.token .. '/deleteMyCommands', {
1092 | ['scope'] = scope,
1093 | ['language_code'] = language_code
1094 | })
1095 | return success, res
1096 | end
1097 |
1098 | function api.get_my_commands(scope, language_code) -- https://core.telegram.org/bots/api#getmycommands
1099 | scope = type(scope) == 'table' and json.encode(scope) or scope
1100 | local success, res = api.request(config.endpoint .. api.token .. '/getMyCommands', {
1101 | ['scope'] = scope,
1102 | ['language_code'] = language_code
1103 | })
1104 | return success, res
1105 | end
1106 |
1107 | function api.set_my_name(name, language_code) -- https://core.telegram.org/bots/api#setmyname
1108 | name = tostring(name)
1109 | if name:len() > 64 then
1110 | name = name:sub(1, 64)
1111 | end
1112 | local success, res = api.request(config.endpoint .. api.token .. '/setMyName', {
1113 | ['name'] = name,
1114 | ['language_code'] = language_code
1115 | })
1116 | return success, res
1117 | end
1118 |
1119 | function api.get_my_name(language_code) -- https://core.telegram.org/bots/api#getmyname
1120 | local success, res = api.request(config.endpoint .. api.token .. '/getMyName', {
1121 | ['language_code'] = language_code
1122 | })
1123 | return success, res
1124 | end
1125 |
1126 | function api.set_my_description(description, language_code) -- https://core.telegram.org/bots/api#setmydescription
1127 | description = tostring(description)
1128 | if description:len() > 512 then
1129 | description = description:sub(1, 512)
1130 | end
1131 | local success, res = api.request(config.endpoint .. api.token .. '/setMyDescription', {
1132 | ['description'] = description,
1133 | ['language_code'] = language_code
1134 | })
1135 | return success, res
1136 | end
1137 |
1138 | function api.get_my_description(language_code) -- https://core.telegram.org/bots/api#getmydescription
1139 | local success, res = api.request(config.endpoint .. api.token .. '/getMyDescription', {
1140 | ['language_code'] = language_code
1141 | })
1142 | return success, res
1143 | end
1144 |
1145 | function api.set_my_short_description(short_description, language_code) -- https://core.telegram.org/bots/api#setmyshortdescription
1146 | short_description = tostring(short_description)
1147 | if short_description:len() > 120 then
1148 | short_description = short_description:sub(1, 120)
1149 | end
1150 | local success, res = api.request(config.endpoint .. api.token .. '/setMyShortDescription', {
1151 | ['short_description'] = short_description,
1152 | ['language_code'] = language_code
1153 | })
1154 | return success, res
1155 | end
1156 |
1157 | function api.get_my_short_description(language_code) -- https://core.telegram.org/bots/api#getmyshortdescription
1158 | local success, res = api.request(config.endpoint .. api.token .. '/getMyShortDescription', {
1159 | ['language_code'] = language_code
1160 | })
1161 | return success, res
1162 | end
1163 |
1164 | function api.set_chat_menu_button(chat_id, menu_button) -- https://core.telegram.org/bots/api#setchatmenubutton
1165 | menu_button = type(menu_button) == 'table' and json.encode(menu_button) or menu_button
1166 | local success, res = api.request(config.endpoint .. api.token .. '/setChatMenuButton', {
1167 | ['chat_id'] = chat_id,
1168 | ['menu_button'] = menu_button
1169 | })
1170 | return success, res
1171 | end
1172 |
1173 | function api.get_chat_menu_button(chat_id) -- https://core.telegram.org/bots/api#getchatmenubutton
1174 | local success, res = api.request(config.endpoint .. api.token .. '/getChatMenuButton', {
1175 | ['chat_id'] = chat_id
1176 | })
1177 | return success, res
1178 | end
1179 |
1180 | function api.set_my_default_administrator_rights(rights, for_channels) -- https://core.telegram.org/bots/api#setmydefaultadministratorrights
1181 | rights = type(rights) == 'table' and json.encode(rights) or rights
1182 | local success, res = api.request(config.endpoint .. api.token .. '/setMyDefaultAdministratorRights', {
1183 | ['rights'] = rights,
1184 | ['for_channels'] = for_channels
1185 | })
1186 | return success, res
1187 | end
1188 |
1189 | function api.get_my_default_administrator_rights(for_channels) -- https://core.telegram.org/bots/api#getmydefaultadministratorrights
1190 | local success, res = api.request(config.endpoint .. api.token .. '/getMyDefaultAdministratorRights', {
1191 | ['for_channels'] = for_channels
1192 | })
1193 | return success, res
1194 | end
1195 |
1196 | function api.edit_message_text(chat_id, message_id, text, parse_mode, entities, link_preview_options, reply_markup,
1197 | inline_message_id) -- https://core.telegram.org/bots/api#editmessagetext
1198 | entities = type(entities) == 'table' and json.encode(entities) or entities
1199 | link_preview_options = type(link_preview_options) == 'table' and json.encode(link_preview_options) or
1200 | link_preview_options
1201 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1202 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'MarkdownV2' or parse_mode
1203 | local success, res = api.request(config.endpoint .. api.token .. '/editMessageText', {
1204 | ['chat_id'] = chat_id,
1205 | ['message_id'] = message_id,
1206 | ['inline_message_id'] = inline_message_id,
1207 | ['text'] = text,
1208 | ['parse_mode'] = parse_mode,
1209 | ['entities'] = entities,
1210 | ['link_preview_options'] = link_preview_options,
1211 | ['reply_markup'] = reply_markup
1212 | })
1213 | -- Try as an inline message
1214 | if not success then
1215 | success, res = api.request(config.endpoint .. api.token .. '/editMessageText', {
1216 | ['chat_id'] = chat_id,
1217 | ['message_id'] = inline_message_id,
1218 | ['inline_message_id'] = message_id,
1219 | ['text'] = text,
1220 | ['parse_mode'] = parse_mode,
1221 | ['entities'] = entities,
1222 | ['link_preview_options'] = link_preview_options,
1223 | ['reply_markup'] = reply_markup
1224 | })
1225 | end
1226 | return success, res
1227 | end
1228 |
1229 | function api.edit_message_caption(chat_id, message_id, caption, parse_mode, caption_entities, reply_markup,
1230 | inline_message_id) -- https://core.telegram.org/bots/api#editmessagecaption
1231 | caption_entities = type(caption_entities) == 'table' and json.encode(caption_entities) or caption_entities
1232 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1233 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'MarkdownV2' or parse_mode
1234 | local success, res = api.request(config.endpoint .. api.token .. '/editMessageCaption', {
1235 | ['chat_id'] = chat_id,
1236 | ['message_id'] = message_id,
1237 | ['inline_message_id'] = inline_message_id,
1238 | ['caption'] = caption,
1239 | ['parse_mode'] = parse_mode,
1240 | ['caption_entities'] = caption_entities,
1241 | ['reply_markup'] = reply_markup
1242 | })
1243 | -- Try as an inline message
1244 | if not success then
1245 | success, res = api.request(config.endpoint .. api.token .. '/editMessageCaption', {
1246 | ['chat_id'] = chat_id,
1247 | ['message_id'] = inline_message_id,
1248 | ['inline_message_id'] = message_id,
1249 | ['caption'] = caption,
1250 | ['parse_mode'] = parse_mode,
1251 | ['caption_entities'] = caption_entities,
1252 | ['reply_markup'] = reply_markup
1253 | })
1254 | end
1255 | return success, res
1256 | end
1257 |
1258 | function api.edit_message_media(chat_id, message_id, media, reply_markup, inline_message_id) -- https://core.telegram.org/bots/api#editmessagemedia
1259 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1260 | media = type(media) == 'table' and json.encode(media) or media
1261 | local success, res = api.request(config.endpoint .. api.token .. '/editMessageMedia', {
1262 | ['chat_id'] = chat_id,
1263 | ['message_id'] = message_id,
1264 | ['inline_message_id'] = inline_message_id,
1265 | ['media'] = media,
1266 | ['reply_markup'] = reply_markup
1267 | })
1268 | if not success then
1269 | success, res = api.request(config.endpoint .. api.token .. '/editMessageMedia', {
1270 | ['chat_id'] = chat_id,
1271 | ['message_id'] = inline_message_id,
1272 | ['inline_message_id'] = message_id,
1273 | ['media'] = media,
1274 | ['reply_markup'] = reply_markup
1275 | })
1276 | end
1277 | return success, res
1278 | end
1279 |
1280 | function api.edit_message_reply_markup(chat_id, message_id, inline_message_id, reply_markup) -- https://core.telegram.org/bots/api#editmessagereplymarkup
1281 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1282 | local success, res = api.request(config.endpoint .. api.token .. '/editMessageReplyMarkup', {
1283 | ['chat_id'] = chat_id,
1284 | ['message_id'] = message_id,
1285 | ['inline_message_id'] = inline_message_id,
1286 | ['reply_markup'] = reply_markup
1287 | })
1288 | -- Try as an inline message
1289 | if not success then
1290 | success, res = api.request(config.endpoint .. api.token .. '/editMessageReplyMarkup', {
1291 | ['chat_id'] = chat_id,
1292 | ['message_id'] = inline_message_id,
1293 | ['inline_message_id'] = message_id,
1294 | ['reply_markup'] = reply_markup
1295 | })
1296 | end
1297 | return success, res
1298 | end
1299 |
1300 | function api.stop_poll(chat_id, message_id, reply_markup) -- https://core.telegram.org/bots/api#stoppoll
1301 | local success, res = api.request(config.endpoint .. api.token .. '/stopPoll', {
1302 | ['chat_id'] = chat_id,
1303 | ['message_id'] = message_id,
1304 | ['reply_markup'] = reply_markup
1305 | })
1306 | return success, res
1307 | end
1308 |
1309 | function api.delete_message(chat_id, message_id) -- https://core.telegram.org/bots/api#deletemessage
1310 | local success, res = api.request(config.endpoint .. api.token .. '/deleteMessage', {
1311 | ['chat_id'] = chat_id,
1312 | ['message_id'] = message_id
1313 | })
1314 | return success, res
1315 | end
1316 |
1317 | function api.delete_messages(chat_id, message_ids) -- https://core.telegram.org/bots/api#deletemessages
1318 | message_ids = type(message_ids) == 'table' and json.encode(message_ids) or message_ids
1319 | local success, res = api.request(config.endpoint .. api.token .. '/deleteMessages', {
1320 | ['chat_id'] = chat_id,
1321 | ['message_ids'] = message_ids
1322 | })
1323 | return success, res
1324 | end
1325 |
1326 | --------------
1327 | -- STICKERS --
1328 | --------------
1329 |
1330 | function api.send_sticker(chat_id, sticker, message_thread_id, emoji, disable_notification, protect_content,
1331 | reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendsticker
1332 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
1333 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1334 | local success, res = api.request(config.endpoint .. api.token .. '/sendSticker', {
1335 | ['chat_id'] = chat_id,
1336 | ['message_thread_id'] = message_thread_id,
1337 | ['emoji'] = emoji,
1338 | ['disable_notification'] = disable_notification,
1339 | ['protect_content'] = protect_content,
1340 | ['reply_parameters'] = reply_parameters,
1341 | ['reply_markup'] = reply_markup
1342 | }, {
1343 | ['sticker'] = sticker
1344 | })
1345 | return success, res
1346 | end
1347 |
1348 | function api.get_sticker_set(name) -- https://core.telegram.org/bots/api#getstickerset
1349 | local success, res = api.request(config.endpoint .. api.token .. '/getStickerSet', {
1350 | ['name'] = name
1351 | })
1352 | return success, res
1353 | end
1354 |
1355 | function api.get_custom_emoji_stickers(custom_emoji_ids) -- https://core.telegram.org/bots/api#getcustomemojistickers
1356 | custom_emoji_ids = type(custom_emoji_ids) == 'table' and json.encode(custom_emoji_ids) or custom_emoji_ids
1357 | local success, res = api.request(config.endpoint .. api.token .. '/getCustomEmojiStickers', {
1358 | ['custom_emoji_ids'] = custom_emoji_ids
1359 | })
1360 | return success, res
1361 | end
1362 |
1363 | function api.upload_sticker_file(user_id, sticker, sticker_format) -- https://core.telegram.org/bots/api#uploadstickerfile
1364 | local success, res = api.request(config.endpoint .. api.token .. '/uploadStickerFile', {
1365 | ['user_id'] = user_id,
1366 | ['sticker_format'] = sticker_format
1367 | }, {
1368 | ['sticker'] = sticker
1369 | })
1370 | return success, res
1371 | end
1372 |
1373 | function api.create_new_sticker_set(user_id, name, title, stickers, sticker_format, sticker_type, needs_repainting) -- https://core.telegram.org/bots/api#createnewstickerset
1374 | stickers = type(stickers) == 'table' and json.encode(stickers) or stickers
1375 | local success, res = api.request(config.endpoint .. api.token .. '/createNewStickerSet', {
1376 | ['user_id'] = user_id,
1377 | ['name'] = name,
1378 | ['title'] = title,
1379 | ['stickers'] = stickers,
1380 | ['sticker_format'] = sticker_format,
1381 | ['sticker_type'] = sticker_type,
1382 | ['needs_repainting'] = needs_repainting
1383 | })
1384 | return success, res
1385 | end
1386 |
1387 | function api.add_sticker_to_set(user_id, name, sticker) -- https://core.telegram.org/bots/api#addstickertoset
1388 | sticker = type(sticker) == 'table' and json.encode(sticker) or sticker
1389 | local success, res = api.request(config.endpoint .. api.token .. '/addStickerToSet', {
1390 | ['user_id'] = user_id,
1391 | ['name'] = name,
1392 | ['sticker'] = sticker
1393 | })
1394 | return success, res
1395 | end
1396 |
1397 | function api.set_sticker_position_in_set(sticker, position) -- https://core.telegram.org/bots/api#setstickerpositioninset
1398 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerPositionInSet', {
1399 | ['sticker'] = sticker,
1400 | ['position'] = position
1401 | })
1402 | return success, res
1403 | end
1404 |
1405 | function api.delete_sticker_from_set(sticker) -- https://core.telegram.org/bots/api#deletestickerfromset
1406 | local success, res = api.request(config.endpoint .. api.token .. '/deleteStickerFromSet', {
1407 | ['sticker'] = sticker
1408 | })
1409 | return success, res
1410 | end
1411 |
1412 | function api.set_sticker_emoji_list(sticker, emoji_list) -- https://core.telegram.org/bots/api#setstickeremojilist
1413 | emoji_list = type(emoji_list) == 'table' and json.encode(emoji_list) or emoji_list
1414 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerEmojiList', {
1415 | ['sticker'] = sticker,
1416 | ['emoji_list'] = emoji_list
1417 | })
1418 | return success, res
1419 | end
1420 |
1421 | function api.set_sticker_keywords(sticker, keywords) -- https://core.telegram.org/bots/api#setstickerkeywords
1422 | keywords = type(keywords) == 'table' and json.encode(keywords) or keywords
1423 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerKeywords', {
1424 | ['sticker'] = sticker,
1425 | ['keywords'] = keywords
1426 | })
1427 | return success, res
1428 | end
1429 |
1430 | function api.set_sticker_mask_position(sticker, mask_position) -- https://core.telegram.org/bots/api#setstickermaskposition
1431 | mask_position = type(mask_position) == 'table' and json.encode(mask_position) or mask_position
1432 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerMaskPosition', {
1433 | ['sticker'] = sticker,
1434 | ['mask_position'] = mask_position
1435 | })
1436 | return success, res
1437 | end
1438 |
1439 | function api.set_sticker_set_title(name, title) -- https://core.telegram.org/bots/api#setstickersettitle
1440 | title = tostring(title)
1441 | if title:len() > 64 then
1442 | title = title:sub(1, 64)
1443 | end
1444 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerSetTitle', {
1445 | ['name'] = name,
1446 | ['title'] = title
1447 | })
1448 | return success, res
1449 | end
1450 |
1451 | function api.set_sticker_set_thumbnail(name, user_id, thumbnail) -- https://core.telegram.org/bots/api#setstickersetthumbnail
1452 | local success, res = api.request(config.endpoint .. api.token .. '/setStickerSetThumbnail', {
1453 | ['name'] = name,
1454 | ['user_id'] = user_id
1455 | }, {
1456 | ['thumbnail'] = thumbnail
1457 | })
1458 | return success, res
1459 | end
1460 |
1461 | function api.set_custom_emoji_sticker_set_thumbnail(name, custom_emoji_id) -- https://core.telegram.org/bots/api#setcustomemojistickersetthumbnail
1462 | local success, res = api.request(config.endpoint .. api.token .. '/setCustomEmojiStickerSetThumbnail', {
1463 | ['name'] = name,
1464 | ['custom_emoji_id'] = custom_emoji_id
1465 | })
1466 | return success, res
1467 | end
1468 |
1469 | function api.delete_sticker_set(name) -- https://core.telegram.org/bots/api#deletestickerset
1470 | local success, res = api.request(config.endpoint .. api.token .. '/deleteStickerSet', {
1471 | ['name'] = name
1472 | })
1473 | return success, res
1474 | end
1475 |
1476 | function api.answer_inline_query(inline_query_id, results, cache_time, is_personal, next_offset, button) -- https://core.telegram.org/bots/api#answerinlinequery
1477 | button = type(button) == 'table' and json.encode(button) or button
1478 | if results and type(results) == 'table' then
1479 | if results.id then
1480 | results = {results}
1481 | end
1482 | results = json.encode(results)
1483 | end
1484 | local success, res = api.request(config.endpoint .. api.token .. '/answerInlineQuery', {
1485 | ['inline_query_id'] = inline_query_id,
1486 | ['results'] = results,
1487 | ['cache_time'] = cache_time,
1488 | ['is_personal'] = is_personal,
1489 | ['next_offset'] = next_offset,
1490 | ['button'] = button
1491 | })
1492 | return success, res
1493 | end
1494 |
1495 | function api.answer_web_app_query(web_app_query_id, result) -- https://core.telegram.org/bots/api#answerwebappquery
1496 | result = type(result) == 'table' and json.encode(result) or result
1497 | local success, res = api.request(config.endpoint .. api.token .. '/answerWebAppQuery', {
1498 | ['web_app_query_id'] = web_app_query_id,
1499 | ['result'] = result
1500 | })
1501 | return success, res
1502 | end
1503 |
1504 | --------------
1505 | -- PAYMENTS --
1506 | --------------
1507 |
1508 | function api.send_invoice(chat_id, title, description, payload, provider_token, currency, prices, message_thread_id,
1509 | max_tip_amount, suggested_tip_amounts, start_parameter, provider_data, photo_url, photo_size, photo_width,
1510 | photo_height, need_name, need_phone_number, need_email, need_shipping_address, send_phone_number_to_provider,
1511 | send_email_to_provider, is_flexible, disable_notification, protect_content, reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendinvoice
1512 | prices = type(prices) == 'table' and json.encode(prices) or prices
1513 | suggested_tip_amounts = type(suggested_tip_amounts) == 'table' and json.encode(suggested_tip_amounts) or
1514 | suggested_tip_amounts
1515 | provider_data = type(provider_data) == 'table' and json.encode(provider_data) or provider_data
1516 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
1517 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1518 | local success, res = api.request(config.endpoint .. api.token .. '/sendInvoice', {
1519 | ['chat_id'] = chat_id,
1520 | ['message_thread_id'] = message_thread_id,
1521 | ['title'] = title,
1522 | ['description'] = description,
1523 | ['payload'] = payload,
1524 | ['provider_token'] = provider_token,
1525 | ['currency'] = currency,
1526 | ['prices'] = prices,
1527 | ['max_tip_amount'] = max_tip_amount,
1528 | ['suggested_tip_amounts'] = suggested_tip_amounts,
1529 | ['start_parameter'] = start_parameter,
1530 | ['provider_data'] = provider_data,
1531 | ['photo_url'] = photo_url,
1532 | ['photo_size'] = photo_size,
1533 | ['photo_width'] = photo_width,
1534 | ['photo_height'] = photo_height,
1535 | ['need_name'] = need_name,
1536 | ['need_phone_number'] = need_phone_number,
1537 | ['need_email'] = need_email,
1538 | ['need_shipping_address'] = need_shipping_address,
1539 | ['send_phone_number_to_provider'] = send_phone_number_to_provider,
1540 | ['send_email_to_provider'] = send_email_to_provider,
1541 | ['is_flexible'] = is_flexible,
1542 | ['disable_notification'] = disable_notification,
1543 | ['protect_content'] = protect_content,
1544 | ['reply_parameters'] = reply_parameters,
1545 | ['reply_markup'] = reply_markup
1546 | })
1547 | return success, res
1548 | end
1549 |
1550 | function api.create_invoice_link(title, description, payload, provider_token, currency, prices, max_tip_amount,
1551 | suggested_tip_amounts, provider_data, photo_url, photo_size, photo_width, photo_height, need_name,
1552 | need_phone_number, need_email, need_shipping_address, send_phone_number_to_provider, send_email_to_provider,
1553 | is_flexible) -- https://core.telegram.org/bots/api#createinvoicelink
1554 | prices = type(prices) == 'table' and json.encode(prices) or prices
1555 | suggested_tip_amounts = type(suggested_tip_amounts) == 'table' and json.encode(suggested_tip_amounts) or
1556 | suggested_tip_amounts
1557 | provider_data = type(provider_data) == 'table' and json.encode(provider_data) or provider_data
1558 | local success, res = api.request(config.endpoint .. api.token .. '/createInvoiceLink', {
1559 | ['title'] = title,
1560 | ['description'] = description,
1561 | ['payload'] = payload,
1562 | ['provider_token'] = provider_token,
1563 | ['currency'] = currency,
1564 | ['prices'] = prices,
1565 | ['max_tip_amount'] = max_tip_amount,
1566 | ['suggested_tip_amounts'] = suggested_tip_amounts,
1567 | ['provider_data'] = provider_data,
1568 | ['photo_url'] = photo_url,
1569 | ['photo_size'] = photo_size,
1570 | ['photo_width'] = photo_width,
1571 | ['photo_height'] = photo_height,
1572 | ['need_name'] = need_name,
1573 | ['need_phone_number'] = need_phone_number,
1574 | ['need_email'] = need_email,
1575 | ['need_shipping_address'] = need_shipping_address,
1576 | ['send_phone_number_to_provider'] = send_phone_number_to_provider,
1577 | ['send_email_to_provider'] = send_email_to_provider,
1578 | ['is_flexible'] = is_flexible
1579 | })
1580 | return success, res
1581 | end
1582 |
1583 | function api.answer_shipping_query(shipping_query_id, ok, shipping_options, error_message) -- https://core.telegram.org/bots/api#answershippingquery
1584 | shipping_options = type(shipping_options) == 'table' and json.encode(shipping_options) or shipping_options
1585 | -- Ensure an error_message is given when ok is false
1586 | if type(ok) == 'boolean' and ok == false and not error_message then
1587 | error_message = 'Unspecified issue occurred! Please contact the person you received this invoice from!'
1588 | end
1589 | local success, res = api.request(config.endpoint .. api.token .. '/answerShippingQuery', {
1590 | ['shipping_query_id'] = shipping_query_id,
1591 | ['ok'] = ok,
1592 | ['shipping_options'] = shipping_options,
1593 | ['error_message'] = error_message
1594 | })
1595 | return success, res
1596 | end
1597 |
1598 | function api.answer_pre_checkout_query(pre_checkout_query_id, ok, error_message) -- https://core.telegram.org/bots/api#answerprecheckoutquery
1599 | -- Ensure an error_message is given when ok is false
1600 | if type(ok) == 'boolean' and ok == false and not error_message then
1601 | error_message = 'Unspecified issue occurred! Please contact the person you received this invoice from!'
1602 | end
1603 | local success, res = api.request(config.endpoint .. api.token .. '/answerPreCheckoutQuery', {
1604 | ['pre_checkout_query_id'] = pre_checkout_query_id,
1605 | ['ok'] = ok,
1606 | ['error_message'] = error_message
1607 | })
1608 | return success, res
1609 | end
1610 |
1611 | ---------------
1612 | -- PASSPORTS --
1613 | ---------------
1614 |
1615 | function api.set_passport_data_errors(user_id, errors) -- https://core.telegram.org/bots/api#setpassportdataerrors
1616 | errors = type(errors) == 'table' and json.encode(errors) or errors
1617 | local success, res = api.request(config.endpoint .. api.token .. '/setPassportDataErrors', {
1618 | ['user_id'] = user_id,
1619 | ['errors'] = errors
1620 | })
1621 | return success, res
1622 | end
1623 |
1624 | -----------
1625 | -- GAMES --
1626 | -----------
1627 |
1628 | function api.send_game(chat_id, game_short_name, message_thread_id, disable_notification, protect_content,
1629 | reply_parameters, reply_markup) -- https://core.telegram.org/bots/api#sendgame
1630 | reply_parameters = type(reply_parameters) == 'table' and json.encode(reply_parameters) or reply_parameters
1631 | reply_markup = type(reply_markup) == 'table' and json.encode(reply_markup) or reply_markup
1632 | local success, res = api.request(config.endpoint .. api.token .. '/sendGame', {
1633 | ['chat_id'] = chat_id,
1634 | ['message_thread_id'] = message_thread_id,
1635 | ['game_short_name'] = game_short_name,
1636 | ['disable_notification'] = disable_notification,
1637 | ['protect_content'] = protect_content,
1638 | ['reply_parameters'] = reply_parameters,
1639 | ['reply_markup'] = reply_markup
1640 | })
1641 | return success, res
1642 | end
1643 |
1644 | function api.set_game_score(user_id, score, force, disable_edit_message, chat_id, message_id, inline_message_id) -- https://core.telegram.org/bots/api#setgamescore
1645 | local success, res = api.request(config.endpoint .. api.token .. '/setGameScore', {
1646 | ['user_id'] = user_id,
1647 | ['score'] = score,
1648 | ['force'] = force,
1649 | ['disable_edit_message'] = disable_edit_message,
1650 | ['chat_id'] = chat_id,
1651 | ['message_id'] = message_id,
1652 | ['inline_message_id'] = inline_message_id
1653 | })
1654 | return success, res
1655 | end
1656 |
1657 | function api.get_game_high_scores(chat_id, user_id, message_id, inline_message_id) -- https://core.telegram.org/bots/api#getgamehighscores
1658 | local success, res = api.request(config.endpoint .. api.token .. '/getGameHighScores', {
1659 | ['user_id'] = user_id,
1660 | ['chat_id'] = chat_id,
1661 | ['message_id'] = message_id,
1662 | ['inline_message_id'] = inline_message_id
1663 | })
1664 | return success, res
1665 | end
1666 |
1667 | function api.on_update(_)
1668 | end
1669 | function api.on_message(_)
1670 | end
1671 | function api.on_private_message(_)
1672 | end
1673 | function api.on_group_message(_)
1674 | end
1675 | function api.on_supergroup_message(_)
1676 | end
1677 | function api.on_callback_query(_)
1678 | end
1679 | function api.on_inline_query(_)
1680 | end
1681 | function api.on_channel_post(_)
1682 | end
1683 | function api.on_edited_message(_)
1684 | end
1685 | function api.on_edited_private_message(_)
1686 | end
1687 | function api.on_edited_group_message(_)
1688 | end
1689 | function api.on_edited_supergroup_message(_)
1690 | end
1691 | function api.on_edited_channel_post(_)
1692 | end
1693 | function api.on_chosen_inline_result(_)
1694 | end
1695 | function api.on_shipping_query(_)
1696 | end
1697 | function api.on_pre_checkout_query(_)
1698 | end
1699 | function api.on_poll(_)
1700 | end
1701 | function api.on_poll_answer(_)
1702 | end
1703 | function api.on_message_reaction(_)
1704 | end
1705 | function api.on_message_reaction_count(_)
1706 | end
1707 | function api.on_my_chat_member(_)
1708 | end
1709 | function api.on_chat_member(_)
1710 | end
1711 | function api.on_chat_join_request(_)
1712 | end
1713 | function api.on_chat_boost(_)
1714 | end
1715 | function api.on_removed_chat_boost(_)
1716 | end
1717 |
1718 | function api.process_update(update)
1719 | if update then
1720 | api.on_update(update)
1721 | end
1722 | if update.message then
1723 | if update.message.chat.type == 'private' then
1724 | api.on_private_message(update.message)
1725 | elseif update.message.chat.type == 'group' then
1726 | api.on_group_message(update.message)
1727 | elseif update.message.chat.type == 'supergroup' then
1728 | api.on_supergroup_message(update.message)
1729 | end
1730 | return api.on_message(update.message)
1731 | elseif update.edited_message then
1732 | if update.edited_message.chat.type == 'private' then
1733 | api.on_edited_private_message(update.edited_message)
1734 | elseif update.edited_message.chat.type == 'group' then
1735 | api.on_edited_group_message(update.edited_message)
1736 | elseif update.edited_message.chat.type == 'supergroup' then
1737 | api.on_edited_supergroup_message(update.edited_message)
1738 | end
1739 | return api.on_edited_message(update.edited_message)
1740 | elseif update.callback_query then
1741 | return api.on_callback_query(update.callback_query)
1742 | elseif update.inline_query then
1743 | return api.on_inline_query(update.inline_query)
1744 | elseif update.channel_post then
1745 | return api.on_channel_post(update.channel_post)
1746 | elseif update.edited_channel_post then
1747 | return api.on_edited_channel_post(update.edited_channel_post)
1748 | elseif update.chosen_inline_result then
1749 | return api.on_chosen_inline_result(update.chosen_inline_result)
1750 | elseif update.shipping_query then
1751 | return api.on_shipping_query(update.shipping_query)
1752 | elseif update.pre_checkout_query then
1753 | return api.on_pre_checkout_query(update.pre_checkout_query)
1754 | elseif update.poll then
1755 | return api.on_poll(update.poll)
1756 | elseif update.poll_answer then
1757 | return api.on_poll_answer
1758 | elseif update.message_reaction then
1759 | return api.on_message_reaction
1760 | elseif update.message_reaction_count then
1761 | return api.on_message_reaction_count
1762 | elseif update.my_chat_member then
1763 | return api.on_my_chat_member
1764 | elseif update.chat_member then
1765 | return api.on_chat_member
1766 | elseif update.chat_join_request then
1767 | return api.on_chat_join_request
1768 | elseif update.chat_boost then
1769 | return api.on_chat_boost
1770 | elseif update.removed_chat_boost then
1771 | return api.on_removed_chat_boost
1772 | end
1773 | return false
1774 | end
1775 |
1776 | function api.run(limit, timeout, offset, allowed_updates, use_beta_endpoint)
1777 | limit = tonumber(limit) ~= nil and limit or 1
1778 | timeout = tonumber(timeout) ~= nil and timeout or 0
1779 | offset = tonumber(offset) ~= nil and offset or 0
1780 | while true do
1781 | local updates = api.get_updates(timeout, offset, limit, allowed_updates, use_beta_endpoint)
1782 | if updates and type(updates) == 'table' and updates.result then
1783 | for _, v in pairs(updates.result) do
1784 | api.process_update(v)
1785 | offset = v.update_id + 1
1786 | end
1787 | end
1788 | end
1789 | end
1790 |
1791 | function api.input_text_message_content(message_text, parse_mode, disable_web_page_preview, encoded)
1792 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'markdown' or parse_mode
1793 | local input_message_content = {
1794 | ['message_text'] = tostring(message_text),
1795 | ['parse_mode'] = parse_mode,
1796 | ['disable_web_page_preview'] = disable_web_page_preview
1797 | }
1798 | input_message_content = encoded and json.encode(input_message_content) or input_message_content
1799 | return input_message_content
1800 | end
1801 |
1802 | function api.input_location_message_content(latitude, longitude, encoded)
1803 | local input_message_content = {
1804 | ['latitude'] = tonumber(latitude),
1805 | ['longitude'] = tonumber(longitude)
1806 | }
1807 | input_message_content = encoded and json.encode(input_message_content) or input_message_content
1808 | return input_message_content
1809 | end
1810 |
1811 | function api.input_venue_message_content(latitude, longitude, title, address, foursquare_id, encoded)
1812 | local input_message_content = {
1813 | ['latitude'] = tonumber(latitude),
1814 | ['longitude'] = tonumber(longitude),
1815 | ['title'] = tostring(title),
1816 | ['address'] = tostring(address),
1817 | ['foursquare_id'] = foursquare_id
1818 | }
1819 | input_message_content = encoded and json.encode(input_message_content) or input_message_content
1820 | return input_message_content
1821 | end
1822 |
1823 | function api.input_contact_message_content(phone_number, first_name, last_name, encoded)
1824 | local input_message_content = {
1825 | ['phone_number'] = tostring(phone_number),
1826 | ['first_name'] = tonumber(first_name),
1827 | ['last_name'] = last_name
1828 | }
1829 | input_message_content = encoded and json.encode(input_message_content) or input_message_content
1830 | return input_message_content
1831 | end
1832 |
1833 | function api.input_media_photo(media, caption, parse_mode)
1834 | return {
1835 | ['type'] = 'photo',
1836 | ['caption'] = caption,
1837 | ['parse_mode'] = parse_mode
1838 | }, {
1839 | ['media'] = media
1840 | }
1841 | end
1842 |
1843 | function api.input_media_video(media, thumb, caption, parse_mode, width, height, duration, supports_streaming)
1844 | return {
1845 | ['type'] = 'video',
1846 | ['caption'] = caption,
1847 | ['parse_mode'] = parse_mode,
1848 | ['width'] = tonumber(width),
1849 | ['height'] = tonumber(height),
1850 | ['duration'] = tonumber(duration),
1851 | ['supports_streaming'] = supports_streaming
1852 | }, {
1853 | ['media'] = media,
1854 | ['thumb'] = thumb
1855 | }
1856 | end
1857 |
1858 | function api.input_media_animation(media, thumb, caption, parse_mode, width, height, duration)
1859 | return {
1860 | ['type'] = 'animation',
1861 | ['caption'] = caption,
1862 | ['parse_mode'] = parse_mode,
1863 | ['width'] = tonumber(width),
1864 | ['height'] = tonumber(height),
1865 | ['duration'] = tonumber(duration)
1866 | }, {
1867 | ['media'] = media,
1868 | ['thumb'] = thumb
1869 | }
1870 | end
1871 |
1872 | function api.input_media_audio(media, thumb, caption, parse_mode, duration, performer, title)
1873 | return {
1874 | ['type'] = 'audio',
1875 | ['caption'] = caption,
1876 | ['parse_mode'] = parse_mode,
1877 | ['duration'] = tonumber(duration),
1878 | ['performer'] = performer,
1879 | ['title'] = title
1880 | }, {
1881 | ['media'] = media,
1882 | ['thumb'] = thumb
1883 | }
1884 | end
1885 |
1886 | function api.input_media_document(media, thumb, caption, parse_mode)
1887 | return {
1888 | ['type'] = 'document',
1889 | ['caption'] = caption,
1890 | ['parse_mode'] = parse_mode
1891 | }, {
1892 | ['media'] = media,
1893 | ['thumb'] = thumb
1894 | }
1895 | end
1896 |
1897 | -- Functions to handle ChatPermissions
1898 |
1899 | function api.chat_permissions(can_send_messages, can_send_media_messages, can_send_polls, can_send_other_messages,
1900 | can_add_web_page_previews, can_change_info, can_invite_users, can_pin_messages)
1901 | return {
1902 | ['can_send_messages'] = can_send_messages,
1903 | ['can_send_media_messages'] = can_send_media_messages,
1904 | ['can_send_polls'] = can_send_polls,
1905 | ['can_send_other_messages'] = can_send_other_messages,
1906 | ['can_add_web_page_previews'] = can_add_web_page_previews,
1907 | ['can_change_info'] = can_change_info,
1908 | ['can_invite_users'] = can_invite_users,
1909 | ['can_pin_messages'] = can_pin_messages
1910 | }
1911 | end
1912 |
1913 | -- Functions and meta-methods for handling mask positioning arrays to use with various
1914 | -- sticker-related functions.
1915 |
1916 | api.mask_position_meta = {}
1917 | api.mask_position_meta.__index = api.mask_position_meta
1918 |
1919 | function api.mask_position_meta:position(point, x_shift, y_shift, scale)
1920 | table.insert(self, {
1921 | ['point'] = tostring(point), -- Available points include "forehead", "eyes", "mouth" or "chin".
1922 | ['x_shift'] = tonumber(x_shift),
1923 | ['y_shift'] = tonumber(y_shift),
1924 | ['scale'] = tonumber(scale)
1925 | })
1926 | return self
1927 | end
1928 |
1929 | function api.mask_position()
1930 | local output = setmetatable({}, api.mask_position_meta)
1931 | return output
1932 | end
1933 |
1934 | -- Functions for handling inline objects to use with api.answer_inline_query().
1935 |
1936 | function api.send_inline_article(inline_query_id, title, description, message_text, parse_mode, reply_markup)
1937 | description = description or title
1938 | message_text = message_text or description
1939 | parse_mode = (type(parse_mode) == 'boolean' and parse_mode == true) and 'markdown' or parse_mode
1940 | return api.answer_inline_query(inline_query_id, json.encode({{
1941 | ['type'] = 'article',
1942 | ['id'] = '1',
1943 | ['title'] = title,
1944 | ['description'] = description,
1945 | ['input_message_content'] = {
1946 | ['message_text'] = message_text,
1947 | ['parse_mode'] = parse_mode
1948 | },
1949 | ['reply_markup'] = reply_markup
1950 | }}))
1951 | end
1952 |
1953 | function api.send_inline_article_url(inline_query_id, title, url, hide_url, input_message_content, reply_markup, id)
1954 | return api.answer_inline_query(inline_query_id, json.encode({{
1955 | ['type'] = 'article',
1956 | ['id'] = tonumber(id) ~= nil and tostring(id) or '1',
1957 | ['title'] = tostring(title),
1958 | ['url'] = tostring(url),
1959 | ['hide_url'] = hide_url or false,
1960 | ['input_message_content'] = input_message_content,
1961 | ['reply_markup'] = reply_markup
1962 | }}))
1963 | end
1964 |
1965 | api.inline_result_meta = {}
1966 | api.inline_result_meta.__index = api.inline_result_meta
1967 |
1968 | function api.inline_result_meta:type(type)
1969 | self['type'] = tostring(type)
1970 | return self
1971 | end
1972 |
1973 | function api.inline_result_meta:id(id)
1974 | self['id'] = id and tostring(id) or '1'
1975 | return self
1976 | end
1977 |
1978 | function api.inline_result_meta:title(title)
1979 | self['title'] = tostring(title)
1980 | return self
1981 | end
1982 |
1983 | function api.inline_result_meta:input_message_content(input_message_content)
1984 | self['input_message_content'] = input_message_content
1985 | return self
1986 | end
1987 |
1988 | function api.inline_result_meta:reply_markup(reply_markup)
1989 | self['reply_markup'] = reply_markup
1990 | return self
1991 | end
1992 |
1993 | function api.inline_result_meta:url(url)
1994 | self['url'] = tostring(url)
1995 | return self
1996 | end
1997 |
1998 | function api.inline_result_meta:hide_url(hide_url)
1999 | self['hide_url'] = hide_url or false
2000 | return self
2001 | end
2002 |
2003 | function api.inline_result_meta:description(description)
2004 | self['description'] = tostring(description)
2005 | return self
2006 | end
2007 |
2008 | function api.inline_result_meta:thumb_url(thumb_url)
2009 | self['thumb_url'] = tostring(thumb_url)
2010 | return self
2011 | end
2012 |
2013 | function api.inline_result_meta:thumb_width(thumb_width)
2014 | self['thumb_width'] = tonumber(thumb_width)
2015 | return self
2016 | end
2017 |
2018 | function api.inline_result_meta:thumb_height(thumb_height)
2019 | self['thumb_height'] = tonumber(thumb_height)
2020 | return self
2021 | end
2022 |
2023 | function api.inline_result_meta:photo_url(photo_url)
2024 | self['photo_url'] = tostring(photo_url)
2025 | return self
2026 | end
2027 |
2028 | function api.inline_result_meta:photo_width(photo_width)
2029 | self['photo_width'] = tonumber(photo_width)
2030 | return self
2031 | end
2032 |
2033 | function api.inline_result_meta:photo_height(photo_height)
2034 | self['photo_height'] = tonumber(photo_height)
2035 | return self
2036 | end
2037 |
2038 | function api.inline_result_meta:caption(caption)
2039 | self['caption'] = tostring(caption)
2040 | return self
2041 | end
2042 |
2043 | function api.inline_result_meta:gif_url(gif_url)
2044 | self['gif_url'] = tostring(gif_url)
2045 | return self
2046 | end
2047 |
2048 | function api.inline_result_meta:gif_width(gif_width)
2049 | self['gif_width'] = tonumber(gif_width)
2050 | return self
2051 | end
2052 |
2053 | function api.inline_result_meta:gif_height(gif_height)
2054 | self['gif_height'] = tonumber(gif_height)
2055 | return self
2056 | end
2057 |
2058 | function api.inline_result_meta:mpeg4_url(mpeg4_url)
2059 | self['mpeg4_url'] = tostring(mpeg4_url)
2060 | return self
2061 | end
2062 |
2063 | function api.inline_result_meta:mpeg4_width(mpeg4_width)
2064 | self['mpeg4_width'] = tonumber(mpeg4_width)
2065 | return self
2066 | end
2067 |
2068 | function api.inline_result_meta:mpeg4_height(mpeg4_height)
2069 | self['mpeg4_height'] = tonumber(mpeg4_height)
2070 | return self
2071 | end
2072 |
2073 | function api.inline_result_meta:video_url(video_url)
2074 | self['video_url'] = tostring(video_url)
2075 | return self
2076 | end
2077 |
2078 | function api.inline_result_meta:mime_type(mime_type)
2079 | self['mime_type'] = tostring(mime_type)
2080 | return self
2081 | end
2082 |
2083 | function api.inline_result_meta:video_width(video_width)
2084 | self['video_width'] = tonumber(video_width)
2085 | return self
2086 | end
2087 |
2088 | function api.inline_result_meta:video_height(video_height)
2089 | self['video_height'] = tonumber(video_height)
2090 | return self
2091 | end
2092 |
2093 | function api.inline_result_meta:video_duration(video_duration)
2094 | self['video_duration'] = tonumber(video_duration)
2095 | return self
2096 | end
2097 |
2098 | function api.inline_result_meta:audio_url(audio_url)
2099 | self['audio_url'] = tostring(audio_url)
2100 | return self
2101 | end
2102 |
2103 | function api.inline_result_meta:performer(performer)
2104 | self['performer'] = tostring(performer)
2105 | return self
2106 | end
2107 |
2108 | function api.inline_result_meta:audio_duration(audio_duration)
2109 | self['audio_duration'] = tonumber(audio_duration)
2110 | return self
2111 | end
2112 |
2113 | function api.inline_result_meta:voice_url(voice_url)
2114 | self['voice_url'] = tostring(voice_url)
2115 | return self
2116 | end
2117 |
2118 | function api.inline_result_meta:voice_duration(voice_duration)
2119 | self['voice_duration'] = tonumber(voice_duration)
2120 | return self
2121 | end
2122 |
2123 | function api.inline_result_meta:document_url(document_url)
2124 | self['document_url'] = tostring(document_url)
2125 | return self
2126 | end
2127 |
2128 | function api.inline_result_meta:latitude(latitude)
2129 | self['latitude'] = tonumber(latitude)
2130 | return self
2131 | end
2132 |
2133 | function api.inline_result_meta:longitude(longitude)
2134 | self['longitude'] = tonumber(longitude)
2135 | return self
2136 | end
2137 |
2138 | function api.inline_result_meta:live_period(live_period)
2139 | self['live_period'] = tonumber(live_period)
2140 | return self
2141 | end
2142 |
2143 | function api.inline_result_meta:address(address)
2144 | self['address'] = tostring(address)
2145 | return self
2146 | end
2147 |
2148 | function api.inline_result_meta:foursquare_id(foursquare_id)
2149 | self['foursquare_id'] = tostring(foursquare_id)
2150 | return self
2151 | end
2152 |
2153 | function api.inline_result_meta:phone_number(phone_number)
2154 | self['phone_number'] = tostring(phone_number)
2155 | return self
2156 | end
2157 |
2158 | function api.inline_result_meta:first_name(first_name)
2159 | self['first_name'] = tostring(first_name)
2160 | return self
2161 | end
2162 |
2163 | function api.inline_result_meta:last_name(last_name)
2164 | self['last_name'] = tostring(last_name)
2165 | return self
2166 | end
2167 |
2168 | function api.inline_result_meta:game_short_name(game_short_name)
2169 | self['game_short_name'] = tostring(game_short_name)
2170 | return self
2171 | end
2172 |
2173 | function api.inline_result()
2174 | local output = setmetatable({}, api.inline_result_meta)
2175 | return output
2176 | end
2177 |
2178 | function api.send_inline_photo(inline_query_id, photo_url, caption, reply_markup)
2179 | return api.answer_inline_query(inline_query_id, json.encode({{
2180 | ['type'] = 'photo',
2181 | ['id'] = '1',
2182 | ['photo_url'] = photo_url,
2183 | ['thumb_url'] = photo_url,
2184 | ['caption'] = caption,
2185 | ['reply_markup'] = reply_markup
2186 | }}))
2187 | end
2188 |
2189 | function api.send_inline_cached_photo(inline_query_id, photo_file_id, caption, reply_markup)
2190 | return api.answer_inline_query(inline_query_id, json.encode({{
2191 | ['type'] = 'photo',
2192 | ['id'] = '1',
2193 | ['photo_file_id'] = photo_file_id,
2194 | ['caption'] = caption,
2195 | ['reply_markup'] = reply_markup
2196 | }}))
2197 | end
2198 |
2199 | function api.url_button(text, url, encoded)
2200 | if not text or not url then
2201 | return false
2202 | end
2203 | local button = {
2204 | ['text'] = tostring(text),
2205 | ['url'] = tostring(url)
2206 | }
2207 | if encoded then
2208 | button = json.encode(button)
2209 | end
2210 | return button
2211 | end
2212 |
2213 | function api.callback_data_button(text, callback_data, encoded)
2214 | if not text or not callback_data then
2215 | return false
2216 | end
2217 | local button = {
2218 | ['text'] = tostring(text),
2219 | ['callback_data'] = tostring(callback_data)
2220 | }
2221 | if encoded then
2222 | button = json.encode(button)
2223 | end
2224 | return button
2225 | end
2226 |
2227 | function api.switch_inline_query_button(text, switch_inline_query, encoded)
2228 | if not text or not switch_inline_query then
2229 | return false
2230 | end
2231 | local button = {
2232 | ['text'] = tostring(text),
2233 | ['switch_inline_query'] = tostring(switch_inline_query)
2234 | }
2235 | if encoded then
2236 | button = json.encode(button)
2237 | end
2238 | return button
2239 | end
2240 |
2241 | function api.switch_inline_query_current_chat_button(text, switch_inline_query_current_chat, encoded)
2242 | if not text or not switch_inline_query_current_chat then
2243 | return false
2244 | end
2245 | local button = {
2246 | ['text'] = tostring(text),
2247 | ['switch_inline_query_current_chat'] = tostring(switch_inline_query_current_chat)
2248 | }
2249 | if encoded then
2250 | button = json.encode(button)
2251 | end
2252 | return button
2253 | end
2254 |
2255 | function api.callback_game_button(text, callback_game, encoded)
2256 | if not text or not callback_game then
2257 | return false
2258 | end
2259 | local button = {
2260 | ['text'] = tostring(text),
2261 | ['callback_game'] = tostring(callback_game)
2262 | }
2263 | if encoded then
2264 | button = json.encode(button)
2265 | end
2266 | return button
2267 | end
2268 |
2269 | function api.pay_button(text, pay, encoded)
2270 | if not text or pay == nil then
2271 | return false
2272 | end
2273 | local button = {
2274 | ['text'] = tostring(text),
2275 | ['pay'] = pay
2276 | }
2277 | if encoded then
2278 | button = json.encode(button)
2279 | end
2280 | return button
2281 | end
2282 |
2283 | function api.remove_keyboard(selective)
2284 | return {
2285 | ['remove_keyboard'] = true,
2286 | ['selective'] = selective or false
2287 | }
2288 | end
2289 |
2290 | api.keyboard_meta = {}
2291 | api.keyboard_meta.__index = api.keyboard_meta
2292 |
2293 | function api.keyboard_meta:row(row)
2294 | table.insert(self.keyboard, row)
2295 | return self
2296 | end
2297 |
2298 | function api.keyboard(resize_keyboard, one_time_keyboard, selective)
2299 | return setmetatable({
2300 | ['keyboard'] = {},
2301 | ['resize_keyboard'] = resize_keyboard or false,
2302 | ['one_time_keyboard'] = one_time_keyboard or false,
2303 | ['selective'] = selective or false
2304 | }, api.keyboard_meta)
2305 | end
2306 |
2307 | api.inline_keyboard_meta = {}
2308 | api.inline_keyboard_meta.__index = api.inline_keyboard_meta
2309 |
2310 | function api.inline_keyboard_meta:row(row)
2311 | table.insert(self.inline_keyboard, row)
2312 | return self
2313 | end
2314 |
2315 | function api.inline_keyboard()
2316 | return setmetatable({
2317 | ['inline_keyboard'] = {}
2318 | }, api.inline_keyboard_meta)
2319 | end
2320 |
2321 | api.prices_meta = {}
2322 | api.prices_meta.__index = api.prices_meta
2323 |
2324 | function api.prices_meta:labeled_price(label, amount)
2325 | table.insert(self, {
2326 | ['label'] = tostring(label),
2327 | ['amount'] = tonumber(amount)
2328 | })
2329 | return self
2330 | end
2331 |
2332 | function api.prices()
2333 | return setmetatable({}, api.prices_meta)
2334 | end
2335 |
2336 | api.shipping_options_meta = {}
2337 | api.shipping_options_meta.__index = api.shipping_options_meta
2338 |
2339 | function api.shipping_options_meta:shipping_option(id, title, prices)
2340 | table.insert(self, {
2341 | ['id'] = tostring(id),
2342 | ['title'] = tostring(title),
2343 | ['prices'] = prices
2344 | })
2345 | return self
2346 | end
2347 |
2348 | function api.shipping_options()
2349 | return setmetatable({}, api.shipping_options_meta)
2350 | end
2351 |
2352 | api.row_meta = {}
2353 | api.row_meta.__index = api.row_meta
2354 |
2355 | function api.row_meta:url_button(text, url)
2356 | table.insert(self, {
2357 | ['text'] = tostring(text),
2358 | ['url'] = tostring(url)
2359 | })
2360 | return self
2361 | end
2362 |
2363 | function api.row_meta:callback_data_button(text, callback_data)
2364 | table.insert(self, {
2365 | ['text'] = tostring(text),
2366 | ['callback_data'] = tostring(callback_data)
2367 | })
2368 | return self
2369 | end
2370 |
2371 | function api.row_meta:switch_inline_query_button(text, switch_inline_query)
2372 | table.insert(self, {
2373 | ['text'] = tostring(text),
2374 | ['switch_inline_query'] = tostring(switch_inline_query)
2375 | })
2376 | return self
2377 | end
2378 |
2379 | function api.row_meta:switch_inline_query_current_chat_button(text, switch_inline_query_current_chat)
2380 | table.insert(self, {
2381 | ['text'] = tostring(text),
2382 | ['switch_inline_query_current_chat'] = tostring(switch_inline_query_current_chat)
2383 | })
2384 | return self
2385 | end
2386 |
2387 | function api.row_meta:pay_button(text, pay)
2388 | table.insert(self, {
2389 | ['text'] = tostring(text),
2390 | ['pay'] = pay
2391 | })
2392 | return self
2393 | end
2394 |
2395 | function api.row(_)
2396 | return setmetatable({}, api.row_meta)
2397 | end
2398 |
2399 | api.input_media_meta = {}
2400 | api.input_media_meta.__index = api.input_media_meta
2401 |
2402 | function api.input_media_meta:photo(media, caption)
2403 | table.insert(self, {
2404 | ['type'] = 'photo',
2405 | ['media'] = tostring(media),
2406 | ['caption'] = caption
2407 | })
2408 | return self
2409 | end
2410 |
2411 | function api.input_media_meta:video(media, caption, width, height, duration)
2412 | table.insert(self, {
2413 | ['type'] = 'video',
2414 | ['media'] = tostring(media),
2415 | ['caption'] = caption,
2416 | ['width'] = width,
2417 | ['height'] = height,
2418 | ['duration'] = duration
2419 | })
2420 | return self
2421 | end
2422 |
2423 | function api.input_media(_)
2424 | return setmetatable({}, api.input_media_meta)
2425 | end
2426 |
2427 | function api.labeled_price(label, amount, encoded)
2428 | if not label or not amount or tonumber(amount) == nil then
2429 | return false
2430 | end
2431 | local button = {
2432 | ['label'] = tostring(label),
2433 | ['amount'] = tonumber(amount)
2434 | }
2435 | if encoded then
2436 | button = json.encode(button)
2437 | end
2438 | return button
2439 | end
2440 |
2441 | function api.get_chat_member_permissions(chat_id, user_id)
2442 | if not chat_id or not user_id then
2443 | return false
2444 | end
2445 | local success = api.get_chat_member(chat_id, user_id)
2446 | if not success then
2447 | return success
2448 | end
2449 | local p = success.result
2450 | return {
2451 | ['can_be_edited'] = p.can_be_edited or false,
2452 | ['can_post_messages'] = p.can_post_messages or false,
2453 | ['can_edit_messages'] = p.can_edit_messages or false,
2454 | ['can_delete_messages'] = p.can_delete_messages or false,
2455 | ['can_restrict_members'] = p.can_restrict_members or false,
2456 | ['can_promote_members'] = p.can_promote_members or false,
2457 | ['can_change_info'] = p.can_change_info or false,
2458 | ['can_invite_users'] = p.can_invite_users or false,
2459 | ['can_pin_messages'] = p.can_pin_messages or false,
2460 | ['can_send_messages'] = p.can_send_messages or false,
2461 | ['can_send_media_messages'] = p.can_send_media_messages or false,
2462 | ['can_send_polls'] = p.can_send_polls or false,
2463 | ['can_send_other_messages'] = p.can_send_other_messages or false,
2464 | ['can_add_web_page_previews'] = p.can_add_web_page_previews or false
2465 | }
2466 | end
2467 |
2468 | function api.is_user_kicked(chat_id, user_id)
2469 | if not chat_id or not user_id then
2470 | return false
2471 | end
2472 | local user, res = api.get_chat_member(chat_id, user_id)
2473 | if not user or not user.result then
2474 | return false, res
2475 | elseif user.result.status == 'kicked' then
2476 | return true, res
2477 | end
2478 | return false, user.result.status
2479 | end
2480 |
2481 | function api.is_user_group_admin(chat_id, user_id)
2482 | if not chat_id or not user_id then
2483 | return false
2484 | end
2485 | local user, res = api.get_chat_member(chat_id, user_id)
2486 | if not user or not user.result then
2487 | return false, res
2488 | elseif user.result.status == ('administrator' or 'creator') then
2489 | return true, res
2490 | end
2491 | return false, user.result.status
2492 | end
2493 |
2494 | function api.is_user_group_creator(chat_id, user_id)
2495 | if not chat_id or not user_id then
2496 | return false
2497 | end
2498 | local user, res = api.get_chat_member(chat_id, user_id)
2499 | if not user or not user.result then
2500 | return false, res
2501 | elseif user.result.status == 'creator' then
2502 | return true, res
2503 | end
2504 | return false, user.result.status
2505 | end
2506 |
2507 | function api.is_user_restricted(chat_id, user_id)
2508 | if not chat_id or not user_id then
2509 | return false
2510 | end
2511 | local user, res = api.get_chat_member(chat_id, user_id)
2512 | if not user or not user.result then
2513 | return false, res
2514 | elseif user.result.status == 'kicked' then
2515 | return true, res
2516 | end
2517 | return false, user.result.status
2518 | end
2519 |
2520 | function api.has_user_left(chat_id, user_id)
2521 | if not chat_id or not user_id then
2522 | return false
2523 | end
2524 | local user, res = api.get_chat_member(chat_id, user_id)
2525 | if not user or not user.result then
2526 | return false, res
2527 | elseif user.result.status == 'left' then
2528 | return true, res
2529 | end
2530 | return false, user.result.status
2531 | end
2532 |
2533 | -- New stuff, to be sorted
2534 |
2535 | function api.reaction_type_emoji(emoji)
2536 | return {
2537 | ['type'] = 'emoji',
2538 | ['emoji'] = emoji
2539 | }
2540 | end
2541 |
2542 | function api.reaction_type_custom_emoji(custom_emoji_id)
2543 | return {
2544 | ['type'] = 'custom_emoji',
2545 | ['custom_emoji_id'] = custom_emoji_id
2546 | }
2547 | end
2548 |
2549 | function api.chat_permissions(can_send_messages, can_send_audios, can_send_documents, can_send_photos, can_send_videos,
2550 | can_send_video_notes, can_send_voice_notes, can_send_polls, can_send_other_messages, can_add_web_page_previews,
2551 | can_change_info, can_invite_users, can_pin_messages, can_manage_topics)
2552 | return {
2553 | ['can_send_messages'] = can_send_messages,
2554 | ['can_send_audios'] = can_send_audios,
2555 | ['can_send_documents'] = can_send_documents,
2556 | ['can_send_photos'] = can_send_photos,
2557 | ['can_send_videos'] = can_send_videos,
2558 | ['can_send_video_notes'] = can_send_video_notes,
2559 | ['can_send_voice_notes'] = can_send_voice_notes,
2560 | ['can_send_polls'] = can_send_polls,
2561 | ['can_send_other_messages'] = can_send_other_messages,
2562 | ['can_add_web_page_previews'] = can_add_web_page_previews,
2563 | ['can_change_info'] = can_change_info,
2564 | ['can_invite_users'] = can_invite_users,
2565 | ['can_pin_messages'] = can_pin_messages,
2566 | ['can_manage_topics'] = can_manage_topics
2567 | }
2568 | end
2569 |
2570 | function api.bot_command(command, description)
2571 | command = tostring(command)
2572 | description = tostring(description)
2573 | if command:len() > 32 then
2574 | command = command:sub(1, 32)
2575 | end
2576 | if description:len() > 256 then
2577 | description = description:sub(1, 256)
2578 | end
2579 | return {
2580 | ['command'] = command,
2581 | ['description'] = description
2582 | }
2583 | end
2584 |
2585 | function api.bot_command_scope_default()
2586 | return {
2587 | ['type'] = 'default'
2588 | }
2589 | end
2590 |
2591 | function api.bot_command_scope_all_private_chats()
2592 | return {
2593 | ['type'] = 'all_private_chats'
2594 | }
2595 | end
2596 |
2597 | function api.bot_command_scope_all_group_chats()
2598 | return {
2599 | ['type'] = 'all_group_chats'
2600 | }
2601 | end
2602 |
2603 | function api.bot_command_scope_all_chat_administrators()
2604 | return {
2605 | ['type'] = 'all_chat_administrators'
2606 | }
2607 | end
2608 |
2609 | function api.bot_command_scope_chat(chat_id)
2610 | return {
2611 | ['type'] = 'chat',
2612 | ['chat_id'] = chat_id
2613 | }
2614 | end
2615 |
2616 | function api.bot_command_scope_chat_administrators(chat_id)
2617 | return {
2618 | ['type'] = 'chat_administrators',
2619 | ['chat_id'] = chat_id
2620 | }
2621 | end
2622 |
2623 | function api.bot_command_scope_chat_member(chat_id, user_id)
2624 | return {
2625 | ['type'] = 'chat_member',
2626 | ['chat_id'] = chat_id,
2627 | ['user_id'] = user_id
2628 | }
2629 | end
2630 |
2631 | function api.menu_button_commands()
2632 | return {
2633 | ['type'] = 'commands'
2634 | }
2635 | end
2636 |
2637 | function api.menu_button_web_app(text, web_app)
2638 | return {
2639 | ['type'] = 'web_app',
2640 | ['text'] = text,
2641 | ['web_app'] = web_app
2642 | }
2643 | end
2644 |
2645 | function api.menu_button_default()
2646 | return {
2647 | ['type'] = 'default'
2648 | }
2649 | end
2650 |
2651 | function api.chat_administrator_rights(is_anonymous, can_manage_chat, can_delete_messages, can_manage_video_chats,
2652 | can_restrict_members, can_promote_members, can_change_info, can_invite_users, can_post_messages, can_edit_messages,
2653 | can_pin_messages, can_post_stories, can_edit_stories, can_delete_stories, can_manage_topics)
2654 | return {
2655 | ['is_anonymous'] = is_anonymous,
2656 | ['can_manage_chat'] = can_manage_chat,
2657 | ['can_delete_messages'] = can_delete_messages,
2658 | ['can_manage_video_chats'] = can_manage_video_chats,
2659 | ['can_restrict_members'] = can_restrict_members,
2660 | ['can_promote_members'] = can_promote_members,
2661 | ['can_change_info'] = can_change_info,
2662 | ['can_invite_users'] = can_invite_users,
2663 | ['can_post_messages'] = can_post_messages,
2664 | ['can_edit_messages'] = can_edit_messages,
2665 | ['can_pin_messages'] = can_pin_messages,
2666 | ['can_post_stories'] = can_post_stories,
2667 | ['can_edit_stories'] = can_edit_stories,
2668 | ['can_delete_stories'] = can_delete_stories,
2669 | ['can_manage_topics'] = can_manage_topics
2670 | }
2671 | end
2672 |
2673 | function api.link_preview_options(is_disabled, url, prefer_small_media, prefer_large_media, show_above_text)
2674 | return {
2675 | ['is_disabled'] = is_disabled,
2676 | ['url'] = url,
2677 | ['prefer_small_media'] = prefer_small_media,
2678 | ['prefer_large_media'] = prefer_large_media,
2679 | ['show_above_text'] = show_above_text
2680 | }
2681 | end
2682 |
2683 | function api.message_entity(entity_type, offset, length, url, user, language, custom_emoji_id)
2684 | return {
2685 | ['type'] = tostring(entity_type),
2686 | ['offset'] = tonumber(offset),
2687 | ['length'] = tonumber(length),
2688 | ['url'] = tostring(url),
2689 | ['user'] = type(user) == 'table' and user or nil,
2690 | ['language'] = tostring(language),
2691 | ['custom_emoji_id'] = tostring(custom_emoji_id)
2692 | }
2693 | end
2694 |
2695 | function api.reply_parameter(message_id, chat_id, allow_sending_without_reply, quote, quote_parse_mode, quote_entities,
2696 | quote_position)
2697 | quote_entities = type(quote_entities) == 'table' and json.encode(quote_entities) or quote_entities
2698 | return {
2699 | ['message_id'] = tonumber(message_id),
2700 | ['chat_id'] = chat_id,
2701 | ['allow_sending_without_reply'] = allow_sending_without_reply,
2702 | ['quote'] = quote,
2703 | ['quote_parse_mode'] = quote_parse_mode,
2704 | ['quote_entities'] = quote_entities,
2705 | ['quote_position'] = tonumber(quote_position)
2706 | }
2707 | end
2708 |
2709 | function api.input_sticker(sticker, emoji_list, mask_position, keywords)
2710 | return {
2711 | ['sticker'] = sticker,
2712 | ['emoji_list'] = emoji_list,
2713 | ['mask_position'] = mask_position,
2714 | ['keywords'] = keywords
2715 | }
2716 | end
2717 |
2718 | function api.inline_query_results_button(text, web_app, start_parameter)
2719 | return {
2720 | ['text'] = text,
2721 | ['web_app'] = web_app,
2722 | ['start_parameter'] = start_parameter
2723 | }
2724 | end
2725 |
2726 | function api.labeled_price(label, amount)
2727 | return {
2728 | ['label'] = label,
2729 | ['amount'] = amount
2730 | }
2731 | end
2732 |
2733 | function api.passport_element_error_data_field(error_type, field_name, data_hash, message)
2734 | return {
2735 | ['source'] = 'data',
2736 | ['type'] = error_type,
2737 | ['field_name'] = field_name,
2738 | ['data_hash'] = data_hash,
2739 | ['message'] = message
2740 | }
2741 | end
2742 |
2743 | function api.passport_element_error_front_side(error_type, file_hash, message)
2744 | return {
2745 | ['source'] = 'front_side',
2746 | ['type'] = error_type,
2747 | ['file_hash'] = file_hash,
2748 | ['message'] = message
2749 | }
2750 | end
2751 |
2752 | function api.passport_element_error_reverse_side(error_type, file_hash, message)
2753 | return {
2754 | ['source'] = 'reverse_side',
2755 | ['type'] = error_type,
2756 | ['file_hash'] = file_hash,
2757 | ['message'] = message
2758 | }
2759 | end
2760 |
2761 | function api.passport_element_error_selfie(error_type, file_hash, message)
2762 | return {
2763 | ['source'] = 'selfie',
2764 | ['type'] = error_type,
2765 | ['file_hash'] = file_hash,
2766 | ['message'] = message
2767 | }
2768 | end
2769 |
2770 | function api.passport_element_error_file(error_type, file_hash, message)
2771 | return {
2772 | ['source'] = 'file',
2773 | ['type'] = error_type,
2774 | ['file_hash'] = file_hash,
2775 | ['message'] = message
2776 | }
2777 | end
2778 |
2779 | function api.passport_element_error_files(error_type, file_hashes, message)
2780 | return {
2781 | ['source'] = 'files',
2782 | ['type'] = error_type,
2783 | ['file_hashes'] = file_hashes,
2784 | ['message'] = message
2785 | }
2786 | end
2787 |
2788 | function api.passport_element_error_translation_file(error_type, file_hash, message)
2789 | return {
2790 | ['source'] = 'translation_file',
2791 | ['type'] = error_type,
2792 | ['file_hash'] = file_hash,
2793 | ['message'] = message
2794 | }
2795 | end
2796 |
2797 | function api.passport_element_error_translation_files(error_type, file_hashes, message)
2798 | return {
2799 | ['source'] = 'translation_files',
2800 | ['type'] = error_type,
2801 | ['file_hashes'] = file_hashes,
2802 | ['message'] = message
2803 | }
2804 | end
2805 |
2806 | function api.passport_element_error_unspecified(error_type, element_hash, message)
2807 | return {
2808 | ['source'] = 'unspecified',
2809 | ['type'] = error_type,
2810 | ['element_hash'] = element_hash,
2811 | ['message'] = message
2812 | }
2813 | end
2814 |
2815 | function api.web_app_info(url)
2816 | return {
2817 | ['url'] = url
2818 | }
2819 | end
2820 |
2821 | return api
2822 |
--------------------------------------------------------------------------------
/src/tools.lua:
--------------------------------------------------------------------------------
1 | --[[
2 |
3 | _ _ _ _ _
4 | | | | | | | | | | |
5 | | |_ ___| | ___ __ _ _ __ __ _ _ __ ___ ______| |__ ___ | |_ ______| |_ _ __ _
6 | | __/ _ \ |/ _ \/ _` | '__/ _` | '_ ` _ \______| '_ \ / _ \| __|______| | | | |/ _` |
7 | | || __/ | __/ (_| | | | (_| | | | | | | | |_) | (_) | |_ | | |_| | (_| |
8 | \__\___|_|\___|\__, |_| \__,_|_| |_| |_| |_.__/ \___/ \__| |_|\__,_|\__,_|
9 | __/ |
10 | |___/
11 |
12 | Version 2.0-0
13 | Copyright (c) 2017-2024 Matthew Hesketh
14 | See LICENSE for details
15 |
16 | ]] local tools = {}
17 | local api = require('telegram-bot-lua.core')
18 | local https = require('ssl.https')
19 | local http = require('socket.http')
20 | local socket = require('socket')
21 | local ltn12 = require('ltn12')
22 | local json = require('dkjson')
23 | local utf8 = utf8 or require('lua-utf8') -- Lua 5.2 compatibility.
24 | local b64url = require('telegram-bot-lua.b64url')
25 |
26 | function tools.comma_value(amount)
27 | amount = tostring(amount)
28 | local k
29 | while true do
30 | amount, k = amount:gsub('^(-?%d+)(%d%d%d)', '%1,%2')
31 | if k == 0 then
32 | break
33 | end
34 | end
35 | return amount
36 | end
37 |
38 | function tools.format_ms(milliseconds)
39 | local total_seconds = math.floor(milliseconds / 1000)
40 | local seconds = total_seconds % 60
41 | local minutes = math.floor(total_seconds / 60) % 60
42 | local hours = math.floor(minutes / 60)
43 | return string.format('%02d:%02d:%02d', hours, minutes, seconds)
44 | end
45 |
46 | function tools.format_time(seconds)
47 | if not seconds or tonumber(seconds) == nil then
48 | return false
49 | end
50 | seconds = tonumber(seconds) -- Make sure we're handling a numerical value
51 | local minutes = math.floor(seconds / 60)
52 | if minutes == 0 then
53 | return seconds ~= 1 and seconds .. ' seconds' or seconds .. ' second'
54 | elseif minutes < 60 then
55 | return minutes ~= 1 and minutes .. ' minutes' or minutes .. ' minute'
56 | end
57 | local hours = math.floor(seconds / 3600)
58 | if hours == 0 then
59 | return minutes ~= 1 and minutes .. ' minutes' or minutes .. ' minute'
60 | elseif hours < 24 then
61 | return hours ~= 1 and hours .. ' hours' or hours .. ' hour'
62 | end
63 | local days = math.floor(seconds / 86400)
64 | if days == 0 then
65 | return hours ~= 1 and hours .. ' hours' or hours .. ' hour'
66 | elseif days < 7 then
67 | return days ~= 1 and days .. ' days' or days .. ' day'
68 | end
69 | local weeks = math.floor(seconds / 604800)
70 | if weeks == 0 then
71 | return days ~= 1 and days .. ' days' or days .. ' day'
72 | else
73 | return weeks ~= 1 and weeks .. ' weeks' or weeks .. ' week'
74 | end
75 | end
76 |
77 | function tools.round(num, idp)
78 | if idp and idp > 0 then
79 | local mult = 10 ^ idp
80 | return math.floor(num * mult + .5) / mult
81 | end
82 | return math.floor(num + .5)
83 | end
84 |
85 | function tools.pretty_print(table)
86 | return json.encode(table, {
87 | ['indent'] = true
88 | })
89 | end
90 |
91 | tools.commands_meta = {}
92 | tools.commands_meta.__index = tools.commands_meta
93 |
94 | function tools.commands_meta:command(command)
95 | table.insert(self.table, '^[/!#]' .. command .. '$')
96 | table.insert(self.table, '^[/!#]' .. command .. '@' .. self.username .. '$')
97 | table.insert(self.table, '^[/!#]' .. command .. '%s+[^%s]*')
98 | table.insert(self.table, '^[/!#]' .. command .. '@' .. self.username .. '%s+[^%s]*')
99 | return self
100 | end
101 |
102 | function tools.commands(username, command_table)
103 | local self = setmetatable({}, tools.commands_meta)
104 | self.username = username
105 | self.table = command_table or {}
106 | return self
107 | end
108 |
109 | function tools.table_size(t)
110 | local i = 0
111 | for _ in pairs(t) do
112 | i = i + 1
113 | end
114 | return i
115 | end
116 |
117 | function tools.escape_markdown(str)
118 | return tostring(str):gsub('_', '\\_'):gsub('%[', '\\['):gsub('*', '\\*'):gsub('`', '\\`')
119 | end
120 |
121 | function tools.escape_html(str)
122 | return tostring(str):gsub('&', '&'):gsub('<', '<'):gsub('>', '>')
123 | end
124 |
125 | function tools.escape_bash(str)
126 | return tostring(str):gsub('%$', ''):gsub('%^', ''):gsub('&', ''):gsub('|', ''):gsub(';', '')
127 | end
128 |
129 | function tools.utf8_len(str)
130 | local chars = 0
131 | for i = 1, str:len() do
132 | local byte = str:byte(i)
133 | if byte < 128 or byte >= 192 then
134 | chars = chars + 1
135 | end
136 | end
137 | return chars
138 | end
139 |
140 | function tools.get_linked_name(id)
141 | local success = api.get_chat(id)
142 | if not success or not success.result then
143 | return false
144 | end
145 | local output = tools.escape_html(success.result.first_name)
146 | if success.result.username then
147 | output = '' .. output .. ''
148 | end
149 | return output
150 | end
151 |
152 | function tools.get_word(str, i)
153 | if not str then
154 | return false
155 | end
156 | i = i or 1
157 | local n = 1
158 | for word in str:gmatch('%g+') do
159 | if n == i then
160 | return word
161 | end
162 | n = n + 1
163 | end
164 | return false
165 | end
166 |
167 | function tools.input(s)
168 | if not s then
169 | return false
170 | end
171 | local input = s:find(' ')
172 | if not input then
173 | return false
174 | end
175 | return s:sub(input + 1)
176 | end
177 |
178 | function tools.trim(str)
179 | return str:gsub('^%s*(.-)%s*$', '%1')
180 | end
181 |
182 | tools.symbols = {
183 | ['back'] = utf8.char(8592),
184 | ['previous'] = utf8.char(8592),
185 | ['forward'] = utf8.char(8594),
186 | ['next'] = utf8.char(8594),
187 | ['bullet'] = utf8.char(8226),
188 | ['bullet_point'] = utf8.char(8226)
189 | }
190 |
191 | function tools.create_link(text, link, parse_mode)
192 | text = tostring(text)
193 | parse_mode = parse_mode == true and 'markdown' or tostring(parse_mode)
194 | if not link then
195 | return text
196 | elseif parse_mode:lower() == 'markdown' then
197 | return '[' .. tools.escape_markdown(text) .. '](' .. tools.escape_markdown(link) .. ')'
198 | end
199 | return '' .. tools.escape_html(text) .. ''
200 | end
201 |
202 | function tools.download_file(url, name, path)
203 | name = name or os.time() .. '.' .. url:match('.+%/%.(.-)$')
204 | local body = {}
205 | local _, res
206 | if url:match('^https') then
207 | _, res = https.request({
208 | ['url'] = url,
209 | ['sink'] = ltn12.sink.table(body)
210 | })
211 | else
212 | _, res = http.request({
213 | ['url'] = url,
214 | ['sink'] = ltn12.sink.table(body),
215 | ['redirect'] = true
216 | })
217 | end
218 | if res ~= 200 then
219 | error(res)
220 | return false
221 | end
222 | path = path and tostring(path) or '/tmp/'
223 | if not path:match('^/') then
224 | path = '/' .. path
225 | end
226 | if not path:match('/$') then
227 | path = path .. '/'
228 | end
229 | local file = io.open(path .. name, 'w+')
230 | local contents = table.concat(body)
231 | file:write(contents)
232 | file:close()
233 | path = path .. name
234 | return path
235 | end
236 |
237 | function tools.save_to_file(data, filename, append)
238 | if not data or not filename then
239 | return false
240 | end
241 | local mode = append and 'a+' or 'w+'
242 | if not filename:match('^/') then
243 | filename = '/tmp/' .. filename
244 | end
245 | local file = io.open(filename, mode)
246 | file:write(data)
247 | file:close()
248 | return filename
249 | end
250 |
251 | function tools.file_exists(path)
252 | local file = io.open(path, 'rb')
253 | if file then
254 | file:close()
255 | end
256 | return file ~= nil
257 | end
258 |
259 | function tools.get_file_as_table(path)
260 | if not path or not tools.file_exists(path) then
261 | return {}
262 | end
263 | local file = {}
264 | for line in io.lines(file) do
265 | file[#file + 1] = line
266 | end
267 | return file
268 | end
269 |
270 | function tools.read_file(path)
271 | if not path then
272 | return false
273 | end
274 | local file = io.open(path, 'rb')
275 | if not file then
276 | return false
277 | end
278 | local data = file:read('*all')
279 | file:close()
280 | return data
281 | end
282 |
283 | function tools.json_to_table(path)
284 | if not path then
285 | return {}
286 | end
287 | local parsed = tools.read_file(path)
288 | if not parsed then
289 | return {}
290 | end
291 | parsed = json.decode(parsed)
292 | return type(parsed) == 'table' and parsed or {}
293 | end
294 |
295 | function tools.get_formatted_user(user_id, name, parse_mode)
296 | if not user_id or not name then
297 | return false
298 | end
299 | if not parse_mode or type(parse_mode) == ('nil' or 'boolean') then
300 | parse_mode = 'MarkdownV2'
301 | end
302 | local user_id_string = '[%s](tg://user?id=%s)'
303 | if parse_mode:lower() == 'html' then
304 | user_id_string = '%s'
305 | return string.format(user_id_string, user_id, tools.escape_html(name))
306 | end
307 | return string.format(user_id_string, tools.escape_markdown(name), user_id)
308 | end
309 |
310 | tools.random_string_charset = {}
311 |
312 | for i = 65, 90 do
313 | table.insert(tools.random_string_charset, string.char(i))
314 | end
315 |
316 | for i = 97, 122 do
317 | table.insert(tools.random_string_charset, string.char(i))
318 | end
319 |
320 | function tools.random_string(length, amount)
321 | if not length or tonumber(length) <= 0 then
322 | return ''
323 | end
324 | local command = io.popen('shuf -i 1-100000 -n 1') -- uses shuf for another random value because everything in lua is shocking
325 | local seed = command:read('*all')
326 | command:close()
327 | seed = tonumber(seed) * socket.gettime()
328 | math.randomseed(seed)
329 | if amount and tonumber(amount) ~= nil then
330 | local output = {}
331 | for _ = 1, tonumber(amount) do
332 | local value = tools.random_string(length - 1) ..
333 | tools.random_string_charset[math.random(1, #tools.random_string_charset)]
334 | table.insert(output, value)
335 | end
336 | return output
337 | end
338 | return tools.random_string(length - 1) .. tools.random_string_charset[math.random(1, #tools.random_string_charset)]
339 | end
340 |
341 | function tools.string_hexdump(data, length, size, space)
342 | data = tostring(data)
343 | size = (tonumber(size) == nil or tonumber(size) < 1) and 1 or tonumber(size)
344 | space = (tonumber(space) == nil or tonumber(space) < 1) and 8 or tonumber(space)
345 | length = (tonumber(length) == nil or tonumber(length) < 1) and 32 or tonumber(length)
346 | local output = {}
347 | local column = 0
348 | for i = 1, #data, size do
349 | for j = size, 1, -1 do
350 | local sub = string.sub(data, i + j - 1, i + j - 1)
351 | if #sub > 0 then
352 | local byte = string.byte(sub)
353 | local formatted = string.format('%.2x', byte)
354 | table.insert(output, formatted)
355 | end
356 | end
357 | if column % space == 0 then
358 | table.insert(output, ' ')
359 | end
360 | if (i + size - 1) % length == 0 then
361 | table.insert(output, '\n')
362 | end
363 | column = column + 1
364 | end
365 | return table.concat(output)
366 | end
367 |
368 | function tools.table_contains(tab, match)
369 | if type(tab) ~= 'table' then
370 | return false
371 | end
372 | for _, val in pairs(tab) do
373 | if val == match then
374 | return true
375 | end
376 | end
377 | return false
378 | end
379 |
380 | function tools.table_random(tab, seed)
381 | if seed and tonumber(seed) ~= nil then
382 | math.randomseed(seed)
383 | end
384 | tab = type(tab) == 'table' and tab or {tostring(tab)}
385 | local total = 0
386 | for _, chance in pairs(tab) do
387 | total = total + chance
388 | end
389 | local choice = math.random() * total
390 | for key, chance in pairs(tab) do
391 | choice = choice - chance
392 | if choice < 0 then
393 | return key
394 | end
395 | end
396 | end
397 |
398 | function tools.get_word(str, i)
399 | if not str then
400 | return false
401 | end
402 | local n = 1
403 | for word in str:gmatch('%g+') do
404 | i = i or 1
405 | if n == i then
406 | return word
407 | end
408 | n = n + 1
409 | end
410 | return false
411 | end
412 |
413 | function tools.service_message(message)
414 | if message.new_chat_member then
415 | return true, 'new_chat_member'
416 | elseif message.left_chat_member then
417 | return true, 'left_chat_member'
418 | elseif message.new_chat_title then
419 | return true, 'new_chat_title'
420 | elseif message.new_chat_photo then
421 | return true, 'new_chat_photo'
422 | elseif message.delete_chat_photo then
423 | return true, 'delete_chat_photo'
424 | elseif message.group_chat_created then
425 | return true, 'group_chat_created'
426 | elseif message.supergroup_chat_created then
427 | return true, 'supergroup_chat_created'
428 | elseif message.channel_chat_created then
429 | return true, 'channel_chat_created'
430 | elseif message.migrate_to_chat_id then
431 | return true, 'migrate_to_chat_id'
432 | elseif message.migrate_from_chat_id then
433 | return true, 'migrate_from_chat_id'
434 | elseif message.pinned_message then
435 | return true, 'pinned_message'
436 | elseif message.successful_payment then
437 | return true, 'successful_payment'
438 | end
439 | return false
440 | end
441 |
442 | function tools.is_media(message)
443 | if message.audio or message.document or message.game or message.photo or message.sticker or message.video or
444 | message.voice or message.video_note or message.contact or message.location or message.venue or message.invoice or
445 | message.poll or message.dice then
446 | return true
447 | end
448 | return false
449 | end
450 |
451 | function tools.media_type(message)
452 | if message.audio then
453 | return 'audio'
454 | elseif message.document then
455 | return 'document'
456 | elseif message.game then
457 | return 'game'
458 | elseif message.photo then
459 | return 'photo'
460 | elseif message.sticker then
461 | return 'sticker'
462 | elseif message.video then
463 | return 'video'
464 | elseif message.voice then
465 | return 'voice'
466 | elseif message.video_note then
467 | return 'video note'
468 | elseif message.contact then
469 | return 'contact'
470 | elseif message.location then
471 | return 'location'
472 | elseif message.venue then
473 | return 'venue'
474 | elseif message.invoice then
475 | return 'invoice'
476 | elseif message.forward_from or message.forward_from_chat then
477 | return 'forwarded'
478 | elseif message.dice then
479 | return 'dice'
480 | elseif message.poll then
481 | return 'poll'
482 | elseif message.text then
483 | return (message.text:match('[\216-\219][\128-\191]') or message.text:match(utf8.char(0x202e)) or
484 | message.text:match(utf8.char(0x200f))) and 'rtl' or 'text'
485 | end
486 | return ''
487 | end
488 |
489 | function tools.file_id(message, unique)
490 | if message.audio then
491 | if unique then
492 | return message.audio.file_unique_id
493 | end
494 | return message.audio.file_id
495 | elseif message.document then
496 | if unique then
497 | return message.document.file_unique_id
498 | end
499 | return message.document.file_id
500 | elseif message.sticker then
501 | if unique then
502 | return message.sticker.file_unique_id
503 | end
504 | return message.sticker.file_id
505 | elseif message.video then
506 | if unique then
507 | return message.video.file_unique_id
508 | end
509 | return message.video.file_id
510 | elseif message.voice then
511 | if unique then
512 | return message.voice.file_unique_id
513 | end
514 | return message.voice.file_id
515 | elseif message.video_note then
516 | if unique then
517 | return message.video_note.file_unique_id
518 | end
519 | return message.video_note.file_id
520 | elseif message.photo then -- Get the highest resolution for photos.
521 | if unique then
522 | return message.photo[#message.photo].file_unique_id
523 | end
524 | return message.photo[#message.photo].file_id
525 | end
526 | return ''
527 | end
528 |
529 | function tools.is_duplicate(tab, val)
530 | local seen = {}
531 | local duplicated = {}
532 | for i = 1, #tab do
533 | local element = tab[i]
534 | if seen[element] then
535 | duplicated[element] = true
536 | else
537 | seen[element] = true
538 | end
539 | end
540 | if val and duplicated[val] then
541 | return true
542 | elseif val then
543 | return false
544 | end
545 | return duplicated
546 | end
547 |
548 | function tools.is_valid_url(original_url, parts, any)
549 | if not original_url then
550 | return false
551 | end
552 | original_url = tostring(original_url)
553 | if not original_url:match('^[Hh][Tt][Tt][Pp][Ss]?://') and not any then
554 | original_url = 'http://' .. original_url
555 | end
556 | -- Thanks to https://stackoverflow.com/questions/23590304/finding-a-url-in-a-string-lua-pattern
557 | local url, protocol, subdomain, tld, colon, port, slash, path = string.match(original_url,
558 | '^(([%w_.~!*:@&+$/?%%#-]-)(%w[-.%w]*%.)(%w+)(:?)(%d*)(/?)([%w_.~!*:@&+$/?%%#=-]*))$')
559 | if parts then
560 | return {
561 | ['url'] = url,
562 | ['protocol'] = protocol,
563 | ['subdomain'] = subdomain,
564 | ['tld'] = tld,
565 | ['colon'] = colon,
566 | ['port'] = port,
567 | ['slash'] = slash,
568 | ['path'] = path
569 | }
570 | end
571 | return url and true or false, url
572 | end
573 |
574 | function tools.file_size(file)
575 | local is_path = false
576 | if type(file) ~= 'userdata' and type(file) ~= 'string' then
577 | return false, 'No file/path given!'
578 | elseif type(file) == 'string' then
579 | is_path = true
580 | if not file:match('^/') then
581 | file = '/' .. file
582 | end
583 | if file:match('/$') then
584 | file = file:match('^(.-)/$')
585 | end
586 | file = io.open(file, 'r')
587 | end
588 | local current = file:seek()
589 | local size = file:seek('end')
590 | file:seek('set', current)
591 | if is_path then
592 | file:close()
593 | end
594 | return tonumber(size)
595 | end
596 |
597 | function tools.rle_encode(s)
598 | local new, count = '', 0
599 | for i = 1, #s do
600 | local current = s:sub(i, i)
601 | if current == string.char(0) then
602 | count = count + 1
603 | else
604 | if count > 0 then
605 | new = new .. string.char(0) .. string.char(count)
606 | count = 0
607 | end
608 | new = new .. current
609 | end
610 | end
611 | return new
612 | end
613 |
614 | function tools.rle_decode(input)
615 | local new = ''
616 | local last = ''
617 | local length = #input
618 | for i = 1, length do
619 | local current = input:sub(i, i)
620 | if last == string.char(0) then
621 | new = new .. string.rep(last, string.byte(current))
622 | last = ''
623 | else
624 | new = new .. last
625 | last = current
626 | end
627 | end
628 | return new .. last
629 | end
630 |
631 | function tools.unpack_telegram_invite_link(link)
632 | if not link then
633 | return false, 'No link given!'
634 | elseif link:match('joinchat/') then
635 | link = link:match('joinchat/(.-)$')
636 | end
637 | local append = ''
638 | local amount = (string.len(link) % 4)
639 | for _ = 1, amount do
640 | append = append .. '='
641 | end
642 | local decoded = b64url.decode(link .. append)
643 | if not decoded then
644 | return false, 'Could not decode!'
645 | end
646 | local user_id, chat_id, rand_long = string.unpack('>IIL', decoded)
647 | return {
648 | ['user_id'] = user_id,
649 | ['chat_id'] = chat_id,
650 | ['rand_long'] = rand_long
651 | }
652 | end
653 |
654 | function tools.unpack_file_id(file_id, media_type)
655 | if not file_id then
656 | return false, 'No file_id given!'
657 | elseif not media_type then
658 | media_type = ''
659 | end
660 | local append = ''
661 | local amount = (string.len(file_id) % 4)
662 | for _ = 1, amount do
663 | append = append .. '='
664 | end
665 | local decoded = tools.rle_decode(b64url.decode(file_id .. append))
666 | if not decoded then
667 | return false, 'Could not decode!'
668 | end
669 | local file_type = string.unpack('> 32
708 | end
709 | return payload
710 | end
711 |
712 | function tools.unpack_inline_message_id(inline_message_id)
713 | if not inline_message_id then
714 | return false, 'No inline_message_id given!'
715 | end
716 | local append = ''
717 | local amount = (string.len(inline_message_id) % 4)
718 | for _ = 1, amount do
719 | append = append .. '='
720 | end
721 | local decoded = b64url.decode(inline_message_id .. append)
722 | if not decoded then
723 | return false, 'Could not decode!'
724 | end
725 | local dc_id, message_id, chat_id, access_hash = string.unpack('= 2.5-2",
27 | "lpeg >= 1.0.1-1",
28 | "luasec >= 0.6-1",
29 | "luasocket >= 3.0rc1-2",
30 | "multipart-post >= 1.1-1",
31 | "luautf8 >= 0.1.1-1",
32 | "html-entities >= 1.3.1-0"
33 | }
34 |
35 | build = {
36 | type = "builtin",
37 | modules = {
38 | ["telegram-bot-lua.config"] = "src/config.lua",
39 | ["telegram-bot-lua.core"] = "src/core.lua",
40 | ["telegram-bot-lua.tools"] = "src/tools.lua",
41 | ["telegram-bot-lua.b64url"] = "src/b64url.lua"
42 | }
43 | }
44 |
--------------------------------------------------------------------------------