Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions Resources/texts.resx
Original file line number Diff line number Diff line change
Expand Up @@ -632,4 +632,13 @@ If you'd like to get access, you can contact <a href="{0}">me here</a&g
<data name="MessageProcessMediaSend" xml:space="preserve">
<value>The mailing list is over. Sent {0}/{1}</value>
</data>
<data name="CancelButtonText" xml:space="preserve">
<value>Cancel</value>
</data>
<data name="SessionExpiredMessage" xml:space="preserve">
<value>Session expired. Please send the link again.</value>
</data>
<data name="CancelledMessage" xml:space="preserve">
<value>Cancelled</value>
</data>
</root>
9 changes: 9 additions & 0 deletions Resources/texts.ru-RU.resx
Original file line number Diff line number Diff line change
Expand Up @@ -676,4 +676,13 @@ PS: квадратные скобки не нужны :)</value>
<data name="MessageProcessMediaSend" xml:space="preserve">
<value>Рассылка окончена. Отправлено {0}/{1}</value>
</data>
<data name="CancelButtonText" xml:space="preserve">
<value>Отмена</value>
</data>
<data name="SessionExpiredMessage" xml:space="preserve">
<value>Сессия истекла. Отправьте ссылку заново.</value>
</data>
<data name="CancelledMessage" xml:space="preserve">
<value>Отменено</value>
</data>
</root>
8 changes: 8 additions & 0 deletions TelegramBot/Handlers/ICallBackQuery/CallbackNames.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,12 @@ public static class CallbackNames
public const string UserSetAutoSendVideoTimeTo = "user_set_auto_send_video_time_to:";
public const string UserSetVideoSendUsersParameterized = "user_set_video_send_users:";
public const string UserSetSiteStopList = "user_set_site_stop_list:";

// Media session parameterized callbacks
public const string SendToAllContactsSession = "send_to_all_contacts:";
public const string SendToDefaultGroupsSession = "send_to_default_groups:";
public const string SendToSpecifiedGroupsSession = "send_to_specified_groups:";
public const string SendToSpecifiedUsersSession = "send_to_specified_users:";
public const string SendOnlyToMeSession = "send_only_to_me:";
public const string CancelMediaSession = "cancel_media:";
}
312 changes: 312 additions & 0 deletions TelegramBot/Handlers/ICallBackQuery/IMediaSessionCallbackQuery.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,312 @@
// Copyright (C) 2024-2025 ZenonEl
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.


using TelegramMediaRelayBot.TelegramBot.Sessions;
using TelegramMediaRelayBot.Database;
using TelegramMediaRelayBot.Database.Interfaces;

namespace TelegramMediaRelayBot.TelegramBot.Handlers.ICallBackQuery;


public class SendToAllContactsSessionCommand : IBotCallbackQueryHandlers
{
private readonly TGBot _tgBot;
private readonly IContactGetter _contactGetterRepository;
private readonly IUserGetter _userGetter;

public SendToAllContactsSessionCommand(
TGBot tgBot,
IContactGetter contactGetterRepository,
IUserGetter userGetter)
{
_tgBot = tgBot;
_contactGetterRepository = contactGetterRepository;
_userGetter = userGetter;
}

public string Name => "send_to_all_contacts:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

// Cancel default action timeout
try { session.Cts.Cancel(); } catch (ObjectDisposedException) { }

long chatId = session.ChatId;
int userId = _userGetter.GetUserIDbyTelegramID(chatId);
List<long> mutedByUserIds = _userGetter.GetUsersIdForMuteContactId(userId);
List<long> contactUserTGIds = await _contactGetterRepository.GetAllContactUserTGIds(userId);
List<long> targetUserIds = contactUserTGIds.Except(mutedByUserIds).ToList();

int messageId = int.Parse(sessionId);
var statusMessage = update.CallbackQuery!.Message!;

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("WaitDownloadingVideo"),
cancellationToken: ct
);

_ = _tgBot.HandleMediaRequest(botClient, session.Url, chatId, statusMessage, targetUserIds, caption: session.Caption ?? "");
}
}

