1
0
mirror of https://github.com/aNNiMON/ffmpegbot synced 2024-09-19 22:54:20 +03:00

Admin command to manage sessions

This commit is contained in:
aNNiMON 2023-10-21 18:29:08 +03:00
parent 856cd15358
commit 6e58de0049
8 changed files with 165 additions and 2 deletions

View File

@ -40,7 +40,7 @@ public class MainBotHandler extends BotHandler {
commands.registerBundle(mediaProcessingBundle); commands.registerBundle(mediaProcessingBundle);
commands.registerBundle(new InputParametersBundle(sessions)); commands.registerBundle(new InputParametersBundle(sessions));
commands.registerBundle(new YtDlpCommandBundle(sessions)); commands.registerBundle(new YtDlpCommandBundle(sessions));
commands.registerBundle(new AdminCommandBundle()); commands.registerBundle(new AdminCommandBundle(sessions));
commands.register(new HelpCommand()); commands.register(new HelpCommand());
} }

View File

@ -40,7 +40,7 @@ public class HelpCommand implements TextCommand {
<b>yt-dlp</b> <b>yt-dlp</b>
/dl link [format] download a media using yt-dlp /dl link [format] download a media using yt-dlp
<code>link</code> a link to download (it must be supported by yt-dlp) <code>link</code> a link to download (it must be supported by yt-dlp)
<code>format</code> (optional) a download format. Can be "audio", "240", "360", "480", "720" or "1080" <code>format</code> (optional) a download format. Can be "best", "audio", "240", "360", "480", "720" or "1080"
""".stripIndent()).enableHtml().callAsync(ctx.sender); """.stripIndent()).enableHtml().callAsync(ctx.sender);
} }
} }

View File

@ -1,5 +1,6 @@
package com.annimon.ffmpegbot.commands.admin; package com.annimon.ffmpegbot.commands.admin;
import com.annimon.ffmpegbot.session.Sessions;
import com.annimon.tgbotsmodule.commands.CommandBundle; import com.annimon.tgbotsmodule.commands.CommandBundle;
import com.annimon.tgbotsmodule.commands.CommandRegistry; import com.annimon.tgbotsmodule.commands.CommandRegistry;
import com.annimon.tgbotsmodule.commands.authority.For; import com.annimon.tgbotsmodule.commands.authority.For;
@ -7,9 +8,17 @@ import org.jetbrains.annotations.NotNull;
public class AdminCommandBundle implements CommandBundle<For> { public class AdminCommandBundle implements CommandBundle<For> {
private final Sessions sessions;
public AdminCommandBundle(Sessions sessions) {
this.sessions = sessions;
}
@Override @Override
public void register(@NotNull CommandRegistry commands) { public void register(@NotNull CommandRegistry commands) {
commands.register(new RunCommand()); commands.register(new RunCommand());
commands.register(new ClearCommand()); commands.register(new ClearCommand());
commands.register(new SessionsCommand(sessions));
commands.register(new SessionsClearCommand(sessions));
} }
} }

View File

@ -0,0 +1,38 @@
package com.annimon.ffmpegbot.commands.admin;
import com.annimon.ffmpegbot.Permissions;
import com.annimon.ffmpegbot.session.Sessions;
import com.annimon.tgbotsmodule.commands.CallbackQueryCommand;
import com.annimon.tgbotsmodule.commands.authority.For;
import com.annimon.tgbotsmodule.commands.context.CallbackQueryContext;
import org.jetbrains.annotations.NotNull;
import java.util.EnumSet;
public class SessionsClearCommand implements CallbackQueryCommand {
static final String CALLBACK_NAME = "sessions_clear";
private final Sessions sessions;
public SessionsClearCommand(Sessions sessions) {
this.sessions = sessions;
}
@Override
public String command() {
return CALLBACK_NAME;
}
@SuppressWarnings("unchecked")
@Override
public EnumSet<For> authority() {
return Permissions.SUPERUSERS;
}
@Override
public void accept(@NotNull CallbackQueryContext ctx) {
final int size = sessions.getSize();
sessions.clear();
ctx.editMessage("%d sessions cleared".formatted(size))
.setReplyMarkup(null)
.callAsync(ctx.sender);
}
}

View File

