···1616DEFAULT_CRON_SCHEDULE=0 */1 * * *
1717IMAGES_PER_INTERVAL=1
18181919+# Recache Cron Schedule
2020+# How often to run the recache process (default: every day at 3:30am)
2121+RECACHE_CRON_SCHEDULE=30 3 * * *
2222+1923# Queue Configuration
2024# QUEUE_FILE_PATH=/path/to/custom/queue.json
2125
+58-28
bot/telegrambot/commands/recache.js
···11const queueManager = require('../../../queue/queueManager');
22const mediaCache = require('../../../utils/mediaCache');
33+const fs = require('fs-extra');
44+const path = require('path');
3546/**
55- * /recache command handler
77+ * /recache command handler and scheduled recache logic
68 */
79class RecacheCommand {
810 constructor(bot, authHelper) {
···1820 return;
1921 }
2022 this.bot.sendMessage(chatId, 'Recaching missing images and files. This may take a while...');
2121- try {
2222- const queue = await queueManager.getQueue();
2323- let recachedCount = 0;
2424- for (let i = 0; i < queue.length; i++) {
2525- const item = queue[i];
2626- // Support both single and multiple images
2727- const urls = [];
2828- if (item.sourceImgUrl) urls.push(item.sourceImgUrl);
2929- if (Array.isArray(item.originalImageUrls)) urls.push(...item.originalImageUrls);
3030- if (item.downloadUrl && !urls.includes(item.downloadUrl)) urls.push(item.downloadUrl);
3131- if (item.originalImageUrl && !urls.includes(item.originalImageUrl)) urls.push(item.originalImageUrl);
3232- // Remove duplicates
3333- const uniqueUrls = [...new Set(urls.filter(Boolean))];
3434- for (const url of uniqueUrls) {
3535- try {
3636- const result = await mediaCache.processMediaUrl(url, item.isVideo);
3737- // Optionally update imageUrl/imageUrls if missing or invalid
3838- // (not overwriting if already present and valid)
3939- // Could add logic here if needed
4040- recachedCount++;
4141- } catch (err) {
4242- // Log but continue
4343- console.error(`Failed to recache for queue item: ${item.title || item.id} (${url}):`, err.message);
2323+ const { processed, removed } = await RecacheCommand.runScheduledRecache();
2424+ this.bot.sendMessage(chatId, `Recache complete. Processed ${processed} queue items. Removed ${removed} items after 3 failed attempts.`);
2525+ });
2626+ }
2727+2828+ /**
2929+ * Run recache for missing files, remove items after 3 failures
3030+ * Can be called from a scheduler (does not require bot instance)
3131+ * @returns {Promise<{processed: number, removed: number}>}
3232+ */
3333+ static async runScheduledRecache() {
3434+ const queue = await queueManager.getQueue();
3535+ let processed = 0;
3636+ let removed = 0;
3737+ // Track indices to remove after loop to avoid index shifting
3838+ const indicesToRemove = [];
3939+ for (let i = 0; i < queue.length; i++) {
4040+ const item = queue[i];
4141+ // Gather all relevant URLs
4242+ const urls = [];
4343+ if (item.sourceImgUrl) urls.push(item.sourceImgUrl);
4444+ if (Array.isArray(item.originalImageUrls)) urls.push(...item.originalImageUrls);
4545+ if (item.downloadUrl && !urls.includes(item.downloadUrl)) urls.push(item.downloadUrl);
4646+ if (item.originalImageUrl && !urls.includes(item.originalImageUrl)) urls.push(item.originalImageUrl);
4747+ const uniqueUrls = [...new Set(urls.filter(Boolean))];
4848+ let allFilesExist = true;
4949+ for (const url of uniqueUrls) {
5050+ // Determine expected cache path
5151+ const hash = mediaCache.getHashedFilename(url);
5252+ const ext = mediaCache.getFileExtension(url);
5353+ const isVideo = item.isVideo;
5454+ const dir = isVideo ? mediaCache.videoDir : mediaCache.imageDir;
5555+ const filePath = path.join(dir, `${hash}${ext}`);
5656+ const exists = await fs.pathExists(filePath);
5757+ if (!exists) {
5858+ allFilesExist = false;
5959+ try {
6060+ await mediaCache.processMediaUrl(url, isVideo);
6161+ // Reset failure count on success
6262+ if (item._recacheFailures) item._recacheFailures = 0;
6363+ } catch (err) {
6464+ item._recacheFailures = (item._recacheFailures || 0) + 1;
6565+ if (item._recacheFailures >= 3) {
6666+ indicesToRemove.push(i);
6767+ break; // No need to try other URLs for this item
4468 }
4569 }
4670 }
4747- this.bot.sendMessage(chatId, `Recache complete. Processed ${queue.length} queue items. Attempted to recache ${recachedCount} files.`);
4848- } catch (error) {
4949- this.bot.sendMessage(chatId, `Error during recache: ${error.message}`);
5071 }
5151- });
7272+ processed++;
7373+ }
7474+ // Remove items in reverse order to avoid index shifting
7575+ indicesToRemove.sort((a, b) => b - a);
7676+ for (const idx of indicesToRemove) {
7777+ queue.splice(idx, 1);
7878+ removed++;
7979+ }
8080+ if (removed > 0) await queueManager.saveQueueToDisk();
8181+ return { processed, removed };
5282 }
5383}
5484