Skip to content

Commit 56342f8

Browse files
committed
- documents attach for vk and telegram
- sample
1 parent 6cc1f8b commit 56342f8

File tree

18 files changed

+208
-53
lines changed

18 files changed

+208
-53
lines changed

Botticelli.Framework.Telegram/TelegramBot.cs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,15 @@ await _client.SendStickerAsync(chatId,
239239
await SendContact(request, token, replyMarkup);
240240

241241
break;
242+
case MediaType.Document:
243+
var doc = new InputOnlineFile(attachment.Data.ToStream(), attachment.Name);
244+
await _client.SendDocumentAsync(chatId,
245+
doc,
246+
replyToMessageId: request.Message.ReplyToMessageUid != default ? int.Parse(request.Message.ReplyToMessageUid) : default,
247+
replyMarkup: replyMarkup,
248+
cancellationToken: token
249+
);
250+
break;
242251
case MediaType.Unknown:
243252
case MediaType.Poll:
244253
case MediaType.Text:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Botticelli.Framework.Vk.Messages.API.Responses;
4+
5+
public class AudioMessage
6+
{
7+
[JsonPropertyName("duration")]
8+
public int Duration { get; set; }
9+
10+
[JsonPropertyName("id")]
11+
public int Id { get; set; }
12+
13+
[JsonPropertyName("link_mp3")]
14+
public string LinkMp3 { get; set; }
15+
16+
[JsonPropertyName("link_ogg")]
17+
public string LinkOgg { get; set; }
18+
19+
[JsonPropertyName("owner_id")]
20+
public int OwnerId { get; set; }
21+
22+
[JsonPropertyName("access_key")]
23+
public string AccessKey { get; set; }
24+
25+
[JsonPropertyName("waveform")]
26+
public List<int> Waveform { get; set; }
27+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Botticelli.Framework.Vk.Messages.API.Responses;
4+
5+
public class AudioResponseData
6+
{
7+
[JsonPropertyName("type")]
8+
public string Type { get; set; }
9+
10+
[JsonPropertyName("audio_message")]
11+
public AudioMessage AudioMessage { get; set; }
12+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Botticelli.Framework.Vk.Messages.API.Responses;
4+
5+
public class Document
6+
{
7+
[JsonPropertyName("id")]
8+
public int Id { get; set; }
9+
10+
[JsonPropertyName("owner_id")]
11+
public int OwnerId { get; set; }
12+
13+
[JsonPropertyName("title")]
14+
public string Title { get; set; }
15+
16+
[JsonPropertyName("size")]
17+
public int Size { get; set; }
18+
19+
[JsonPropertyName("ext")]
20+
public string Ext { get; set; }
21+
22+
[JsonPropertyName("date")]
23+
public int Date { get; set; }
24+
25+
[JsonPropertyName("type")]
26+
public int Type { get; set; }
27+
28+
[JsonPropertyName("url")]
29+
public string Url { get; set; }
30+
31+
[JsonPropertyName("is_unsafe")]
32+
public int IsUnsafe { get; set; }
33+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Botticelli.Framework.Vk.Messages.API.Responses;
4+
5+
public class DocumentResponseData
6+
{
7+
[JsonPropertyName("type")]
8+
public string Type { get; set; }
9+
10+
[JsonPropertyName("doc")]
11+
public Document Document { get; set; }
12+
}

Botticelli.Framework.Vk/API/Responses/GetUploadAddressResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
namespace Botticelli.Framework.Vk.Messages.API.Responses;
44

5-
// Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse);
5+
// VkSendDocumentResponse myDeserializedClass = JsonSerializer.Deserialize<VkSendDocumentResponse>(myJsonResponse);
66
public class GetUploadAddressResponse
77
{
88
[JsonPropertyName("album_id")]

Botticelli.Framework.Vk/API/Responses/VkSendAudioResponse.cs

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,4 @@ public class VkSendAudioResponse
66
{
77
[JsonPropertyName("response")]
88
public AudioResponseData AudioResponseData { get; set; }
9-
}
10-
11-
12-
13-
// Root myDeserializedClass = JsonSerializer.Deserialize<Root>(myJsonResponse);
14-
public class AudioMessage
15-
{
16-
[JsonPropertyName("duration")]
17-
public int Duration { get; set; }
18-
19-
[JsonPropertyName("id")]
20-
public int Id { get; set; }
21-
22-
[JsonPropertyName("link_mp3")]
23-
public string LinkMp3 { get; set; }
24-
25-
[JsonPropertyName("link_ogg")]
26-
public string LinkOgg { get; set; }
27-
28-
[JsonPropertyName("owner_id")]
29-
public int OwnerId { get; set; }
30-
31-
[JsonPropertyName("access_key")]
32-
public string AccessKey { get; set; }
33-
34-
[JsonPropertyName("waveform")]
35-
public List<int> Waveform { get; set; }
36-
}
37-
38-
public class AudioResponseData
39-
{
40-
[JsonPropertyName("type")]
41-
public string Type { get; set; }
42-
43-
[JsonPropertyName("audio_message")]
44-
public AudioMessage AudioMessage { get; set; }
45-
}
9+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
using System.Text.Json.Serialization;
2+
3+
namespace Botticelli.Framework.Vk.Messages.API.Responses;
4+
5+
public class VkSendDocumentResponse
6+
{
7+
[JsonPropertyName("response")]
8+
public DocumentResponseData DocumentResponseData { get; set; }
9+
}

Botticelli.Framework.Vk/VkBot.cs

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -122,23 +122,29 @@ private void SetApiKey(BotContext context)
122122
_vkUploader.SetApiKey(context.BotKey);
123123
}
124124

125-
private string CreateVkAttach(VkSendPhotoResponse fk, BotContext currentContext, string type)
125+
private string CreateVkAttach(VkSendPhotoResponse fk, string type)
126126
=> $"{type}" +
127127
$"{fk.Response?.FirstOrDefault()?.OwnerId.ToString()}" +
128128
$"_{fk.Response?.FirstOrDefault()?.Id.ToString()}";
129129

130130

131-
private string CreateVkAttach(VkSendVideoResponse fk, BotContext currentContext, string type)
131+
private string CreateVkAttach(VkSendVideoResponse fk, string type)
132132
=> $"{type}" +
133133
$"{fk.Response?.OwnerId.ToString()}" +
134134
$"_{fk.Response?.VideoId.ToString()}";
135135

136136

137137

138-
private string CreateVkAttach(VkSendAudioResponse fk, BotContext currentContext, string type)
138+
private string CreateVkAttach(VkSendAudioResponse fk, string type)
139139
=> $"{type}" +
140-
$"{fk.AudioResponseData.AudioMessage.OwnerId.ToString()}" +
141-
$"_{fk.AudioResponseData.AudioMessage.Id.ToString()}";
140+
$"{fk.AudioResponseData.AudioMessage.OwnerId}" +
141+
$"_{fk.AudioResponseData.AudioMessage.Id}";
142+
143+
private string CreateVkAttach(VkSendDocumentResponse fk, string type)
144+
=> $"{type}" +
145+
$"{fk.DocumentResponseData.Document.OwnerId}" +
146+
$"_{fk.DocumentResponseData.Document.Id}";
147+
142148

143149
public override async Task<SendMessageResponse> SendMessageAsync<TSendOptions>(SendMessageRequest request,
144150
ISendOptionsBuilder<TSendOptions> optionsBuilder,
@@ -213,7 +219,7 @@ private async Task<IEnumerable<VkSendMessageRequest>> CreateRequestsWithAttachme
213219
ba.Name,
214220
ba.Data,
215221
token);
216-
if (sendPhotoResponse != default) vkRequest.Attachment = CreateVkAttach(sendPhotoResponse, currentContext, "photo");
222+
if (sendPhotoResponse != default) vkRequest.Attachment = CreateVkAttach(sendPhotoResponse, "photo");
217223

218224
break;
219225
case {MediaType: MediaType.Video}:
@@ -231,11 +237,20 @@ private async Task<IEnumerable<VkSendMessageRequest>> CreateRequestsWithAttachme
231237
ba.Name,
232238
ba.Data,
233239
token);
234-
if (sendAudioMessageResponse != default) vkRequest.Attachment = CreateVkAttach(sendAudioMessageResponse, currentContext, "doc");
240+
if (sendAudioMessageResponse != default) vkRequest.Attachment = CreateVkAttach(sendAudioMessageResponse, "doc");
235241

236242

237243
break;
238-
}
244+
case { MediaType: MediaType.Document }:
245+
var sendDocMessageResponse = await _vkUploader.SendDocsMessageAsync(vkRequest,
246+
ba.Name,
247+
ba.Data,
248+
token);
249+
if (sendDocMessageResponse != default) vkRequest.Attachment = CreateVkAttach(sendDocMessageResponse, "doc");
250+
251+
252+
break;
253+
}
239254
}
240255