@ -0,0 +1,84 @@
package com.annimon.ffmpegbot.commands.admin;
import com.annimon.ffmpegbot.Permissions;
import com.annimon.ffmpegbot.TextUtils;
import com.annimon.ffmpegbot.session.MediaSession;
import com.annimon.ffmpegbot.session.Session;
import com.annimon.ffmpegbot.session.Sessions;
import com.annimon.ffmpegbot.session.YtDlpSession;
import com.annimon.tgbotsmodule.commands.TextCommand;
import com.annimon.tgbotsmodule.commands.authority.For;
import com.annimon.tgbotsmodule.commands.context.MessageContext;
import org.jetbrains.annotations.NotNull;
import org.telegram.telegrambots.meta.api.objects.replykeyboard.buttons.InlineKeyboardButton;
import java.util.Comparator;
import java.util.EnumSet;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
public class SessionsCommand implements TextCommand {
private final Sessions sessions;
public SessionsCommand(Sessions sessions) {
this.sessions = sessions;
}
@Override
public String command() {
return "/sessions";
}
@SuppressWarnings("unchecked")
@Override
public EnumSet<For> authority() {
return Permissions.SUPERUSERS;
}
@Override
public void accept(@NotNull MessageContext ctx) {
final int size = sessions.getSize();
if (size == 0) {
ctx.replyToMessage("No sessions found").callAsync(ctx.sender);
return;
}
if (ctx.argument(1).equals("clear")) {
sessions.clear();
ctx.replyToMessage("%d sessions cleared".formatted(size)).callAsync(ctx.sender);
} else {
final var sessionsInfo = sessions.sessions()
.sorted(Comparator.comparing(Session::getInstant).reversed())
.map(this::formatSession)
.limit(30)
.collect(Collectors.joining("\n"));
ctx.replyToMessage(("%d active sessions:\n%s").formatted(size, sessionsInfo))
.disableWebPagePreview()
.setSingleRowInlineKeyboard(InlineKeyboardButton.builder()
.text("Clear").callbackData(SessionsClearCommand.CALLBACK_NAME)
.build())
.callAsync(ctx.sender);
}
}
private String formatSession(Session session) {
long chatId = session.getChatId();
if (session instanceof MediaSession ms) {
return String.join(" ", str(chatId), str(ms.getOriginalFilename()),
str(ms.getFileSize(), TextUtils::readableFileSize),
str(ms.getDuration(), TextUtils::readableDuration));
} else if (session instanceof YtDlpSession ys) {
return String.join(" ", str(chatId), str(ys.getUrl()));
}
return str(chatId);
}
private String str(Object obj) {
return obj == null ? "" : Objects.toString(obj);
}
private <T> String str(T obj, Function<? super T, String> func) {
return obj == null ? "" : str(func.apply(obj));
}
}

View File

@ -54,14 +54,26 @@ public final class MediaSession extends Session {
this.originalFilename = originalFilename; this.originalFilename = originalFilename;
} }
public String getOriginalFilename() {
return originalFilename;
}
public void setFileSize(Long fileSize) { public void setFileSize(Long fileSize) {
this.fileSize = fileSize; this.fileSize = fileSize;
} }
public Long getFileSize() {
return fileSize;
}
public void setDuration(Integer duration) { public void setDuration(Integer duration) {
this.duration = duration; this.duration = duration;
} }
public Integer getDuration() {
return duration;
}
public void setResolution(Integer width, Integer height) { public void setResolution(Integer width, Integer height) {
if (width == null && height == null) { if (width == null && height == null) {
this.resolution = null; this.resolution = null;

View File

@ -2,6 +2,7 @@ package com.annimon.ffmpegbot.session;
import com.annimon.ffmpegbot.parameters.InputParameters; import com.annimon.ffmpegbot.parameters.InputParameters;
import java.time.Instant;
import java.util.StringJoiner; import java.util.StringJoiner;
public abstract sealed class Session permits MediaSession, YtDlpSession { public abstract sealed class Session permits MediaSession, YtDlpSession {
@ -10,6 +11,8 @@ public abstract sealed class Session permits MediaSession, YtDlpSession {
protected int messageId; protected int messageId;
// Parameters // Parameters
protected final InputParameters inputParams = new InputParameters(); protected final InputParameters inputParams = new InputParameters();
// Meta
private final Instant instant = Instant.now();
public long getChatId() { public long getChatId() {
return chatId; return chatId;
@ -31,5 +34,9 @@ public abstract sealed class Session permits MediaSession, YtDlpSession {
return inputParams; return inputParams;
} }
public Instant getInstant() {
return instant;
}
abstract StringJoiner describe(); abstract StringJoiner describe();
} }

View File

@ -2,6 +2,7 @@ package com.annimon.ffmpegbot.session;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Stream;
public class Sessions { public class Sessions {
private final Map<String, Session> sessions; private final Map<String, Session> sessions;
@ -10,6 +11,18 @@ public class Sessions {
sessions = new ConcurrentHashMap<>(); sessions = new ConcurrentHashMap<>();
} }
public void clear() {
sessions.clear();
}
public int getSize() {
return sessions.size();
}
public Stream<Session> sessions() {
return sessions.values().stream();
}
public Session get(long chatId, long messageId) { public Session get(long chatId, long messageId) {
return sessions.get(mapKey(chatId, messageId)); return sessions.get(mapKey(chatId, messageId));
} }