diff --git a/README.md b/README.md index dce9d56..4530b9d 100644 --- a/README.md +++ b/README.md @@ -95,7 +95,7 @@ api.run({ timeout = 60 }) ``` src/ - init.lua -- Entry point, core HTTP, module loader + main.lua -- Entry point, core HTTP, module loader config.lua -- API endpoint configuration polyfill.lua -- Lua 5.1+ compatibility (bit ops, string.pack) async.lua -- Copas-based concurrency module @@ -137,6 +137,74 @@ luarocks install busted busted ``` +## Migrating from v2 + +v3 includes a compatibility layer that lets most v2 code run with deprecation warnings. Here's what to do: + +### 1. Update + +``` +luarocks install telegram-bot-lua +``` + +LuaRocks handles dependency changes automatically (`lpeg` and `html-entities` removed, `copas` added). + +### 2. Update your require (optional but recommended) + +```lua +-- v2 +local api = require('telegram-bot-lua.core').configure('TOKEN') + +-- v3 +local api = require('telegram-bot-lua').configure('TOKEN') +``` + +The old `require('telegram-bot-lua.core')` still works but prints a deprecation warning. + +### 3. Update method calls (optional but recommended) + +v3 uses options tables instead of positional args. The compat layer auto-detects v2-style calls and converts them, but you should update your code: + +```lua +-- v2 +api.send_message(chat_id, text, nil, 'HTML', nil, nil, false, false, reply_params, reply_markup) +api.send_photo(chat_id, photo, nil, 'Caption', 'HTML') +api.answer_callback_query(id, 'Alert text', true) +api.edit_message_text(chat_id, msg_id, text, 'HTML') +api.run(1, 60) + +-- v3 +api.send_message(chat_id, text, { parse_mode = 'HTML', reply_parameters = reply_params, reply_markup = reply_markup }) +api.send_photo(chat_id, photo, { caption = 'Caption', parse_mode = 'HTML' }) +api.answer_callback_query(id, { text = 'Alert text', show_alert = true }) +api.edit_message_text(chat_id, msg_id, text, { parse_mode = 'HTML' }) +api.run({ timeout = 60 }) +``` + +### 4. Renamed methods + +These v2 methods are aliased with deprecation warnings: + +| v2 | v3 | +|----|-----| +| `kick_chat_member(chat_id, user_id, until_date)` | `ban_chat_member(chat_id, user_id, opts)` | +| `get_chat_members_count(chat_id)` | `get_chat_member_count(chat_id)` | + +### 5. Async is now the default + +`api.run()` uses copas for concurrent update processing. Each handler runs in its own coroutine. For the old sequential behaviour: + +```lua +api.run({ sync = true, timeout = 60 }) +``` + +### What doesn't need migration + +- Handler functions (`api.on_message`, `api.on_callback_query`, etc.) — same pattern +- Builder methods (`api.keyboard()`, `api.inline_keyboard()`, etc.) — same API +- Tool functions (`tools.escape_html`, `tools.comma_value`, etc.) — same API +- No config files, secrets, or environment variables to migrate + ## License This project is licensed under the GPL-3.0 License - see the LICENSE file for details. diff --git a/spec/compat_spec.lua b/spec/compat_spec.lua index 4f8091d..c3d518a 100644 --- a/spec/compat_spec.lua +++ b/spec/compat_spec.lua @@ -29,27 +29,153 @@ describe('legacy compatibility', function() end) end) - describe('positional arg wrappers', function() - it('send_message with positional parse_mode still works', function() - api.send_message(123, 'Hello', 'HTML') + --------------------------------------------------------------------------- + -- api.run() compat + --------------------------------------------------------------------------- + describe('api.run() positional args', function() + -- api.run() enters an infinite loop, so we test _run_sync directly + -- by verifying the compat wrapper calls through correctly. + -- We override _run_sync and async.run to capture the opts. + local captured_opts + + before_each(function() + captured_opts = nil + end) + + it('converts v2 positional args to opts table', function() + local original_sync = api._run_sync + local original_async_run = api.async.run + api._run_sync = function(opts) captured_opts = opts end + api.async.run = function(opts) captured_opts = opts end + api.run(10, 30, 5, {'message'}, true) + api._run_sync = original_sync + api.async.run = original_async_run + assert.is_table(captured_opts) + assert.equals(10, captured_opts.limit) + assert.equals(30, captured_opts.timeout) + assert.equals(5, captured_opts.offset) + assert.same({'message'}, captured_opts.allowed_updates) + assert.is_true(captured_opts.use_beta_endpoint) + end) + + it('passes v3 opts table through unchanged', function() + local original_sync = api._run_sync + local original_async_run = api.async.run + api._run_sync = function(opts) captured_opts = opts end + api.async.run = function(opts) captured_opts = opts end + api.run({ timeout = 60, sync = true }) + api._run_sync = original_sync + api.async.run = original_async_run + assert.is_table(captured_opts) + assert.equals(60, captured_opts.timeout) + assert.is_true(captured_opts.sync) + end) + end) + + --------------------------------------------------------------------------- + -- api.get_updates() compat + --------------------------------------------------------------------------- + describe('api.get_updates() positional args', function() + it('converts v2 positional args to opts table', function() + api.get_updates(30, 0, 100, {'message', 'callback_query'}) local req = api._last_request() - assert.truthy(req.endpoint:find('/sendMessage')) - assert.equals('HTML', req.parameters.parse_mode) + assert.truthy(req.endpoint:find('/getUpdates')) + assert.equals(30, tonumber(req.parameters.timeout)) + assert.equals(0, tonumber(req.parameters.offset)) + assert.equals(100, tonumber(req.parameters.limit)) end) - it('send_message with opts table works normally', function() + it('passes v3 opts table through unchanged', function() + api.get_updates({ timeout = 60, limit = 50 }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/getUpdates')) + assert.equals(60, tonumber(req.parameters.timeout)) + assert.equals(50, tonumber(req.parameters.limit)) + end) + + it('handles no args', function() + api.get_updates() + local req = api._last_request() + assert.truthy(req.endpoint:find('/getUpdates')) + end) + end) + + --------------------------------------------------------------------------- + -- api.set_webhook() compat + --------------------------------------------------------------------------- + describe('api.set_webhook() positional args', function() + it('converts v2 positional args to opts table', function() + api.set_webhook('https://example.com/hook', '/path/to/cert.pem', 40, {'message'}) + local req = api._last_request() + assert.truthy(req.endpoint:find('/setWebhook')) + assert.equals('https://example.com/hook', req.parameters.url) + assert.equals(40, tonumber(req.parameters.max_connections)) + end) + + it('passes v3 opts table through unchanged', function() + api.set_webhook('https://example.com/hook', { max_connections = 40 }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/setWebhook')) + assert.equals('https://example.com/hook', req.parameters.url) + assert.equals(40, tonumber(req.parameters.max_connections)) + end) + end) + + --------------------------------------------------------------------------- + -- api.send_message() compat + --------------------------------------------------------------------------- + describe('api.send_message() positional args', function() + it('v3 opts table works normally', function() api.send_message(123, 'Hello', { parse_mode = 'HTML' }) local req = api._last_request() assert.equals('HTML', req.parameters.parse_mode) end) - it('send_message with nil opts works', function() + it('v3 with nil opts works', function() api.send_message(123, 'Hello') local req = api._last_request() assert.equals('Hello', req.parameters.text) end) - it('answer_callback_query with positional text works', function() + it('v2 shorthand: parse_mode as 3rd arg (string)', function() + api.send_message(123, 'Hello', 'HTML') + local req = api._last_request() + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v2 shorthand: parse_mode as 3rd arg (boolean)', function() + api.send_message(123, 'Hello', true) + local req = api._last_request() + assert.equals('MarkdownV2', req.parameters.parse_mode) + end) + + it('v2 full positional: nil thread_id + parse_mode', function() + api.send_message(123, 'Hello', nil, 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendMessage')) + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v2 full positional: numeric thread_id + parse_mode', function() + api.send_message(123, 'Hello', 42, 'HTML') + local req = api._last_request() + assert.equals('HTML', req.parameters.parse_mode) + assert.equals(42, tonumber(req.parameters.message_thread_id)) + end) + + it('v2 full positional: all args', function() + api.send_message(123, 'Hello', nil, 'HTML', nil, nil, true, false, nil, nil) + local req = api._last_request() + assert.equals('HTML', req.parameters.parse_mode) + assert.is_true(req.parameters.disable_notification) + end) + end) + + --------------------------------------------------------------------------- + -- api.answer_callback_query() compat + --------------------------------------------------------------------------- + describe('api.answer_callback_query() positional args', function() + it('v2 positional text works', function() api.answer_callback_query('123', 'Alert text', true) local req = api._last_request() assert.truthy(req.endpoint:find('/answerCallbackQuery')) @@ -57,23 +183,176 @@ describe('legacy compatibility', function() assert.is_true(req.parameters.show_alert) end) - it('answer_callback_query with opts table works', function() + it('v3 opts table works', function() api.answer_callback_query('123', { text = 'Hello' }) local req = api._last_request() assert.equals('Hello', req.parameters.text) end) + end) - it('edit_message_text with positional parse_mode works', function() + --------------------------------------------------------------------------- + -- api.edit_message_text() compat + --------------------------------------------------------------------------- + describe('api.edit_message_text() positional args', function() + it('v2 positional parse_mode works', function() api.edit_message_text(123, 42, 'Updated', 'HTML') local req = api._last_request() assert.truthy(req.endpoint:find('/editMessageText')) assert.equals('HTML', req.parameters.parse_mode) end) - it('edit_message_text with opts table works', function() + it('v3 opts table works', function() api.edit_message_text(123, 42, 'Updated', { parse_mode = 'HTML' }) local req = api._last_request() assert.equals('HTML', req.parameters.parse_mode) end) end) + + --------------------------------------------------------------------------- + -- Media method compat + --------------------------------------------------------------------------- + describe('api.send_photo() positional args', function() + it('v3 opts table works', function() + api.send_photo(123, 'photo.jpg', { caption = 'Nice pic', parse_mode = 'HTML' }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendPhoto')) + assert.equals('Nice pic', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v2 positional: nil thread_id + caption + parse_mode', function() + api.send_photo(123, 'photo.jpg', nil, 'My caption', 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendPhoto')) + assert.equals('My caption', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v2 positional: numeric thread_id + caption', function() + api.send_photo(123, 'photo.jpg', 42, 'My caption') + local req = api._last_request() + assert.equals(42, tonumber(req.parameters.message_thread_id)) + assert.equals('My caption', req.parameters.caption) + end) + + it('v2 positional: has_spoiler flag', function() + api.send_photo(123, 'photo.jpg', nil, 'Caption', nil, nil, true) + local req = api._last_request() + assert.equals('Caption', req.parameters.caption) + assert.is_true(req.parameters.has_spoiler) + end) + + it('v3 no opts works', function() + api.send_photo(123, 'photo.jpg') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendPhoto')) + end) + end) + + describe('api.send_video() positional args', function() + it('v3 opts table works', function() + api.send_video(123, 'video.mp4', { caption = 'Cool vid', duration = 30 }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendVideo')) + assert.equals('Cool vid', req.parameters.caption) + assert.equals(30, tonumber(req.parameters.duration)) + end) + + it('v2 positional: duration + dimensions + caption', function() + api.send_video(123, 'video.mp4', nil, 30, 1920, 1080, 'Cool vid', 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendVideo')) + assert.equals(30, tonumber(req.parameters.duration)) + assert.equals(1920, tonumber(req.parameters.width)) + assert.equals(1080, tonumber(req.parameters.height)) + assert.equals('Cool vid', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v3 no opts works', function() + api.send_video(123, 'video.mp4') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendVideo')) + end) + end) + + describe('api.send_document() positional args', function() + it('v3 opts table works', function() + api.send_document(123, 'file.pdf', { caption = 'Read this' }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendDocument')) + assert.equals('Read this', req.parameters.caption) + end) + + it('v2 positional: thumbnail + caption + parse_mode', function() + api.send_document(123, 'file.pdf', nil, nil, 'Read this', 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendDocument')) + assert.equals('Read this', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + + it('v3 no opts works', function() + api.send_document(123, 'file.pdf') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendDocument')) + end) + end) + + describe('api.send_audio() positional args', function() + it('v3 opts table works', function() + api.send_audio(123, 'song.mp3', { caption = 'Great tune', duration = 180 }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendAudio')) + assert.equals('Great tune', req.parameters.caption) + end) + + it('v2 positional: caption + parse_mode + duration', function() + api.send_audio(123, 'song.mp3', nil, 'Great tune', 'HTML', nil, 180, 'Artist', 'Title') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendAudio')) + assert.equals('Great tune', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + assert.equals(180, tonumber(req.parameters.duration)) + assert.equals('Artist', req.parameters.performer) + assert.equals('Title', req.parameters.title) + end) + end) + + describe('api.send_voice() positional args', function() + it('v2 positional: caption + parse_mode', function() + api.send_voice(123, 'voice.ogg', nil, 'Listen', 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendVoice')) + assert.equals('Listen', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + end) + + describe('api.send_animation() positional args', function() + it('v2 positional: duration + dimensions + caption', function() + api.send_animation(123, 'anim.gif', nil, 5, 320, 240, nil, 'Funny gif', 'HTML') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendAnimation')) + assert.equals(5, tonumber(req.parameters.duration)) + assert.equals(320, tonumber(req.parameters.width)) + assert.equals(240, tonumber(req.parameters.height)) + assert.equals('Funny gif', req.parameters.caption) + assert.equals('HTML', req.parameters.parse_mode) + end) + end) + + describe('api.send_sticker() positional args', function() + it('v2 positional: thread_id + emoji', function() + api.send_sticker(123, 'sticker_id', nil, '😀') + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendSticker')) + end) + + it('v3 opts table works', function() + api.send_sticker(123, 'sticker_id', { emoji = '😀' }) + local req = api._last_request() + assert.truthy(req.endpoint:find('/sendSticker')) + end) + end) end) diff --git a/src/compat.lua b/src/compat.lua index bc2f8ba..e0c95be 100644 --- a/src/compat.lua +++ b/src/compat.lua @@ -1,5 +1,6 @@ -- Legacy compatibility layer for v2 -> v3 migration --- Provides deprecated method names and require('telegram-bot-lua.core') support +-- Provides deprecated method names, positional-arg wrappers, and +-- require('telegram-bot-lua.core') support so v2 code runs on v3. return function(api) local warned = {} local function deprecation_warning(old_name, new_name) @@ -12,6 +13,10 @@ return function(api) end end + --------------------------------------------------------------------------- + -- Renamed methods + --------------------------------------------------------------------------- + -- v2: get_chat_members_count -> v3: get_chat_member_count function api.get_chat_members_count(chat_id) deprecation_warning('get_chat_members_count', 'get_chat_member_count') @@ -24,48 +29,129 @@ return function(api) return api.ban_chat_member(chat_id, user_id, { until_date = until_date }) end - -- v2 positional-arg wrappers for commonly used methods + --------------------------------------------------------------------------- + -- api.run() — v2: run(limit, timeout, offset, allowed_updates, use_beta_endpoint) + --------------------------------------------------------------------------- + local v3_run = api.run + function api.run(opts_or_limit, ...) + if type(opts_or_limit) == 'number' then + deprecation_warning('run(limit, timeout, ...)', 'run(opts)') + local args = {...} + return v3_run({ + limit = opts_or_limit, + timeout = args[1], + offset = args[2], + allowed_updates = args[3], + use_beta_endpoint = args[4] + }) + end + return v3_run(opts_or_limit) + end + + --------------------------------------------------------------------------- + -- api.get_updates() — v2: get_updates(timeout, offset, limit, allowed_updates, use_beta_endpoint) + --------------------------------------------------------------------------- + local v3_get_updates = api.get_updates + function api.get_updates(opts_or_timeout, ...) + if type(opts_or_timeout) == 'number' then + deprecation_warning('get_updates(timeout, offset, ...)', 'get_updates(opts)') + local args = {...} + return v3_get_updates({ + timeout = opts_or_timeout, + offset = args[1], + limit = args[2], + allowed_updates = args[3], + use_beta_endpoint = args[4] + }) + end + return v3_get_updates(opts_or_timeout) + end + + --------------------------------------------------------------------------- + -- api.set_webhook() — v2: set_webhook(url, certificate, max_connections, allowed_updates) + --------------------------------------------------------------------------- + local v3_set_webhook = api.set_webhook + function api.set_webhook(url, opts_or_cert, ...) + if opts_or_cert ~= nil and type(opts_or_cert) ~= 'table' then + deprecation_warning('set_webhook(url, certificate, ...)', 'set_webhook(url, opts)') + local args = {...} + return v3_set_webhook(url, { + certificate = opts_or_cert, + max_connections = args[1], + allowed_updates = args[2] + }) + end + return v3_set_webhook(url, opts_or_cert) + end - -- v2: send_message(chat_id, text, parse_mode, disable_web_page_preview, disable_notification, reply_to_message_id, reply_markup) + --------------------------------------------------------------------------- + -- api.send_message() + -- v2: send_message(chat_id, text, message_thread_id, parse_mode, entities, + -- link_preview_options, disable_notification, protect_content, + -- reply_parameters, reply_markup) + -- v3: send_message(chat_id, text, opts) + --------------------------------------------------------------------------- local v3_send_message = api.send_message - function api.send_message(chat_id, text, opts_or_parse_mode, ...) - if type(opts_or_parse_mode) == 'string' or type(opts_or_parse_mode) == 'boolean' then + function api.send_message(chat_id, text, third, ...) + -- v3 style: opts table or nil with no trailing args + if type(third) == 'table' then + return v3_send_message(chat_id, text, third) + end + -- v2 shorthand: parse_mode as 3rd arg (e.g. send_message(id, text, 'HTML')) + if type(third) == 'string' or type(third) == 'boolean' then deprecation_warning('send_message(positional args)', 'send_message(chat_id, text, opts)') - local parse_mode = opts_or_parse_mode local args = {...} - local disable_web_page_preview = args[1] - local disable_notification = args[2] - local reply_to_message_id = args[3] - -- args[4..8] skipped (were nil placeholders) - local reply_markup = args[4] or args[5] or args[6] or args[7] or args[8] local link_preview_options - if disable_web_page_preview then - link_preview_options = { is_disabled = true } - end + if args[1] then link_preview_options = { is_disabled = true } end local reply_parameters - if reply_to_message_id then - reply_parameters = api.reply_parameters(reply_to_message_id) - end + if args[3] then reply_parameters = api.reply_parameters(args[3]) end return v3_send_message(chat_id, text, { + parse_mode = third, + link_preview_options = link_preview_options, + disable_notification = args[2], + reply_parameters = reply_parameters, + reply_markup = args[4] or args[5] or args[6] or args[7] or args[8] + }) + end + -- v2 full positional: 3rd arg is message_thread_id (number/nil) + more args + local nargs = select('#', ...) + if nargs > 0 or type(third) == 'number' then + deprecation_warning('send_message(positional args)', 'send_message(chat_id, text, opts)') + local args = {...} + local parse_mode = args[1] + local entities = args[2] + local link_preview_options = args[3] + local disable_notification = args[4] + local protect_content = args[5] + local reply_parameters = args[6] + local reply_markup = args[7] + return v3_send_message(chat_id, text, { + message_thread_id = third, parse_mode = parse_mode, + entities = entities, link_preview_options = link_preview_options, disable_notification = disable_notification, + protect_content = protect_content, reply_parameters = reply_parameters, reply_markup = reply_markup }) end - return v3_send_message(chat_id, text, opts_or_parse_mode) + -- v3 with nil opts + return v3_send_message(chat_id, text, third) end - -- v2: answer_callback_query(callback_query_id, text, show_alert, url, cache_time) + --------------------------------------------------------------------------- + -- api.answer_callback_query() + -- v2: answer_callback_query(id, text, show_alert, url, cache_time) + -- v3: answer_callback_query(id, opts) + --------------------------------------------------------------------------- local v3_answer_callback_query = api.answer_callback_query function api.answer_callback_query(callback_query_id, opts_or_text, ...) if type(opts_or_text) == 'string' then deprecation_warning('answer_callback_query(positional args)', 'answer_callback_query(id, opts)') - local text = opts_or_text local args = {...} return v3_answer_callback_query(callback_query_id, { - text = text, + text = opts_or_text, show_alert = args[1], url = args[2], cache_time = args[3] @@ -74,27 +160,209 @@ return function(api) return v3_answer_callback_query(callback_query_id, opts_or_text) end - -- v2: edit_message_text(chat_id, message_id, text, parse_mode, disable_web_page_preview, reply_markup, inline_message_id) + --------------------------------------------------------------------------- + -- api.edit_message_text() + -- v2: edit_message_text(chat_id, message_id, text, parse_mode, + -- disable_web_page_preview, reply_markup, inline_message_id) + -- v3: edit_message_text(chat_id, message_id, text, opts) + --------------------------------------------------------------------------- local v3_edit_message_text = api.edit_message_text function api.edit_message_text(chat_id, message_id, text, opts_or_parse_mode, ...) if type(opts_or_parse_mode) == 'string' or type(opts_or_parse_mode) == 'boolean' then deprecation_warning('edit_message_text(positional args)', 'edit_message_text(chat_id, message_id, text, opts)') local parse_mode = opts_or_parse_mode local args = {...} - local disable_web_page_preview = args[1] - local reply_markup = args[2] - local inline_message_id = args[3] local link_preview_options - if disable_web_page_preview then - link_preview_options = { is_disabled = true } - end + if args[1] then link_preview_options = { is_disabled = true } end return v3_edit_message_text(chat_id, message_id, text, { parse_mode = parse_mode, link_preview_options = link_preview_options, - reply_markup = reply_markup, - inline_message_id = inline_message_id + reply_markup = args[2], + inline_message_id = args[3] }) end return v3_edit_message_text(chat_id, message_id, text, opts_or_parse_mode) end + + --------------------------------------------------------------------------- + -- Media method shims + -- v2 pattern: send_X(chat_id, media, message_thread_id, ..., positional args) + -- v3 pattern: send_X(chat_id, media, opts) + -- Detection: if 3rd arg is not a table, it's v2 positional style. + --------------------------------------------------------------------------- + + -- api.send_photo() + -- v2: send_photo(chat_id, photo, message_thread_id, caption, parse_mode, + -- caption_entities, has_spoiler, disable_notification, protect_content, + -- reply_parameters, reply_markup) + local v3_send_photo = api.send_photo + function api.send_photo(chat_id, photo, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_photo(positional args)', 'send_photo(chat_id, photo, opts)') + local args = {...} + return v3_send_photo(chat_id, photo, { + message_thread_id = third, + caption = args[1], + parse_mode = args[2], + caption_entities = args[3], + has_spoiler = args[4], + disable_notification = args[5], + protect_content = args[6], + reply_parameters = args[7], + reply_markup = args[8] + }) + end + return v3_send_photo(chat_id, photo, third) + end + + -- api.send_audio() + -- v2: send_audio(chat_id, audio, message_thread_id, caption, parse_mode, + -- caption_entities, duration, performer, title, thumbnail, + -- disable_notification, protect_content, reply_parameters, reply_markup) + local v3_send_audio = api.send_audio + function api.send_audio(chat_id, audio, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_audio(positional args)', 'send_audio(chat_id, audio, opts)') + local args = {...} + return v3_send_audio(chat_id, audio, { + message_thread_id = third, + caption = args[1], + parse_mode = args[2], + caption_entities = args[3], + duration = args[4], + performer = args[5], + title = args[6], + thumbnail = args[7], + disable_notification = args[8], + protect_content = args[9], + reply_parameters = args[10], + reply_markup = args[11] + }) + end + return v3_send_audio(chat_id, audio, third) + end + + -- api.send_document() + -- v2: send_document(chat_id, document, message_thread_id, thumbnail, caption, + -- parse_mode, caption_entities, disable_content_type_detection, + -- disable_notification, protect_content, reply_parameters, reply_markup) + local v3_send_document = api.send_document + function api.send_document(chat_id, document, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_document(positional args)', 'send_document(chat_id, document, opts)') + local args = {...} + return v3_send_document(chat_id, document, { + message_thread_id = third, + thumbnail = args[1], + caption = args[2], + parse_mode = args[3], + caption_entities = args[4], + disable_content_type_detection = args[5], + disable_notification = args[6], + protect_content = args[7], + reply_parameters = args[8], + reply_markup = args[9] + }) + end + return v3_send_document(chat_id, document, third) + end + + -- api.send_video() + -- v2: send_video(chat_id, video, message_thread_id, duration, width, height, + -- caption, parse_mode, has_spoiler, supports_streaming, + -- disable_notification, protect_content, reply_parameters, reply_markup) + local v3_send_video = api.send_video + function api.send_video(chat_id, video, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_video(positional args)', 'send_video(chat_id, video, opts)') + local args = {...} + return v3_send_video(chat_id, video, { + message_thread_id = third, + duration = args[1], + width = args[2], + height = args[3], + caption = args[4], + parse_mode = args[5], + has_spoiler = args[6], + supports_streaming = args[7], + disable_notification = args[8], + protect_content = args[9], + reply_parameters = args[10], + reply_markup = args[11] + }) + end + return v3_send_video(chat_id, video, third) + end + + -- api.send_voice() + -- v2: send_voice(chat_id, voice, message_thread_id, caption, parse_mode, + -- caption_entities, duration, disable_notification, protect_content, + -- reply_parameters, reply_markup) + local v3_send_voice = api.send_voice + function api.send_voice(chat_id, voice, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_voice(positional args)', 'send_voice(chat_id, voice, opts)') + local args = {...} + return v3_send_voice(chat_id, voice, { + message_thread_id = third, + caption = args[1], + parse_mode = args[2], + caption_entities = args[3], + duration = args[4], + disable_notification = args[5], + protect_content = args[6], + reply_parameters = args[7], + reply_markup = args[8] + }) + end + return v3_send_voice(chat_id, voice, third) + end + + -- api.send_animation() + -- v2: send_animation(chat_id, animation, message_thread_id, duration, width, + -- height, thumbnail, caption, parse_mode, caption_entities, has_spoiler, + -- disable_notification, protect_content, reply_parameters, reply_markup) + local v3_send_animation = api.send_animation + function api.send_animation(chat_id, animation, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_animation(positional args)', 'send_animation(chat_id, animation, opts)') + local args = {...} + return v3_send_animation(chat_id, animation, { + message_thread_id = third, + duration = args[1], + width = args[2], + height = args[3], + thumbnail = args[4], + caption = args[5], + parse_mode = args[6], + caption_entities = args[7], + has_spoiler = args[8], + disable_notification = args[9], + protect_content = args[10], + reply_parameters = args[11], + reply_markup = args[12] + }) + end + return v3_send_animation(chat_id, animation, third) + end + + -- api.send_sticker() + -- v2: send_sticker(chat_id, sticker, message_thread_id, emoji, + -- disable_notification, protect_content, reply_parameters, reply_markup) + local v3_send_sticker = api.send_sticker + function api.send_sticker(chat_id, sticker, third, ...) + if type(third) ~= 'table' and (type(third) ~= 'nil' or select('#', ...) > 0) then + deprecation_warning('send_sticker(positional args)', 'send_sticker(chat_id, sticker, opts)') + local args = {...} + return v3_send_sticker(chat_id, sticker, { + message_thread_id = third, + emoji = args[1], + disable_notification = args[2], + protect_content = args[3], + reply_parameters = args[4], + reply_markup = args[5] + }) + end + return v3_send_sticker(chat_id, sticker, third) + end end