public class SendToDefaultGroupsSessionCommand : IBotCallbackQueryHandlers
{
private readonly TGBot _tgBot;
private readonly IUserGetter _userGetter;
private readonly IGroupGetter _groupGetter;

public SendToDefaultGroupsSessionCommand(
TGBot tgBot,
IUserGetter userGetter,
IGroupGetter groupGetter)
{
_tgBot = tgBot;
_userGetter = userGetter;
_groupGetter = groupGetter;
}

public string Name => "send_to_default_groups:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

try { session.Cts.Cancel(); } catch (ObjectDisposedException) { }

long chatId = session.ChatId;
int userId = _userGetter.GetUserIDbyTelegramID(chatId);
List<long> mutedByUserIds = _userGetter.GetUsersIdForMuteContactId(userId);
List<int> userIds = await _groupGetter.GetAllUsersInDefaultEnabledGroups(userId);

List<long> targetUserIds = userIds
.Where(contactId => !mutedByUserIds.Contains(_userGetter.GetTelegramIDbyUserID(contactId)))
.Select(_userGetter.GetTelegramIDbyUserID)
.ToList();

int messageId = int.Parse(sessionId);
var statusMessage = update.CallbackQuery!.Message!;

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("WaitDownloadingVideo"),
cancellationToken: ct
);

_ = _tgBot.HandleMediaRequest(botClient, session.Url, chatId, statusMessage, targetUserIds, caption: session.Caption ?? "");
}
}

public class SendOnlyToMeSessionCommand : IBotCallbackQueryHandlers
{
private readonly TGBot _tgBot;

public SendOnlyToMeSessionCommand(TGBot tgBot)
{
_tgBot = tgBot;
}

public string Name => "send_only_to_me:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

try { session.Cts.Cancel(); } catch (ObjectDisposedException) { }

long chatId = session.ChatId;
int messageId = int.Parse(sessionId);
var statusMessage = update.CallbackQuery!.Message!;

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("WaitDownloadingVideo"),
cancellationToken: ct
);

_ = _tgBot.HandleMediaRequest(botClient, session.Url, chatId, statusMessage, caption: session.Caption ?? "");
}
}

public class SendToSpecifiedGroupsSessionCommand : IBotCallbackQueryHandlers
{
private readonly TGBot _tgBot;
private readonly IUserGetter _userGetter;
private readonly IGroupGetter _groupGetter;
private readonly IDefaultActionGetter _defaultActionGetter;

public SendToSpecifiedGroupsSessionCommand(
TGBot tgBot,
IUserGetter userGetter,
IGroupGetter groupGetter,
IDefaultActionGetter defaultActionGetter)
{
_tgBot = tgBot;
_userGetter = userGetter;
_groupGetter = groupGetter;
_defaultActionGetter = defaultActionGetter;
}

public string Name => "send_to_specified_groups:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

try { session.Cts.Cancel(); } catch (ObjectDisposedException) { }

long chatId = session.ChatId;
int userId = _userGetter.GetUserIDbyTelegramID(chatId);
List<long> mutedByUserIds = _userGetter.GetUsersIdForMuteContactId(userId);
int actionId = _defaultActionGetter.GetDefaultActionId(userId, UsersActionTypes.DEFAULT_MEDIA_DISTRIBUTION);
List<int> groupIds = _defaultActionGetter.GetAllDefaultUsersActionTargets(userId, TargetTypes.GROUP, actionId);
List<int> userIds = new List<int>();

foreach (int groupId in groupIds)
{
userIds.AddRange(await _groupGetter.GetAllUsersIdsInGroup(groupId));
}

List<long> targetUserIds = userIds
.Where(contactId => !mutedByUserIds.Contains(_userGetter.GetTelegramIDbyUserID(contactId)))
.Select(_userGetter.GetTelegramIDbyUserID)
.ToList();

int messageId = int.Parse(sessionId);
var statusMessage = update.CallbackQuery!.Message!;

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("WaitDownloadingVideo"),
cancellationToken: ct
);

_ = _tgBot.HandleMediaRequest(botClient, session.Url, chatId, statusMessage, targetUserIds, caption: session.Caption ?? "");
}
}