241256
break;

Botticelli.Framework.Vk/VkStorageUploader.cs

Lines changed: 61 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -171,29 +171,45 @@ private async Task<UploadPhotoResult> UploadPhoto(string uploadUrl, string name,
171171
/// <returns></returns>
172172
private async Task<UploadDocResult> UploadAudioMessage(string uploadUrl, string name, byte[] binaryContent, CancellationToken token)
173173
{
174-
using var httpClient = _httpClientFactory.CreateClient();
175174
// convert to ogg in order to meet VK requirements
176175
var oggContent = _audioConvertor.Convert(binaryContent, new AudioInfo()
177176
{
178177
AudioFormat = AudioFormat.Ogg,
179178
Bitrate = 16000
180179
});
181180

181+
return await PushDocument<UploadDocResult>(uploadUrl, name, oggContent, token);
182+
}
183+
184+
private async Task<TResult> PushDocument<TResult>(string uploadUrl, string name, byte[] binContent,
185+
CancellationToken token)
186+
{
187+
using var httpClient = _httpClientFactory.CreateClient();
182188
var content = new MultipartFormDataContent
183189
{
184190
{
185-
new ByteArrayContent(oggContent, 0, oggContent.Length),
191+
new ByteArrayContent(binContent, 0, binContent.Length),
186192
"file",
187-
$"{name}{Guid.NewGuid()}.ogg"
193+
$"{Path.GetFileNameWithoutExtension(name)}{Guid.NewGuid()}.{Path.GetExtension(name)}"
188194
}
189195
};
190196

191197
var response = await httpClient.PostAsync(uploadUrl, content, token);
192198
var resultString = await response.Content.ReadAsStringAsync();
193199

194-
return JsonSerializer.Deserialize<UploadDocResult>(resultString);
200+
return JsonSerializer.Deserialize<TResult>(resultString);
195201
}
196202

203+
/// <summary>
204+
/// Uploads a document message (binaries)
205+
/// </summary>
206+
/// <param name="uploadUrl"></param>
207+
/// <param name="binaryContent"></param>
208+
/// <param name="token"></param>
209+
/// <returns></returns>
210+
private async Task<UploadDocResult> UploadDocMessage(string uploadUrl, string name, byte[] binaryContent, CancellationToken token)
211+
=> await PushDocument<UploadDocResult>(uploadUrl, name, binaryContent, token);
212+
197213
/// <summary>
198214
/// Uploads a video (binaries)
199215
/// </summary>
@@ -316,6 +332,47 @@ public async Task<VkSendAudioResponse> SendAudioMessageAsync(VkSendMessageReques
316332
}
317333

318334

335+
public async Task<VkSendDocumentResponse> SendDocsMessageAsync(VkSendMessageRequest vkMessageRequest, string name, byte[] binaryContent, CancellationToken token)
336+
{
337+
try
338+
{
339+
var address = await GetDocsUploadAddress(vkMessageRequest, "doc", token);
340+
341+
if (address?.Response == default) throw new BotException("Sending doc error: no upload server address!");
342+
343+
var uploadedDoc = await UploadDocMessage(address.Response.UploadUrl, name, binaryContent, token);
344+
345+
if (uploadedDoc?.File == default) throw new BotException("Sending doc error: no file uploaded!");
346+
347+
using var httpClient = _httpClientFactory.CreateClient();
348+
var request = new HttpRequestMessage(HttpMethod.Post,
349+
ApiUtils.GetMethodUri("https://api.vk.com",
350+
"docs.save",
351+
new
352+
{
353+
file = uploadedDoc.File,
354+
access_token = _apiKey,
355+
v = ApiVersion
356+
}));
357+
request.Content = ApiUtils.GetMethodMultipartFormContent(new
358+
{
359+
doc = uploadedDoc.File
360+
},
361+
snakeCase: true);
362+
363+
var response = await httpClient.SendAsync(request, token);
364+
var resultString = await response.Content.ReadAsStringAsync();
365+
366+
return JsonSerializer.Deserialize<VkSendDocumentResponse>(resultString);
367+
}
368+
catch (Exception ex)
369+
{
370+
_logger.LogError(ex, "Error uploading media");
371+
}
372+
373+
return default;
374+
}
375+
319376
/// <summary>
320377
/// The main public method for sending a video
321378
/// seems to be prohibited for bots in communities

0 commit comments

Comments
 (0)