Skip to content

Commit 6a43a69

Browse files
authored
Merge pull request #28 from lsdrfrx/feature/voice-builder
feat: add TelegramEx.Builder.Voice
2 parents cda9a26 + 951047d commit 6a43a69

8 files changed

Lines changed: 144 additions & 7 deletions

File tree

example/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ A demo bot that showcases every feature of the [TelegramEx](https://github.com/l
1818
| `/document` | Document from local file |
1919
| `/sticker` | Sticker from local `.webp` file |
2020
| `/video` | Video from local file |
21+
| `/voice` | Voice message from local OGG/Opus file |
2122
| `/location` | Send geo coordinates (Paris) |
2223
| `/contact` | Send a contact card |
2324
| `/silent` | Silent message (no notification) |

example/assets/voice.ogg

37.7 KB
Binary file not shown.

example/lib/bot.ex

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@ defmodule Example.Bot do
1010
["/help", "/text", "/markdown"],
1111
["/html", "/keyboard", "/reply_kb"],
1212
["/photo", "/document", "/sticker"],
13-
["/video", "/location", "/contact"],
14-
["/silent", "/admin", "/survey"],
15-
["/poll", "/quiz"],
13+
["/video", "/voice", "/location"],
14+
["/contact", "/silent", "/admin"],
15+
["/survey", "/poll", "/quiz"],
1616
["/command_demo", "/echo hello"]
1717
]
1818

@@ -47,6 +47,7 @@ defmodule Example.Bot do
4747
/document — send a document (file)
4848
/sticker — send a sticker (file)
4949
/video — send a video (file)
50+
/voice — send a voice message (URL)
5051
5152
<b>Other</b>
5253
/location — send a location
@@ -187,6 +188,15 @@ defmodule Example.Bot do
187188
|> Video.send(chat["id"])
188189
end
189190

191+
# ── /voice ─────────────────────────────────────────────────────────
192+
# Voice message from local OGG/Opus file
193+
def handle_message(%{text: "/voice", chat: chat}, ctx) do
194+
ctx
195+
|> Voice.path("assets/voice.ogg")
196+
|> Voice.caption("Voice message sent with `sendVoice`", "Markdown")
197+
|> Voice.send(chat["id"])
198+
end
199+
190200
# ── /location ──────────────────────────────────────────────────────
191201
def handle_message(%{text: "/location", chat: chat}, ctx) do
192202
ctx

guides/messages-and-media.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,15 @@ ctx
139139
|> Video.send(chat_id)
140140
```
141141

142+
Voice message:
143+
144+
```elixir
145+
ctx
146+
|> Voice.path("/tmp/message.ogg")
147+
|> Voice.duration(12)
148+
|> Voice.send(chat_id)
149+
```
150+
142151
Poll:
143152

144153
```elixir