public class SendToSpecifiedUsersSessionCommand : IBotCallbackQueryHandlers
{
private readonly TGBot _tgBot;
private readonly IUserGetter _userGetter;
private readonly IDefaultActionGetter _defaultActionGetter;

public SendToSpecifiedUsersSessionCommand(
TGBot tgBot,
IUserGetter userGetter,
IDefaultActionGetter defaultActionGetter)
{
_tgBot = tgBot;
_userGetter = userGetter;
_defaultActionGetter = defaultActionGetter;
}

public string Name => "send_to_specified_users:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

try { session.Cts.Cancel(); } catch (ObjectDisposedException) { }

long chatId = session.ChatId;
int userId = _userGetter.GetUserIDbyTelegramID(chatId);
List<long> mutedByUserIds = _userGetter.GetUsersIdForMuteContactId(userId);
int actionId = _defaultActionGetter.GetDefaultActionId(userId, UsersActionTypes.DEFAULT_MEDIA_DISTRIBUTION);
List<int> userIds = _defaultActionGetter.GetAllDefaultUsersActionTargets(userId, TargetTypes.USER, actionId);

List<long> targetUserIds = userIds
.Where(contactId => !mutedByUserIds.Contains(_userGetter.GetTelegramIDbyUserID(contactId)))
.Select(_userGetter.GetTelegramIDbyUserID)
.ToList();

int messageId = int.Parse(sessionId);
var statusMessage = update.CallbackQuery!.Message!;

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("WaitDownloadingVideo"),
cancellationToken: ct
);

_ = _tgBot.HandleMediaRequest(botClient, session.Url, chatId, statusMessage, targetUserIds, caption: session.Caption ?? "");
}
}

public class CancelMediaSessionCommand : IBotCallbackQueryHandlers
{
public string Name => "cancel_media:";

public async Task ExecuteAsync(Update update, ITelegramBotClient botClient, CancellationToken ct)
{
string sessionId = update.CallbackQuery!.Data!.Split(':')[1];
if (!MediaSessionManager.TryGet(sessionId, out var session) || session == null)
{
await botClient.AnswerCallbackQuery(update.CallbackQuery.Id, Config.GetResourceString("SessionExpiredMessage"), showAlert: true);
return;
}

long chatId = session.ChatId;
int messageId = int.Parse(sessionId);

MediaSessionManager.Remove(sessionId);

await botClient.EditMessageText(
chatId,
messageId,
Config.GetResourceString("CancelledMessage"),
cancellationToken: ct
);
}
}
12 changes: 7 additions & 5 deletions TelegramBot/Handlers/PrivateUpdateHandler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@


using TelegramMediaRelayBot.TelegramBot.Utils;
using TelegramMediaRelayBot.TelegramBot.Sessions;
using TelegramMediaRelayBot.Database;
using TelegramMediaRelayBot.Database.Interfaces;

Expand Down Expand Up @@ -71,20 +72,21 @@ public async Task ProcessMessage(ITelegramBotClient botClient, Update update, Ca
cancellationToken: cancellationToken
);

string sessionId = statusMessage.MessageId.ToString();
string? caption = string.IsNullOrWhiteSpace(text) ? null : text;
MediaSessionManager.Create(sessionId, chatId, link, caption);

await botClient.EditMessageText(
statusMessage.Chat.Id,
statusMessage.MessageId,
Config.GetResourceString("VideoDistributionQuestion"),
replyMarkup: KeyboardUtils.GetVideoDistributionKeyboardMarkup(),
replyMarkup: KeyboardUtils.GetVideoDistributionKeyboardMarkup(sessionId),
cancellationToken: cancellationToken
);

int userId = _userGetter.GetUserIDbyTelegramID(chatId);
string defaultActionData = _defaultActionGetter.GetDefaultActionByUserIDAndType(userId, UsersActionTypes.DEFAULT_MEDIA_DISTRIBUTION);

CancellationTokenSource timeoutCTS = new CancellationTokenSource();
UserSessionManager.Set(chatId, new ProcessVideoDC(link, statusMessage, text, timeoutCTS, _tgBot, _contactGetterRepository, _userGetter, _groupGetter));

if (defaultActionData == UsersAction.NO_VALUE) return;

string defaultAction = defaultActionData.Split(';')[0];
Expand All @@ -93,7 +95,7 @@ await botClient.EditMessageText(
if (defaultAction == UsersAction.OFF) return;
var privateUtils = new PrivateUtils(_tgBot, _contactGetterRepository, _defaultActionGetter, _userGetter, _groupGetter);
privateUtils.ProcessDefaultSendAction(botClient, chatId, statusMessage, defaultAction, cancellationToken,
userId, defaultCondition, timeoutCTS, link, text);
userId, defaultCondition, sessionId, link, text);
}
else if (update.Message.Text == "/start")
{
Expand Down
Loading
Loading