fix: preserve concurrent Telegram album files
This commit is contained in:
1 parent
37fb436c36
commit
7d28bc8e66
4 files changed
+71
-9
No files matched your search
Vendored
+20
-4
@@ -4517,6 +4517,20 @@ function createTelegramMediaGroupDebouncer(options) {
|
||||
function telegramMediaGroupQueueKey(chatId, mediaGroupId) {
|
||||
return `${chatId === void 0 || chatId === null ? "unknown" : String(chatId)}:${mediaGroupId}`;
|
||||
}
|
||||
async function getOrCreateTelegramMediaGroupQueue(queues, creations, queueKey, create) {
|
||||
const existing = queues.get(queueKey);
|
||||
if (existing) return existing;
|
||||
const inFlight = creations.get(queueKey);
|
||||
if (inFlight) return inFlight;
|
||||
const creation = create().then((queue) => {
|
||||
queues.set(queueKey, queue);
|
||||
return queue;
|
||||
}).finally(() => {
|
||||
creations.delete(queueKey);
|
||||
});
|
||||
creations.set(queueKey, creation);
|
||||
return creation;
|
||||
}
|
||||
function firstCaptionLine2(message) {
|
||||
return String(message.message || message.text || message.caption || "").split(/\r?\n/)[0].trim();
|
||||
}
|
||||
@@ -7261,6 +7275,7 @@ function retryFailedDownloadTasks(limit = 10, taskId, chatId, userId) {
|
||||
return downloadQueue.retryFailed(limit, { chatId, userId }, taskId);
|
||||
}
|
||||
var mediaGroupQueues = /* @__PURE__ */ new Map();
|
||||
var mediaGroupQueueCreations = /* @__PURE__ */ new Map();
|
||||
var mediaGroupDebouncer = createTelegramMediaGroupDebouncer({
|
||||
delayMs: MEDIA_GROUP_DEBOUNCE_MS,
|
||||
onReady: (mediaGroupId) => processBatchUpload(void 0, mediaGroupId)
|
||||
@@ -8230,12 +8245,12 @@ async function handleFileUpload(client2, event) {
|
||||
await checkAndResetSession(client2, message.chatId);
|
||||
}
|
||||
const queueKey = telegramMediaGroupQueueKey(message.chatId, mediaGroupId);
|
||||
let queue = mediaGroupQueues.get(queueKey);
|
||||
if (!queue) {
|
||||
const existingQueue = mediaGroupQueues.get(queueKey) || mediaGroupQueueCreations.has(queueKey);
|
||||
const queue = await getOrCreateTelegramMediaGroupQueue(mediaGroupQueues, mediaGroupQueueCreations, queueKey, async () => {
|
||||
const chatKey = message.chatId?.toString() || String(senderId);
|
||||
const selectedTarget = await consumeOrGetTelegramTargetState(chatKey);
|
||||
const storageTarget = selectedTarget ? storageManager.getTarget(selectedTarget.provider, selectedTarget.accountId) : storageManager.getActiveTarget();
|
||||
queue = {
|
||||
return {
|
||||
mediaGroupId,
|
||||
queueKey,
|
||||
chatId: message.chatId,
|
||||
@@ -8247,7 +8262,8 @@ async function handleFileUpload(client2, event) {
|
||||
createdAt: Date.now(),
|
||||
lastAddedAt: Date.now()
|
||||
};
|
||||
mediaGroupQueues.set(queueKey, queue);
|
||||
});
|
||||
if (!existingQueue) {
|
||||
const queueInstance = queue;
|
||||
setTimeout(() => {
|
||||
if (mediaGroupQueues.get(queueKey) === queueInstance && !queueInstance.processingStarted) {
|
||||
|
||||
@@ -37,7 +37,7 @@ import {
|
||||
import { getUniqueStoredName } from '../utils/fileUtils.js';
|
||||
import { buildStorageFolderWithRules, getStoragePathRules, getTelegramBatchFolderName, getTelegramChatName, isOpaqueTelegramIdentifier } from '../utils/storagePath.js';
|
||||
import { resolveTelegramGeneratedFileName } from '../utils/telegramNaming.js';
|
||||
import { annotateTelegramMediaGroup, createTelegramMediaGroupDebouncer, getForwardedSourceLookup, prefetchForwardedSourceMessages, takePendingMediaGroupSnapshot, telegramMediaGroupQueueKey, type ForwardedSourceMessageCache } from '../utils/telegramMediaGroup.js';
|
||||
import { annotateTelegramMediaGroup, createTelegramMediaGroupDebouncer, getForwardedSourceLookup, getOrCreateTelegramMediaGroupQueue, prefetchForwardedSourceMessages, takePendingMediaGroupSnapshot, telegramMediaGroupQueueKey, type ForwardedSourceMessageCache } from '../utils/telegramMediaGroup.js';
|
||||
import { resolveTelegramStorageFolderPersistent, resolveTelegramTaskStorageFolderPersistent, previewTelegramStorageFolderPersistent } from '../utils/telegramPathSettings.js';
|
||||
import { consumeOrGetTelegramTargetState } from '../utils/telegramTargetStateStore.js';
|
||||
import { findDuplicateFile, getDuplicateMode } from '../utils/duplicatePolicy.js';
|
||||
@@ -1388,6 +1388,7 @@ interface MediaGroupQueue {
|
||||
|
||||
// 多文件上传队列 (key: mediaGroupId)
|
||||
const mediaGroupQueues = new Map<string, MediaGroupQueue>();
|
||||
const mediaGroupQueueCreations = new Map<string, Promise<MediaGroupQueue>>();
|
||||
|
||||
// 多文件上传动态 debounce:每收到同组新消息后重置短等待窗口,同时设置最大等待兜底,避免已收齐相册还固定等 1.5s。
|
||||
const mediaGroupDebouncer = createTelegramMediaGroupDebouncer({
|
||||
@@ -2586,14 +2587,14 @@ export async function handleFileUpload(client: TelegramClient, event: NewMessage
|
||||
await checkAndResetSession(client, message.chatId);
|
||||
}
|
||||
const queueKey = telegramMediaGroupQueueKey(message.chatId, mediaGroupId);
|
||||
let queue = mediaGroupQueues.get(queueKey);
|
||||
if (!queue) {
|
||||
const existingQueue = mediaGroupQueues.get(queueKey) || mediaGroupQueueCreations.has(queueKey);
|
||||
const queue = await getOrCreateTelegramMediaGroupQueue(mediaGroupQueues, mediaGroupQueueCreations, queueKey, async () => {
|
||||
const chatKey = message.chatId?.toString() || String(senderId);
|
||||
const selectedTarget = await consumeOrGetTelegramTargetState(chatKey);
|
||||
const storageTarget = selectedTarget
|
||||
? storageManager.getTarget(selectedTarget.provider, selectedTarget.accountId)
|
||||
: storageManager.getActiveTarget();
|
||||
queue = {
|
||||
return {
|
||||
mediaGroupId,
|
||||
queueKey,
|
||||
chatId: message.chatId,
|
||||
@@ -2605,7 +2606,8 @@ export async function handleFileUpload(client: TelegramClient, event: NewMessage
|
||||
createdAt: Date.now(),
|
||||
lastAddedAt: Date.now(),
|
||||
};
|
||||
mediaGroupQueues.set(queueKey, queue);
|
||||
});
|
||||
if (!existingQueue) {
|
||||
const queueInstance = queue;
|
||||
setTimeout(() => {
|
||||
if (mediaGroupQueues.get(queueKey) === queueInstance && !queueInstance.processingStarted) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
createTelegramMediaGroupDebouncer,
|
||||
|
||||
getForwardedSourceLookup,
|
||||
getOrCreateTelegramMediaGroupQueue,
|
||||
prefetchForwardedSourceMessages,
|
||||
takePendingMediaGroupSnapshot,
|
||||
telegramMediaGroupQueueKey,
|
||||
@@ -83,6 +84,27 @@ function testPendingSnapshotSkipsProcessedAndDuplicateMessages() {
|
||||
assert.deepEqual(takePendingMediaGroupSnapshot(items).map(item => item.message.id), [2, 3]);
|
||||
}
|
||||
|
||||
async function testConcurrentAlbumMessagesShareOneQueueCreation() {
|
||||
const queues = new Map<string, { processingStarted: boolean; files: number[] }>();
|
||||
const creations = new Map<string, Promise<{ processingStarted: boolean; files: number[] }>>();
|
||||
let createCount = 0;
|
||||
let releaseCreation!: () => void;
|
||||
const creationGate = new Promise<void>(resolve => { releaseCreation = resolve; });
|
||||
const create = async () => {
|
||||
createCount += 1;
|
||||
await creationGate;
|
||||
return { processingStarted: false, files: [] };
|
||||
};
|
||||
|
||||
const pending = Array.from({ length: 6 }, () => getOrCreateTelegramMediaGroupQueue(queues, creations, 'chat:album', create));
|
||||
releaseCreation();
|
||||
const resolved = await Promise.all(pending);
|
||||
|
||||
assert.equal(createCount, 1);
|
||||
assert.equal(queues.size, 1);
|
||||
assert.ok(resolved.every(queue => queue === resolved[0]));
|
||||
}
|
||||
|
||||
async function testForwardedSourceLookupUsesOneFetchPerPeer() {
|
||||
const peerA = { className: 'PeerChannel', channelId: { toString: () => '100' } };
|
||||
const peerB = { className: 'PeerChannel', channelId: { toString: () => '200' } };
|
||||
@@ -117,6 +139,7 @@ async function main() {
|
||||
await testAnnotatesMixedMediaInTelegramMessageOrder();
|
||||
await testQueueKeySeparatesChatsWithSameGroupedId();
|
||||
testPendingSnapshotSkipsProcessedAndDuplicateMessages();
|
||||
await testConcurrentAlbumMessagesShareOneQueueCreation();
|
||||
await testForwardedSourceLookupUsesOneFetchPerPeer();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,6 +51,27 @@ export function telegramMediaGroupQueueKey(chatId: unknown, mediaGroupId: string
|
||||
return `${chatId === undefined || chatId === null ? 'unknown' : String(chatId)}:${mediaGroupId}`;
|
||||
}
|
||||
|
||||
export async function getOrCreateTelegramMediaGroupQueue<T>(
|
||||
queues: Map<string, T>,
|
||||
creations: Map<string, Promise<T>>,
|
||||
queueKey: string,
|
||||
create: () => Promise<T>,
|
||||
): Promise<T> {
|
||||
const existing = queues.get(queueKey);
|
||||
if (existing) return existing;
|
||||
const inFlight = creations.get(queueKey);
|
||||
if (inFlight) return inFlight;
|
||||
|
||||
const creation = create().then(queue => {
|
||||
queues.set(queueKey, queue);
|
||||
return queue;
|
||||
}).finally(() => {
|
||||
creations.delete(queueKey);
|
||||
});
|
||||
creations.set(queueKey, creation);
|
||||
return creation;
|
||||
}
|
||||
|
||||
function firstCaptionLine(message: TelegramMediaGroupItemContext['message']): string {
|
||||
return String(message.message || message.text || message.caption || '').split(/\r?\n/)[0].trim();
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user