lib/builders/voice.ex

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
defmodule TelegramEx.Builder.Voice do
2+
@moduledoc """
3+
Builder for voice message payloads.
4+
5+
Supports Telegram file IDs, URLs, local files, captions, parse modes,
6+
duration, and silent sends. See [Messages and Media](messages-and-media.md).
7+
"""
8+
9+
alias TelegramEx.API
10+
alias TelegramEx.Builder
11+
alias TelegramEx.Effect
12+
13+
@type input :: map() | Effect.t()
14+
15+
@doc """
16+
Sets the voice message by Telegram file ID.
17+
"""
18+
@spec id(input(), String.t()) :: Effect.t()
19+
def id(input, id) do
20+
Builder.put_payload(input, :voice, id)
21+
end
22+
23+
@doc """
24+
Sets the voice message from a URL.
25+
"""
26+
@spec url(input(), String.t()) :: Effect.t()
27+
def url(input, url) do
28+
Builder.put_payload(input, :voice, url)
29+
end
30+
31+
@doc """
32+
Sets the voice message from a local file path.
33+
34+
If the file cannot be read, the returned effect contains `{:file, reason}`.
35+
"""
36+
@spec path(input(), String.t()) :: Effect.t()
37+
def path(input, path) do
38+
Builder.put_file_payload(input, :voice, path)
39+
end
40+
41+
@doc """
42+
Sets the voice message caption.
43+
"""
44+
@spec caption(input(), String.t()) :: Effect.t()
45+
def caption(input, caption) do
46+
Builder.put_payload(input, :caption, caption)
47+
end
48+
49+
@doc """
50+
Sets the voice message caption with parse mode.
51+
"""
52+
@spec caption(input(), String.t(), String.t()) :: Effect.t()
53+
def caption(input, caption, parse_mode) do
54+
input
55+
|> Builder.put_payload(:caption, caption)
56+
|> Builder.put_payload(:parse_mode, parse_mode)
57+
end
58+
59+
@doc """
60+
Sets the voice message duration in seconds.
61+
"""
62+
@spec duration(input(), integer()) :: Effect.t()
63+
def duration(input, seconds) do
64+
Builder.put_payload(input, :duration, seconds)
65+
end
66+
67+
@doc """
68+
Sends the voice message without notification sound.
69+
"""
70+
@spec silent(input()) :: Effect.t()
71+
def silent(input) do
72+
Builder.put_payload(input, :disable_notification, true)
73+
end
74+
75+
@doc """
76+
Sends the voice message to the specified chat.
77+
"""
78+
@spec send(input(), integer()) :: Effect.t()
79+
def send(input, id) do
80+
input
81+
|> Effect.wrap()
82+
|> Effect.then(fn ctx ->
83+
new_ctx =
84+
ctx
85+
|> Map.put(:chat_id, id)
86+
|> Map.put(:method, "sendVoice")
87+
|> Map.put(:format, :multipart)
88+
89+
case API.request(new_ctx) do
90+
:ok -> {:ok, new_ctx}
91+
{:error, reason} -> {:error, reason}
92+
end
93+
end)
94+
end
95+
end

lib/mime_type.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,8 @@ defmodule TelegramEx.MimeType do
22
@moduledoc """
33
Resolves MIME content types for local files based on their extension.
44
5-
This is used by the file-based builders (`Photo`, `Video`, `Sticker`,
6-
`Document`) so that uploaded media carries the correct `Content-Type`
5+
This is used by the file-based builders (`Photo`, `Video`, `Voice`,
6+
`Sticker`, `Document`) so that uploaded media carries the correct `Content-Type`
77
header instead of a hardcoded value.
88
"""
99

lib/router.ex

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,18 @@ defmodule TelegramEx.Router do
3030
import TelegramEx.FSM, only: [defstate: 2]
3131
import TelegramEx.Command, only: [defcommand: 3]
3232
alias TelegramEx.{API, Config, FSM}
33-
alias TelegramEx.Builder.{Contact, Document, Location, Message, Photo, Poll, Sticker, Video}
33+
34+
alias TelegramEx.Builder.{
35+
Contact,
36+
Document,
37+
Location,
38+
Message,
39+
Photo,
40+
Poll,
41+
Sticker,
42+
Video,
43+
Voice
44+
}
3445

3546
Module.register_attribute(__MODULE__, :commands, accumulate: true)
3647

lib/telegram_ex.ex

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,18 @@ defmodule TelegramEx do
7373
import TelegramEx.FSM, only: [defstate: 2]
7474
import TelegramEx.Command, only: [defcommand: 3]
7575
alias TelegramEx.{API, Config, FSM}
76-
alias TelegramEx.Builder.{Contact, Document, Location, Message, Photo, Poll, Sticker, Video}
76+
77+
alias TelegramEx.Builder.{
78+
Contact,
79+
Document,
80+
Location,
81+
Message,
82+
Photo,
83+
Poll,
84+
Sticker,
85+
Video,
86+
Voice
87+
}
7788

7889
@bot_name Keyword.fetch!(unquote(opts), :name)
7990
@routers Keyword.get(unquote(opts), :routers, [])

0 commit comments

Comments
 (0)