From e03bb0fb7fc0fb696a310c98b3a079de8d69ed31 Mon Sep 17 00:00:00 2001
From: jarvis2f <137974272+jarvis2f@users.noreply.github.com>
Date: Mon, 17 Feb 2025 11:45:38 +0800
Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=91=EF=B8=8F=20fix:=20Add=20maintenanc?=
=?UTF-8?q?e=20program=20to=20support=20the=20fix=20for=20missing=20album?=
=?UTF-8?q?=20message=20caption.?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
Dockerfile | 4 +-
README.md | 21 ++
.../telegram/files/AutoDownloadVerticle.java | 11 +-
.../telegram/files/AutoRecordsHolder.java | 4 +-
api/src/main/java/telegram/files/Config.java | 5 +
.../main/java/telegram/files/EventEnum.java | 6 +
.../java/telegram/files/HttpVerticle.java | 187 ++++++------------
.../main/java/telegram/files/Maintain.java | 63 ++++++
api/src/main/java/telegram/files/Start.java | 2 +-
.../main/java/telegram/files/TdApiHelp.java | 4 +
.../telegram/files/TelegramVerticles.java | 95 +++++++++
.../AlbumCaptionMaintainVerticle.java | 141 +++++++++++++
.../files/maintains/MaintainVerticle.java | 14 ++
.../telegram/files/repository/FileRecord.java | 9 +-
.../files/repository/FileRepository.java | 4 +
.../repository/impl/FileRepositoryImpl.java | 54 ++++-
.../telegram/files/AutoRecordsHolderTest.java | 8 +-
.../java/telegram/files/DataVerticleTest.java | 6 +-
.../FileDownloadStatusConcurrentTest.java | 2 +-
19 files changed, 484 insertions(+), 156 deletions(-)
create mode 100644 api/src/main/java/telegram/files/Maintain.java
create mode 100644 api/src/main/java/telegram/files/TelegramVerticles.java
create mode 100644 api/src/main/java/telegram/files/maintains/AlbumCaptionMaintainVerticle.java
create mode 100644 api/src/main/java/telegram/files/maintains/MaintainVerticle.java
diff --git a/Dockerfile b/Dockerfile
index 2694b80..8944580 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -77,7 +77,9 @@ RUN npm install -g pm2 && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* ./libs.zip && \
touch /run/nginx.pid && \
- chown -R 1000:1000 /app /etc/nginx /var/lib/nginx /var/log/nginx /run/nginx.pid
+ chown -R 1000:1000 /app /etc/nginx /var/lib/nginx /var/log/nginx /run/nginx.pid && \
+ echo '#!/bin/sh\njava -Djava.library.path=/app/tdlib -cp /app/api.jar telegram.files.Maintain "$@"' > /usr/bin/tfm && \
+ chmod +x /usr/bin/tfm
COPY --from=runtime-builder --chown=1000:1000 /custom-jre/jre /jre
COPY --from=api-builder --chown=1000:1000 /app/api.jar /app/api.jar
diff --git a/README.md b/README.md
index a2f485b..9e6d3cf 100644
--- a/README.md
+++ b/README.md
@@ -222,3 +222,24 @@ manually.~~
Open the `chrome://flags` page, search for `Insecure origins treated as secure`, and add the address of the web page to
the list.
+
+**Q.** How to use the telegram-files maintenance tool?
+
+**A.** You can use the following command to run the maintenance tool(**before running the command, you should stop telegram-files container**):
+
+Command
+
+```shell
+docker run --rm \
+ --entrypoint /bin/bash \
+ -v $(pwd)/data:/app/data \
+ -e APP_ROOT=${APP_ROOT:-/app/data} \
+ -e TELEGRAM_API_ID=${TELEGRAM_API_ID} \
+ -e TELEGRAM_API_HASH=${TELEGRAM_API_HASH} \
+ ghcr.io/jarvis2f/telegram-files:latest tfm ${Maintenance Command}
+```
+
+**Maintenance Command:**
+
+- `album-caption`: Fixed issue with missing caption for album messages before `0.1.15`.
+
diff --git a/api/src/main/java/telegram/files/AutoDownloadVerticle.java b/api/src/main/java/telegram/files/AutoDownloadVerticle.java
index 376cf29..3c7d539 100644
--- a/api/src/main/java/telegram/files/AutoDownloadVerticle.java
+++ b/api/src/main/java/telegram/files/AutoDownloadVerticle.java
@@ -130,7 +130,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
}
Tuple2> rule = handleRule(auto);
- TelegramVerticle telegramVerticle = this.getTelegramVerticle(auto.telegramId);
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(auto.telegramId);
TdApi.SearchChatMessages searchChatMessages = new TdApi.SearchChatMessages();
searchChatMessages.query = rule.v1;
searchChatMessages.chatId = auto.chatId;
@@ -229,7 +229,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
return;
}
log.debug("Download start! TelegramId: %d size: %d".formatted(telegramId, messages.size()));
- TelegramVerticle telegramVerticle = this.getTelegramVerticle(telegramId);
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(telegramId);
int surplusSize = getSurplusSize(telegramId);
if (surplusSize <= 0) {
return;
@@ -251,11 +251,6 @@ public class AutoDownloadVerticle extends AbstractVerticle {
log.debug("Remaining download messages: %d".formatted(messages.size()));
}
- private TelegramVerticle getTelegramVerticle(long telegramId) {
- return HttpVerticle.getTelegramVerticle(telegramId)
- .orElseThrow(() -> new IllegalArgumentException("Telegram verticle not found: %s".formatted(telegramId)));
- }
-
private void onNewMessage(JsonObject jsonObject) {
long telegramId = jsonObject.getLong("telegramId");
long chatId = jsonObject.getLong("chatId");
@@ -263,7 +258,7 @@ public class AutoDownloadVerticle extends AbstractVerticle {
autoRecords.items.stream()
.filter(item -> item.telegramId == telegramId && item.chatId == chatId)
.findFirst()
- .flatMap(item -> HttpVerticle.getTelegramVerticle(telegramId))
+ .flatMap(item -> TelegramVerticles.get(telegramId))
.ifPresent(telegramVerticle -> {
if (telegramVerticle.authorized) {
telegramVerticle.client.execute(new TdApi.GetMessage(chatId, messageId))
diff --git a/api/src/main/java/telegram/files/AutoRecordsHolder.java b/api/src/main/java/telegram/files/AutoRecordsHolder.java
index 5aaecb3..b89360f 100644
--- a/api/src/main/java/telegram/files/AutoRecordsHolder.java
+++ b/api/src/main/java/telegram/files/AutoRecordsHolder.java
@@ -35,7 +35,7 @@ public class AutoRecordsHolder {
if (settingAutoRecords == null) {
return;
}
- settingAutoRecords.items.forEach(item -> HttpVerticle.getTelegramVerticle(item.telegramId)
+ settingAutoRecords.items.forEach(item -> TelegramVerticles.get(item.telegramId)
.ifPresentOrElse(telegramVerticle -> {
if (telegramVerticle.authorized) {
autoRecords.add(item);
@@ -52,7 +52,7 @@ public class AutoRecordsHolder {
for (SettingAutoRecords.Item item : records.items) {
if (!autoRecords.exists(item.telegramId, item.chatId)) {
// new enabled
- HttpVerticle.getTelegramVerticle(item.telegramId)
+ TelegramVerticles.get(item.telegramId)
.ifPresentOrElse(telegramVerticle -> {
if (telegramVerticle.authorized) {
autoRecords.add(item);
diff --git a/api/src/main/java/telegram/files/Config.java b/api/src/main/java/telegram/files/Config.java
index 64cce7a..4c9f52d 100644
--- a/api/src/main/java/telegram/files/Config.java
+++ b/api/src/main/java/telegram/files/Config.java
@@ -7,6 +7,8 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import cn.hutool.log.dialect.jdk.JdkLog;
+import io.vertx.core.DeploymentOptions;
+import io.vertx.core.ThreadingModel;
import java.io.File;
import java.io.IOException;
@@ -29,6 +31,9 @@ public class Config {
public static final int TELEGRAM_LOG_LEVEL = Convert.toInt(System.getenv("TELEGRAM_LOG_LEVEL"), 0);
+ public static final DeploymentOptions VIRTUAL_THREAD_DEPLOYMENT_OPTIONS = new DeploymentOptions()
+ .setThreadingModel(ThreadingModel.VIRTUAL_THREAD);
+
private static Level logLevel;
static {
diff --git a/api/src/main/java/telegram/files/EventEnum.java b/api/src/main/java/telegram/files/EventEnum.java
index c889d07..76de6a2 100644
--- a/api/src/main/java/telegram/files/EventEnum.java
+++ b/api/src/main/java/telegram/files/EventEnum.java
@@ -31,6 +31,12 @@ public enum EventEnum {
* @see telegram.files.EventPayload
*/
TELEGRAM_EVENT,
+
+ /**
+ * suffix = null
+ * body = JSONObject with "success", "message"
+ */
+ MAINTAIN,
;
public String address() {
diff --git a/api/src/main/java/telegram/files/HttpVerticle.java b/api/src/main/java/telegram/files/HttpVerticle.java
index 354a935..309cf31 100644
--- a/api/src/main/java/telegram/files/HttpVerticle.java
+++ b/api/src/main/java/telegram/files/HttpVerticle.java
@@ -3,7 +3,6 @@ package telegram.files;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.FileUtil;
-import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.log.Log;
@@ -14,7 +13,6 @@ import io.vertx.core.http.CookieSameSite;
import io.vertx.core.http.HttpMethod;
import io.vertx.core.http.HttpServerOptions;
import io.vertx.core.http.HttpServerResponse;
-import io.vertx.core.impl.NoStackTraceException;
import io.vertx.core.json.Json;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
@@ -31,9 +29,7 @@ import org.drinkless.tdlib.TdApi;
import telegram.files.repository.SettingAutoRecords;
import telegram.files.repository.SettingKey;
import telegram.files.repository.SettingRecord;
-import telegram.files.repository.TelegramRecord;
-import java.io.File;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
@@ -45,8 +41,6 @@ public class HttpVerticle extends AbstractVerticle {
// session id -> ws handler id
private static final Map clients = new ConcurrentHashMap<>();
- private static final List telegramVerticles = new ArrayList<>();
-
// session id -> telegram verticle
private final Map sessionTelegramVerticles = new ConcurrentHashMap<>();
@@ -184,52 +178,16 @@ public class HttpVerticle extends AbstractVerticle {
}
public Future initTelegramVerticles() {
- return DataVerticle.telegramRepository.getAll()
- .compose(telegramRecords -> {
- List verifiedPath = telegramRecords.stream().map(TelegramRecord::rootPath).toList();
- File telegramRoot = FileUtil.file(Config.TELEGRAM_ROOT);
- List uncertifiedPaths = FileUtil.loopFiles(telegramRoot, 1, null)
- .stream()
- .filter(f -> f.isDirectory() && !verifiedPath.contains(f.getAbsolutePath()))
- .map(File::getAbsolutePath)
- .toList();
- List> futures = new ArrayList<>();
- for (TelegramRecord telegramRecord : telegramRecords) {
- TelegramVerticle telegramVerticle = new TelegramVerticle(telegramRecord);
- if (!telegramVerticle.check()) {
- continue;
- }
- telegramVerticles.add(telegramVerticle);
- futures.add(vertx.deployVerticle(telegramVerticle));
- }
- if (CollUtil.isNotEmpty(uncertifiedPaths)) {
- for (String uncertifiedPath : uncertifiedPaths) {
- TelegramVerticle telegramVerticle = new TelegramVerticle(uncertifiedPath);
- if (!telegramVerticle.check()) {
- continue;
- }
- telegramVerticles.add(telegramVerticle);
- futures.add(vertx.deployVerticle(telegramVerticle));
- }
- }
- return Future.all(futures);
- })
- .onSuccess(r -> log.info("Successfully deployed %d telegram verticles".formatted(r.size())))
- .onFailure(err -> log.error("Failed to deploy telegram verticles: %s".formatted(err.getMessage())))
- .mapEmpty();
+ return TelegramVerticles.initTelegramVerticles(vertx);
}
public Future initAutoDownloadVerticle() {
- return vertx.deployVerticle(new AutoDownloadVerticle(autoRecordsHolder), new DeploymentOptions()
- .setThreadingModel(ThreadingModel.VIRTUAL_THREAD)
- )
+ return vertx.deployVerticle(new AutoDownloadVerticle(autoRecordsHolder), Config.VIRTUAL_THREAD_DEPLOYMENT_OPTIONS)
.mapEmpty();
}
public Future initTransferVerticle() {
- return vertx.deployVerticle(new TransferVerticle(autoRecordsHolder), new DeploymentOptions()
- .setThreadingModel(ThreadingModel.VIRTUAL_THREAD)
- )
+ return vertx.deployVerticle(new TransferVerticle(autoRecordsHolder), Config.VIRTUAL_THREAD_DEPLOYMENT_OPTIONS)
.mapEmpty();
}
@@ -350,7 +308,7 @@ public class HttpVerticle extends AbstractVerticle {
TelegramVerticle newTelegramVerticle = new TelegramVerticle(DataVerticle.telegramRepository.getRootPath());
newTelegramVerticle.setProxy(proxyName);
sessionTelegramVerticles.put(sessionId, newTelegramVerticle);
- telegramVerticles.add(newTelegramVerticle);
+ TelegramVerticles.add(newTelegramVerticle);
vertx.deployVerticle(newTelegramVerticle)
.onSuccess(id -> ctx.json(new JsonObject()
.put("id", newTelegramVerticle.getId())
@@ -360,20 +318,13 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleTelegramDelete(RoutingContext ctx) {
- String telegramId = ctx.pathParam("telegramId");
- if (StrUtil.isBlank(telegramId)) {
- ctx.fail(400);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
- Optional telegramVerticleOptional = getTelegramVerticle(telegramId);
- if (telegramVerticleOptional.isEmpty()) {
- ctx.fail(404);
- return;
- }
- TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
telegramVerticle.close(true)
.onSuccess(r -> {
- telegramVerticles.remove(telegramVerticle);
+ TelegramVerticles.remove(telegramVerticle);
sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle));
ctx.end();
});
@@ -381,7 +332,7 @@ public class HttpVerticle extends AbstractVerticle {
private void handleTelegrams(RoutingContext ctx) {
Boolean authorized = Convert.toBool(ctx.request().getParam("authorized"));
- Future.all(telegramVerticles.stream()
+ Future.all(TelegramVerticles.getAll().stream()
.filter(c -> authorized == null || c.authorized == authorized)
.map(TelegramVerticle::getTelegramAccount)
.toList()
@@ -392,29 +343,25 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleTelegramChats(RoutingContext ctx) {
- String telegramId = ctx.pathParam("telegramId");
- if (StrUtil.isBlank(telegramId)) {
- ctx.fail(400);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
String query = ctx.request().getParam("query");
String chatId = ctx.request().getParam("chatId");
String archived = ctx.request().getParam("archived");
- getTelegramVerticle(telegramId)
- .ifPresentOrElse(telegramVerticle ->
- telegramVerticle.getChats(Convert.toLong(chatId), query, Convert.toBool(archived, false))
- .onSuccess(ctx::json)
- .onFailure(ctx::fail), () -> ctx.fail(404));
+ telegramVerticle.getChats(Convert.toLong(chatId), query, Convert.toBool(archived, false))
+ .onSuccess(ctx::json)
+ .onFailure(ctx::fail);
}
private void handleTelegramFiles(RoutingContext ctx) {
- String telegramId = ctx.pathParam("telegramId");
- if (StrUtil.isBlank(telegramId)) {
- ctx.fail(400);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
- String chatIdStr = ctx.pathParam("chatId");
- if (StrUtil.isBlank(chatIdStr)) {
+ String chatId = ctx.pathParam("chatId");
+ if (StrUtil.isBlank(chatId)) {
ctx.fail(400);
return;
}
@@ -422,19 +369,14 @@ public class HttpVerticle extends AbstractVerticle {
ctx.request().params().forEach(filter::put);
filter.put("search", URLUtil.decode(filter.get("search")));
- long chatId = Convert.toLong(chatIdStr);
- getTelegramVerticle(telegramId)
- .ifPresentOrElse(telegramVerticle ->
- telegramVerticle.getChatFiles(chatId, filter)
- .onSuccess(ctx::json)
- .onFailure(ctx::fail),
- () -> ctx.fail(404));
+ telegramVerticle.getChatFiles(Convert.toLong(chatId), filter)
+ .onSuccess(ctx::json)
+ .onFailure(ctx::fail);
}
private void handleTelegramFilesCount(RoutingContext ctx) {
- String telegramId = ctx.pathParam("telegramId");
- if (StrUtil.isBlank(telegramId)) {
- ctx.fail(400);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
String chatIdStr = ctx.pathParam("chatId");
@@ -443,26 +385,16 @@ public class HttpVerticle extends AbstractVerticle {
return;
}
long chatId = Convert.toLong(chatIdStr);
- getTelegramVerticle(telegramId)
- .ifPresentOrElse(telegramVerticle ->
- telegramVerticle.getChatFilesCount(chatId)
- .onSuccess(ctx::json)
- .onFailure(ctx::fail),
- () -> ctx.fail(404));
+ telegramVerticle.getChatFilesCount(chatId)
+ .onSuccess(ctx::json)
+ .onFailure(ctx::fail);
}
private void handleTelegramDownloadStatistics(RoutingContext ctx) {
- String telegramId = ctx.pathParam("telegramId");
- if (StrUtil.isBlank(telegramId)) {
- ctx.fail(400);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
- Optional telegramVerticleOptional = getTelegramVerticle(telegramId);
- if (telegramVerticleOptional.isEmpty()) {
- ctx.fail(404);
- return;
- }
- TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
String type = ctx.request().getParam("type");
String timeRange = ctx.request().getParam("timeRange");
@@ -487,7 +419,7 @@ public class HttpVerticle extends AbstractVerticle {
sessionTelegramVerticles.remove(sessionId);
return true;
}
- Optional optionalTelegramVerticle = getTelegramVerticle(telegramId);
+ Optional optionalTelegramVerticle = TelegramVerticles.get(telegramId);
if (optionalTelegramVerticle.isEmpty()) {
return false;
}
@@ -497,7 +429,7 @@ public class HttpVerticle extends AbstractVerticle {
private void handleTelegramToggleProxy(RoutingContext ctx) {
String telegramId = ctx.request().getParam("telegramId");
- getTelegramVerticle(telegramId)
+ TelegramVerticles.get(telegramId)
.ifPresentOrElse(telegramVerticle ->
telegramVerticle.toggleProxy(ctx.body().asJsonObject())
.onSuccess(r -> ctx.json(JsonObject.of("proxy", r)))
@@ -510,7 +442,7 @@ public class HttpVerticle extends AbstractVerticle {
ctx.fail(400);
return;
}
- getTelegramVerticle(telegramId)
+ TelegramVerticles.get(telegramId)
.ifPresentOrElse(telegramVerticle ->
telegramVerticle.ping()
.onSuccess(r -> ctx.json(JsonObject.of("ping", r)))
@@ -524,7 +456,7 @@ public class HttpVerticle extends AbstractVerticle {
ctx.fail(400);
return;
}
- getTelegramVerticle(telegramId)
+ TelegramVerticles.get(telegramId)
.ifPresentOrElse(telegramVerticle ->
telegramVerticle.client.execute(new TdApi.TestNetwork())
.onComplete(r ->
@@ -549,7 +481,7 @@ public class HttpVerticle extends AbstractVerticle {
ctx.fail(400);
return;
}
- TelegramVerticle telegramVerticle = getTelegramVerticle(ctx);
+ TelegramVerticle telegramVerticle = getTelegramVerticleBySession(ctx);
if (telegramVerticle == null) {
return;
}
@@ -560,12 +492,10 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFilePreview(RoutingContext ctx) {
- Optional telegramVerticleOptional = getTelegramVerticle(ctx.pathParam("telegramId"));
- if (telegramVerticleOptional.isEmpty()) {
- ctx.fail(404);
+ TelegramVerticle telegramVerticle = getTelegramVerticleByPath(ctx);
+ if (telegramVerticle == null) {
return;
}
- TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
String uniqueId = ctx.pathParam("uniqueId");
if (StrUtil.isBlank(uniqueId)) {
ctx.fail(404);
@@ -585,7 +515,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFileStartDownload(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
JsonObject jsonObject = ctx.body().asJsonObject();
Long chatId = jsonObject.getLong("chatId");
@@ -602,7 +532,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFileStartDownloadMultiple(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
JsonObject jsonObject = ctx.body().asJsonObject();
Long chatId = jsonObject.getLong("chatId");
@@ -629,7 +559,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFileCancelDownload(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
JsonObject jsonObject = ctx.body().asJsonObject();
Integer fileId = jsonObject.getInteger("fileId");
@@ -644,7 +574,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFileTogglePauseDownload(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
JsonObject jsonObject = ctx.body().asJsonObject();
Integer fileId = jsonObject.getInteger("fileId");
@@ -660,7 +590,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleFileRemove(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
if (telegramVerticle == null) {
return;
}
@@ -678,7 +608,7 @@ public class HttpVerticle extends AbstractVerticle {
}
private void handleAutoDownload(RoutingContext ctx) {
- TelegramVerticle telegramVerticle = getTelegramVerticleThrow(ctx.pathParam("telegramId"));
+ TelegramVerticle telegramVerticle = TelegramVerticles.getOrElseThrow(ctx.pathParam("telegramId"));
String chatId = ctx.request().getParam("chatId");
if (StrUtil.isBlank(chatId)) {
@@ -691,28 +621,7 @@ public class HttpVerticle extends AbstractVerticle {
.onFailure(ctx::fail);
}
- public static Optional getTelegramVerticle(String telegramId) {
- Object id = NumberUtil.isNumber(telegramId) ? Convert.toLong(telegramId) : telegramId;
- return telegramVerticles.stream()
- .filter(t -> Objects.equals(t.getId(), id))
- .findFirst();
- }
-
- public static TelegramVerticle getTelegramVerticleThrow(String telegramId) {
- Object id = NumberUtil.isNumber(telegramId) ? Convert.toLong(telegramId) : telegramId;
- return telegramVerticles.stream()
- .filter(t -> Objects.equals(t.getId(), id))
- .findFirst()
- .orElseThrow(() -> new NoStackTraceException("Telegram account not found!"));
- }
-
- public static Optional getTelegramVerticle(long telegramId) {
- return telegramVerticles.stream()
- .filter(t -> t.telegramRecord != null && t.telegramRecord.id() == telegramId)
- .findFirst();
- }
-
- private TelegramVerticle getTelegramVerticle(RoutingContext ctx) {
+ private TelegramVerticle getTelegramVerticleBySession(RoutingContext ctx) {
String sessionId = ctx.session().id();
TelegramVerticle telegramVerticle = sessionTelegramVerticles.get(sessionId);
if (telegramVerticle == null) {
@@ -722,4 +631,18 @@ public class HttpVerticle extends AbstractVerticle {
}
return telegramVerticle;
}
+
+ private TelegramVerticle getTelegramVerticleByPath(RoutingContext ctx) {
+ String telegramId = ctx.pathParam("telegramId");
+ if (StrUtil.isBlank(telegramId)) {
+ ctx.fail(400);
+ return null;
+ }
+ Optional telegramVerticleOptional = TelegramVerticles.get(telegramId);
+ if (telegramVerticleOptional.isEmpty()) {
+ ctx.fail(404);
+ return null;
+ }
+ return telegramVerticleOptional.get();
+ }
}
diff --git a/api/src/main/java/telegram/files/Maintain.java b/api/src/main/java/telegram/files/Maintain.java
new file mode 100644
index 0000000..bd520e0
--- /dev/null
+++ b/api/src/main/java/telegram/files/Maintain.java
@@ -0,0 +1,63 @@
+package telegram.files;
+
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import io.vertx.core.Vertx;
+import telegram.files.maintains.AlbumCaptionMaintainVerticle;
+import telegram.files.maintains.MaintainVerticle;
+
+public class Maintain {
+ static {
+ LogFactory.setCurrentLogFactory(new Config.JDKLogFactory());
+ }
+
+ private static final Log log = LogFactory.get();
+
+ private static final Vertx vertx = Vertx.vertx();
+
+ public static void main(String[] args) {
+ if (ArrayUtil.isEmpty(args)) {
+ System.out.println("Missing maintain name");
+ System.out.println("Usage: java -cp api.jar telegram.files.Maintain ");
+ System.out.println("Maintain names:");
+ System.out.println(" album-caption");
+ System.exit(1);
+ }
+
+ String maintainName = args[0];
+ try {
+ MaintainVerticle maintainVerticle = null;
+ switch (maintainName) {
+ case "album-caption" -> {
+ maintainVerticle = new AlbumCaptionMaintainVerticle();
+ MessyUtils.await(vertx.deployVerticle(maintainVerticle, Config.VIRTUAL_THREAD_DEPLOYMENT_OPTIONS)
+ .onFailure(err -> {
+ log.error("Failed to deploy album caption maintain verticle", err);
+ System.exit(1);
+ }));
+ }
+ default -> {
+ System.out.println("Unknown maintain name: " + maintainName);
+ System.exit(1);
+ }
+ }
+
+ final MaintainVerticle finalMaintainVerticle = maintainVerticle;
+ vertx.eventBus().consumer(EventEnum.MAINTAIN.address(), message ->
+ vertx.undeploy(finalMaintainVerticle.deploymentID())
+ .onSuccess(v -> {
+ log.trace("Undeploy maintain verticle success");
+ System.exit(0);
+ })
+ .onFailure(err -> {
+ log.error("Failed to undeploy maintain verticle", err);
+ System.exit(1);
+ }));
+ } catch (Exception e) {
+ log.error("Failed to maintain", e);
+ System.exit(1);
+ }
+ }
+
+}
diff --git a/api/src/main/java/telegram/files/Start.java b/api/src/main/java/telegram/files/Start.java
index 6a4fd59..c1e3004 100644
--- a/api/src/main/java/telegram/files/Start.java
+++ b/api/src/main/java/telegram/files/Start.java
@@ -13,7 +13,7 @@ public class Start {
private static final Log log = LogFactory.get();
- public static final String VERSION = "0.1.14";
+ public static final String VERSION = "0.1.15";
private static final CountDownLatch shutdownLatch = new CountDownLatch(1);
diff --git a/api/src/main/java/telegram/files/TdApiHelp.java b/api/src/main/java/telegram/files/TdApiHelp.java
index da2b045..ec26f4a 100644
--- a/api/src/main/java/telegram/files/TdApiHelp.java
+++ b/api/src/main/java/telegram/files/TdApiHelp.java
@@ -273,6 +273,7 @@ public class TdApiHelp {
telegramId,
message.chatId,
message.id,
+ message.mediaAlbumId,
message.date,
message.hasSensitiveContent,
file.size == 0 ? file.expectedSize : file.size,
@@ -342,6 +343,7 @@ public class TdApiHelp {
telegramId,
message.chatId,
message.id,
+ message.mediaAlbumId,
message.date,
message.hasSensitiveContent,
file.size == 0 ? file.expectedSize : file.size,
@@ -399,6 +401,7 @@ public class TdApiHelp {
telegramId,
message.chatId,
message.id,
+ message.mediaAlbumId,
message.date,
message.hasSensitiveContent,
file.size == 0 ? file.expectedSize : file.size,
@@ -447,6 +450,7 @@ public class TdApiHelp {
telegramId,
message.chatId,
message.id,
+ message.mediaAlbumId,
message.date,
message.hasSensitiveContent,
file.size == 0 ? file.expectedSize : file.size,
diff --git a/api/src/main/java/telegram/files/TelegramVerticles.java b/api/src/main/java/telegram/files/TelegramVerticles.java
new file mode 100644
index 0000000..f345f3f
--- /dev/null
+++ b/api/src/main/java/telegram/files/TelegramVerticles.java
@@ -0,0 +1,95 @@
+package telegram.files;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.NumberUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import io.vertx.core.Future;
+import io.vertx.core.Vertx;
+import io.vertx.core.impl.NoStackTraceException;
+import telegram.files.repository.TelegramRecord;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+public class TelegramVerticles {
+ private static final Log log = LogFactory.get();
+
+ private static final List telegramVerticles = new ArrayList<>();
+
+ public static Future initTelegramVerticles(Vertx vertx) {
+ return DataVerticle.telegramRepository.getAll()
+ .compose(telegramRecords -> {
+ List verifiedPath = telegramRecords.stream().map(TelegramRecord::rootPath).toList();
+ File telegramRoot = FileUtil.file(Config.TELEGRAM_ROOT);
+ List uncertifiedPaths = FileUtil.loopFiles(telegramRoot, 1, null)
+ .stream()
+ .filter(f -> f.isDirectory() && !verifiedPath.contains(f.getAbsolutePath()))
+ .map(File::getAbsolutePath)
+ .toList();
+ List> futures = new ArrayList<>();
+ for (TelegramRecord telegramRecord : telegramRecords) {
+ TelegramVerticle telegramVerticle = new TelegramVerticle(telegramRecord);
+ if (!telegramVerticle.check()) {
+ continue;
+ }
+ telegramVerticles.add(telegramVerticle);
+ futures.add(vertx.deployVerticle(telegramVerticle));
+ }
+ if (CollUtil.isNotEmpty(uncertifiedPaths)) {
+ for (String uncertifiedPath : uncertifiedPaths) {
+ TelegramVerticle telegramVerticle = new TelegramVerticle(uncertifiedPath);
+ if (!telegramVerticle.check()) {
+ continue;
+ }
+ telegramVerticles.add(telegramVerticle);
+ futures.add(vertx.deployVerticle(telegramVerticle));
+ }
+ }
+ return Future.all(futures);
+ })
+ .onSuccess(r -> log.info("Successfully deployed %d telegram verticles".formatted(r.size())))
+ .onFailure(err -> log.error("Failed to deploy telegram verticles: %s".formatted(err.getMessage())))
+ .mapEmpty();
+ }
+
+ public static void add(TelegramVerticle telegramVerticle) {
+ telegramVerticles.add(telegramVerticle);
+ }
+
+ public static void remove(TelegramVerticle telegramVerticle) {
+ telegramVerticles.remove(telegramVerticle);
+ }
+
+ public static List getAll() {
+ return telegramVerticles;
+ }
+
+ public static Optional get(String telegramId) {
+ Object id = NumberUtil.isNumber(telegramId) ? Convert.toLong(telegramId) : telegramId;
+ return telegramVerticles.stream()
+ .filter(t -> Objects.equals(t.getId(), id))
+ .findFirst();
+ }
+
+ public static TelegramVerticle getOrElseThrow(String telegramId) {
+ return get(telegramId)
+ .orElseThrow(() -> new NoStackTraceException("Telegram account not found!"));
+ }
+
+ public static Optional get(long telegramId) {
+ return telegramVerticles.stream()
+ .filter(t -> t.telegramRecord != null && t.telegramRecord.id() == telegramId)
+ .findFirst();
+ }
+
+ public static TelegramVerticle getOrElseThrow(long telegramId) {
+ return get(telegramId)
+ .orElseThrow(() -> new NoStackTraceException("Telegram account not found!"));
+ }
+}
diff --git a/api/src/main/java/telegram/files/maintains/AlbumCaptionMaintainVerticle.java b/api/src/main/java/telegram/files/maintains/AlbumCaptionMaintainVerticle.java
new file mode 100644
index 0000000..1d5dcc9
--- /dev/null
+++ b/api/src/main/java/telegram/files/maintains/AlbumCaptionMaintainVerticle.java
@@ -0,0 +1,141 @@
+package telegram.files.maintains;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.collection.IterUtil;
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.log.Log;
+import cn.hutool.log.LogFactory;
+import io.vertx.core.Future;
+import io.vertx.core.Promise;
+import io.vertx.sqlclient.templates.SqlTemplate;
+import org.drinkless.tdlib.TdApi;
+import telegram.files.Config;
+import telegram.files.DataVerticle;
+import telegram.files.TelegramVerticle;
+import telegram.files.TelegramVerticles;
+import telegram.files.repository.FileRecord;
+
+import java.util.List;
+import java.util.Optional;
+
+/**
+ * This verticle is responsible for maintaining the captions of the media files.
+ */
+public class AlbumCaptionMaintainVerticle extends MaintainVerticle {
+
+ private static final Log log = LogFactory.get();
+
+ private final DataVerticle dataVerticle = new DataVerticle();
+
+ @Override
+ public void start(Promise startPromise) {
+ vertx.deployVerticle(dataVerticle, Config.VIRTUAL_THREAD_DEPLOYMENT_OPTIONS)
+ .compose(r -> TelegramVerticles.initTelegramVerticles(vertx))
+ .compose(r -> {
+ vertx.setTimer(1000, id -> handleAlbumCaption());
+ return Future.succeededFuture();
+ })
+ .onSuccess(id -> startPromise.complete())
+ .onFailure(startPromise::fail);
+ }
+
+ public void handleAlbumCaption() {
+ log.info("🔨 Start to handle album caption");
+ try {
+ log.trace("🔨 1.Scan all file records and update the media_album_id of file records");
+ long fromMessageId = 0;
+ long count = 0;
+ long page = 1;
+ while (true) {
+ log.trace("🔨 Scan page %d, limit 100".formatted(page));
+ List rows = Future.await(SqlTemplate.forQuery(DataVerticle.pool, """
+ SELECT * FROM file_record WHERE media_album_id is null %s ORDER BY message_id desc LIMIT 100
+ """.formatted(fromMessageId == 0 ? "" : " AND message_id < #{fromMessageId}")
+ )
+ .mapTo(FileRecord.ROW_MAPPER)
+ .execute(MapUtil.of("fromMessageId", fromMessageId))
+ .map(IterUtil::toList));
+
+ if (CollUtil.isEmpty(rows)) {
+ log.trace("🔨 No more file records found, update finished");
+ break;
+ }
+
+ for (FileRecord fileRecord : rows) {
+ if (updateMediaAlbumId(fileRecord)) {
+ count++;
+ }
+ }
+
+ fromMessageId = rows.getLast().messageId();
+ page++;
+ }
+ log.info("✅ Updated %d file records with media album id".formatted(count));
+
+ log.trace("🔨 2.Update the caption of the media album");
+ fromMessageId = 0;
+ count = 0;
+ page = 1;
+ while (true) {
+ log.trace("🔨 Scan page %d, limit 100".formatted(page));
+ List rows = Future.await(SqlTemplate.forQuery(DataVerticle.pool, """
+ SELECT * FROM file_record WHERE media_album_id is not null AND caption != '' %s ORDER BY message_id desc LIMIT 100
+ """.formatted(fromMessageId == 0 ? "" : " AND message_id < #{fromMessageId}")
+ )
+ .mapTo(FileRecord.ROW_MAPPER)
+ .execute(MapUtil.of("fromMessageId", fromMessageId))
+ .map(IterUtil::toList));
+
+ if (CollUtil.isEmpty(rows)) {
+ log.trace("🔨 No more file records found, update finished");
+ break;
+ }
+
+ for (FileRecord fileRecord : rows) {
+ int updated = Future.await(DataVerticle.fileRepository.updateCaptionByMediaAlbumId(fileRecord.mediaAlbumId(), fileRecord.caption()));
+ count += updated;
+ }
+
+ fromMessageId = rows.getLast().messageId();
+ page++;
+ }
+ log.info("✅ Updated %d media albums with caption".formatted(count));
+ log.info("✅ Finished handling album caption");
+ super.end(true, null);
+ } catch (Exception e) {
+ log.error("🔨 Failed to handle album caption", e);
+ super.end(false, e);
+ }
+ }
+
+ private boolean updateMediaAlbumId(FileRecord fileRecord) {
+ try {
+ Optional telegramVerticleOptional = TelegramVerticles.get(fileRecord.telegramId());
+ if (telegramVerticleOptional.isEmpty()) {
+ log.error("🔨 Telegram verticle not found for telegram id: %d".formatted(fileRecord.telegramId()));
+ return false;
+ }
+ TelegramVerticle telegramVerticle = telegramVerticleOptional.get();
+ TdApi.Message message = Future.await(telegramVerticle.client.execute(new TdApi.GetMessage(fileRecord.chatId(), fileRecord.messageId())));
+ if (message != null && message.mediaAlbumId != 0) {
+ Future.await(SqlTemplate.forUpdate(DataVerticle.pool, """
+ UPDATE file_record
+ SET media_album_id = #{mediaAlbumId}
+ WHERE unique_id = #{uniqueId}
+ """)
+ .execute(MapUtil.ofEntries(
+ MapUtil.entry("uniqueId", fileRecord.uniqueId()),
+ MapUtil.entry("mediaAlbumId", message.mediaAlbumId)
+ ))
+ .onFailure(err -> log.error("🔨 Failed to update media album id: %s".formatted(err.getMessage())))
+ .map(true));
+ return true;
+ }
+ return false;
+ } catch (Exception e) {
+ log.error(e, "🔨 Failed to update media album id, unique id: %s".formatted(fileRecord.uniqueId()));
+ return false;
+ }
+ }
+
+}
diff --git a/api/src/main/java/telegram/files/maintains/MaintainVerticle.java b/api/src/main/java/telegram/files/maintains/MaintainVerticle.java
new file mode 100644
index 0000000..27be438
--- /dev/null
+++ b/api/src/main/java/telegram/files/maintains/MaintainVerticle.java
@@ -0,0 +1,14 @@
+package telegram.files.maintains;
+
+import io.vertx.core.AbstractVerticle;
+import io.vertx.core.json.JsonObject;
+import telegram.files.EventEnum;
+
+public class MaintainVerticle extends AbstractVerticle {
+
+ public void end(boolean success, Throwable cause) {
+ vertx.eventBus().publish(EventEnum.MAINTAIN.address(),
+ JsonObject.of("success", success, "message", cause == null ? null : cause.getMessage())
+ );
+ }
+}
diff --git a/api/src/main/java/telegram/files/repository/FileRecord.java b/api/src/main/java/telegram/files/repository/FileRecord.java
index e79b7e4..cc4df6f 100644
--- a/api/src/main/java/telegram/files/repository/FileRecord.java
+++ b/api/src/main/java/telegram/files/repository/FileRecord.java
@@ -14,6 +14,7 @@ public record FileRecord(int id, //file id will change
long telegramId,
long chatId,
long messageId,
+ long mediaAlbumId,
int date, // date when the file was uploaded
boolean hasSensitiveContent,
long size, // file size in bytes
@@ -46,6 +47,7 @@ public record FileRecord(int id, //file id will change
telegram_id BIGINT,
chat_id BIGINT,
message_id BIGINT,
+ media_album_id BIGINT,
date INT,
has_sensitive_content BOOLEAN,
size BIGINT,
@@ -71,6 +73,9 @@ public record FileRecord(int id, //file id will change
}),
MapUtil.entry(new Version("0.1.12"), new String[]{
"ALTER TABLE file_record ADD COLUMN transfer_status VARCHAR(255) DEFAULT 'idle';",
+ }),
+ MapUtil.entry(new Version("0.1.15"), new String[]{
+ "ALTER TABLE file_record ADD COLUMN media_album_id BIGINT;",
})
));
@@ -92,6 +97,7 @@ public record FileRecord(int id, //file id will change
row.getLong("telegram_id"),
row.getLong("chat_id"),
row.getLong("message_id"),
+ Objects.requireNonNullElse(row.getLong("media_album_id"), 0L),
row.getInteger("date"),
Convert.toBool(row.getInteger("has_sensitive_content")),
row.getLong("size"),
@@ -115,6 +121,7 @@ public record FileRecord(int id, //file id will change
MapUtil.entry("telegram_id", r.telegramId()),
MapUtil.entry("chat_id", r.chatId()),
MapUtil.entry("message_id", r.messageId()),
+ MapUtil.entry("media_album_id", r.mediaAlbumId()),
MapUtil.entry("date", r.date()),
MapUtil.entry("has_sensitive_content", r.hasSensitiveContent()),
MapUtil.entry("size", r.size()),
@@ -132,7 +139,7 @@ public record FileRecord(int id, //file id will change
));
public FileRecord withSourceField(int id, long downloadedSize) {
- return new FileRecord(id, uniqueId, telegramId, chatId, messageId, date, hasSensitiveContent, size, downloadedSize, type, mimeType, fileName, thumbnail, caption, localPath, downloadStatus, transferStatus, startDate, completionDate);
+ return new FileRecord(id, uniqueId, telegramId, chatId, messageId, mediaAlbumId, date, hasSensitiveContent, size, downloadedSize, type, mimeType, fileName, thumbnail, caption, localPath, downloadStatus, transferStatus, startDate, completionDate);
}
public boolean isDownloadStatus(DownloadStatus status) {
diff --git a/api/src/main/java/telegram/files/repository/FileRepository.java b/api/src/main/java/telegram/files/repository/FileRepository.java
index 582f587..0d378e4 100644
--- a/api/src/main/java/telegram/files/repository/FileRepository.java
+++ b/api/src/main/java/telegram/files/repository/FileRepository.java
@@ -21,6 +21,8 @@ public interface FileRepository {
Future getByUniqueId(String uniqueId);
+ Future getCaptionByMediaAlbumId(long mediaAlbumId);
+
Future getDownloadStatistics(long telegramId);
Future getCompletedRangeStatistics(long id, long startTime, long endTime, int timeRange);
@@ -39,5 +41,7 @@ public interface FileRepository {
Future updateFileId(int fileId, String uniqueId);
+ Future updateCaptionByMediaAlbumId(long mediaAlbumId, String caption);
+
Future deleteByUniqueId(String uniqueId);
}
diff --git a/api/src/main/java/telegram/files/repository/impl/FileRepositoryImpl.java b/api/src/main/java/telegram/files/repository/impl/FileRepositoryImpl.java
index 13af4c0..558c555 100644
--- a/api/src/main/java/telegram/files/repository/impl/FileRepositoryImpl.java
+++ b/api/src/main/java/telegram/files/repository/impl/FileRepositoryImpl.java
@@ -13,6 +13,7 @@ import io.vertx.core.Future;
import io.vertx.core.json.JsonArray;
import io.vertx.core.json.JsonObject;
import io.vertx.jdbcclient.JDBCPool;
+import io.vertx.sqlclient.SqlResult;
import io.vertx.sqlclient.templates.SqlTemplate;
import org.jooq.lambda.tuple.Tuple;
import org.jooq.lambda.tuple.Tuple3;
@@ -38,16 +39,20 @@ public class FileRepositoryImpl implements FileRepository {
public Future create(FileRecord fileRecord) {
return SqlTemplate
.forUpdate(pool, """
- INSERT INTO file_record(id, unique_id, telegram_id, chat_id, message_id, date, has_sensitive_content, size, downloaded_size,
+ INSERT INTO file_record(id, unique_id, telegram_id, chat_id, message_id, media_album_id, date, has_sensitive_content,
+ size, downloaded_size,
type, mime_type,
file_name, thumbnail, caption, local_path,
download_status, start_date, transfer_status)
- values (#{id}, #{unique_id}, #{telegram_id}, #{chat_id}, #{message_id}, #{date}, #{has_sensitive_content}, #{size}, #{downloaded_size}, #{type},
- #{mime_type}, #{file_name}, #{thumbnail}, #{caption}, #{local_path}, #{download_status}, #{start_date}, #{transfer_status})
+ values (#{id}, #{unique_id}, #{telegram_id}, #{chat_id}, #{message_id}, #{media_album_id}, #{date},
+ #{has_sensitive_content}, #{size}, #{downloaded_size}, #{type},
+ #{mime_type}, #{file_name}, #{thumbnail}, #{caption}, #{local_path}, #{download_status}, #{start_date},
+ #{transfer_status})
""")
.mapFrom(FileRecord.PARAM_MAPPER)
.execute(fileRecord)
.map(r -> fileRecord)
+ .compose(r -> this.updateCaptionByMediaAlbumId(fileRecord.mediaAlbumId(), fileRecord.caption()).map(r))
.onSuccess(r -> log.trace("Successfully created file record: %s".formatted(fileRecord.id()))
)
.onFailure(
@@ -195,6 +200,21 @@ public class FileRepositoryImpl implements FileRepository {
.map(rs -> rs.size() > 0 ? rs.iterator().next() : null);
}
+ @Override
+ public Future getCaptionByMediaAlbumId(long mediaAlbumId) {
+ if (mediaAlbumId <= 0) {
+ return Future.succeededFuture(null);
+ }
+ return SqlTemplate
+ .forQuery(pool, """
+ SELECT caption FROM file_record WHERE media_album_id = #{mediaAlbumId} LIMIT 1
+ """)
+ .mapTo(row -> row.getString("caption"))
+ .execute(Map.of("mediaAlbumId", mediaAlbumId))
+ .map(rs -> rs.size() > 0 ? rs.iterator().next() : null)
+ .onFailure(err -> log.error("Failed to get caption: %s".formatted(err.getMessage())));
+ }
+
@Override
public Future getDownloadStatistics(long telegramId) {
return SqlTemplate
@@ -425,6 +445,34 @@ public class FileRepositoryImpl implements FileRepository {
});
}
+ @Override
+ public Future updateCaptionByMediaAlbumId(long mediaAlbumId, String caption) {
+ if (mediaAlbumId <= 0) {
+ return Future.succeededFuture(0);
+ }
+
+ return Future.future(promise -> {
+ if (StrUtil.isBlank(caption)) {
+ this.getCaptionByMediaAlbumId(mediaAlbumId)
+ .onSuccess(promise::complete);
+ } else {
+ promise.complete(caption);
+ }
+ }).compose(theCaption -> {
+ if (StrUtil.isBlank(theCaption)) {
+ return Future.succeededFuture(0);
+ }
+ return SqlTemplate
+ .forUpdate(pool, """
+ UPDATE file_record SET caption = #{caption} WHERE media_album_id = #{mediaAlbumId}
+ """)
+ .execute(Map.of("mediaAlbumId", mediaAlbumId, "caption", theCaption))
+ .onFailure(err -> log.error("Failed to update file record: %s".formatted(err.getMessage()))
+ )
+ .map(SqlResult::rowCount);
+ });
+ }
+
@Override
public Future deleteByUniqueId(String uniqueId) {
if (StrUtil.isBlank(uniqueId)) {
diff --git a/api/src/test/java/telegram/files/AutoRecordsHolderTest.java b/api/src/test/java/telegram/files/AutoRecordsHolderTest.java
index 255c436..8364b15 100644
--- a/api/src/test/java/telegram/files/AutoRecordsHolderTest.java
+++ b/api/src/test/java/telegram/files/AutoRecordsHolderTest.java
@@ -20,7 +20,7 @@ import static org.mockito.Mockito.*;
public class AutoRecordsHolderTest {
private AutoRecordsHolder autoRecordsHolder;
- private MockedStatic httpVerticleMockedStatic;
+ private MockedStatic telegramVerticlesMockedStatic;
private SettingAutoRecords settingAutoRecords1;
@@ -29,7 +29,7 @@ public class AutoRecordsHolderTest {
@BeforeEach
public void setUp() {
autoRecordsHolder = new AutoRecordsHolder();
- httpVerticleMockedStatic = mockStatic(HttpVerticle.class);
+ telegramVerticlesMockedStatic = mockStatic(TelegramVerticles.class);
// Prepare test data
settingAutoRecords1 = new SettingAutoRecords();
@@ -41,13 +41,13 @@ public class AutoRecordsHolderTest {
// Mock dependencies
TelegramVerticle mockTelegramVerticle = mock(TelegramVerticle.class);
mockTelegramVerticle.authorized = true;
- when(HttpVerticle.getTelegramVerticle(item1.telegramId))
+ when(TelegramVerticles.get(item1.telegramId))
.thenReturn(Optional.of(mockTelegramVerticle));
}
@AfterEach
public void tearDown() {
- httpVerticleMockedStatic.close();
+ telegramVerticlesMockedStatic.close();
}
@Test
diff --git a/api/src/test/java/telegram/files/DataVerticleTest.java b/api/src/test/java/telegram/files/DataVerticleTest.java
index 1e92357..eb8efd9 100644
--- a/api/src/test/java/telegram/files/DataVerticleTest.java
+++ b/api/src/test/java/telegram/files/DataVerticleTest.java
@@ -82,7 +82,7 @@ public class DataVerticleTest {
@DisplayName("Test Get file record by primary key")
void getFileRecordByPrimaryKeyTest(Vertx vertx, VertxTestContext testContext) {
FileRecord fileRecord = new FileRecord(
- 1, "unique_id", 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", "local_path", "download_status", "transfer_status", 0, null
+ 1, "unique_id", 1, 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", "local_path", "download_status", "transfer_status", 0, null
);
DataVerticle.fileRepository.create(fileRecord)
.compose(r -> DataVerticle.fileRepository.getByPrimaryKey(r.id(), r.uniqueId()))
@@ -96,7 +96,7 @@ public class DataVerticleTest {
@DisplayName("Test update file download status")
void updateFileDownloadStatusTest(Vertx vertx, VertxTestContext testContext) {
FileRecord fileRecord = new FileRecord(
- 1, "unique_id", 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null, FileRecord.DownloadStatus.idle.name(), FileRecord.TransferStatus.idle.name(), 0, null
+ 1, "unique_id", 1, 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null, FileRecord.DownloadStatus.idle.name(), FileRecord.TransferStatus.idle.name(), 0, null
);
String updateLocalPath = "local_path";
Long completionDate = 1L;
@@ -123,7 +123,7 @@ public class DataVerticleTest {
@DisplayName("Test update file transfer status")
void updateFileTransferStatusTest(Vertx vertx, VertxTestContext testContext) {
FileRecord fileRecord = new FileRecord(
- 1, "unique_id", 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null, FileRecord.DownloadStatus.idle.name(), FileRecord.TransferStatus.idle.name(), 0, null
+ 1, "unique_id", 1, 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null, FileRecord.DownloadStatus.idle.name(), FileRecord.TransferStatus.idle.name(), 0, null
);
String updateLocalPath = "local_path";
DataVerticle.fileRepository.create(fileRecord)
diff --git a/api/src/test/java/telegram/files/FileDownloadStatusConcurrentTest.java b/api/src/test/java/telegram/files/FileDownloadStatusConcurrentTest.java
index 4996f21..eb412a3 100644
--- a/api/src/test/java/telegram/files/FileDownloadStatusConcurrentTest.java
+++ b/api/src/test/java/telegram/files/FileDownloadStatusConcurrentTest.java
@@ -24,7 +24,7 @@ public class FileDownloadStatusConcurrentTest {
private static ExecutorService executor;
static FileRecord fileRecord = new FileRecord(
- 1, "unique_id", 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null,
+ 1, "unique_id", 1, 1, 1, 1, 1, false, 1, 0, "type", "mime_type", "file_name", "thumbnail", "caption", null,
FileRecord.DownloadStatus.idle.name(), FileRecord.TransferStatus.idle.name(), 0, null
);