diff --git a/src/services/autogen.js b/src/services/autogen.js index 8d8fa9a..971c524 100644 --- a/src/services/autogen.js +++ b/src/services/autogen.js @@ -202,21 +202,70 @@ async function runAutogen({ forceCategory = null } = {}) { params = [currentHour, currentMinute - 5, currentMinute + 5]; } - const { rows: settings } = await query( - `SELECT * FROM autogen_settings ${whereClause} ORDER BY category`, - params + // Сначала берём ВСЕ активные категории (независимо от времени), + // затем применяем ротацию — выбираем 4 из 8 по дню года. + const { rows: allEnabled } = await query( + `SELECT * FROM autogen_settings WHERE enabled=true ORDER BY sort_order, category`, + [] ); + // Ротация: скользящее окно из 4 категорий сдвигается на 1 каждый день. + // Это гарантирует что за 8 дней каждая категория выйдет минимум 4 раза, + // и каждый день читатель видит другой набор. + const DAILY_COUNT = 4; + const total = allEnabled.length; + let categoriesForToday; + if (total <= DAILY_COUNT) { + // Категорий меньше или равно 4 — берём все + categoriesForToday = allEnabled.map(s => s.category); + } else { + // День года (0..364) определяет сдвиг окна + const now = new Date(); + const start = Date.UTC(now.getUTCFullYear(), 0, 0); + const dayOfYear = Math.floor((now - start) / 86400000); + const offset = dayOfYear % total; + // Берём 4 категории начиная со сдвига (с wrap-around) + categoriesForToday = Array.from({ length: DAILY_COUNT }, (_, i) => + allEnabled[(offset + i) % total].category + ); + console.log( + '[Autogen] Ротация дня ' + dayOfYear + ' (offset=' + offset + '): ' + + categoriesForToday.join(', ') + ); + } + + // Теперь фильтруем по расписанию (если не forceCategory) — категория + // должна быть в списке дня И соответствовать текущему времени. + const { rows: allSettings } = await query( + `SELECT * FROM autogen_settings WHERE enabled=true ORDER BY run_hour, run_minute`, + [] + ); + + let settings; + if (forceCategory) { + settings = allSettings.filter(s => s.category === forceCategory); + } else { + // Время окна ±5 мин уже применено в whereClause — переиспользуем + const { rows: timeFiltered } = await query( + `SELECT * FROM autogen_settings ${whereClause} ORDER BY run_hour, run_minute`, + params + ); + // Оставляем только категории дня из сработавших по времени + const todaySet = new Set(categoriesForToday); + settings = timeFiltered.filter(s => todaySet.has(s.category)); + } + if (!settings.length) { console.log('[Autogen] Nothing to generate at this time'); return { processed: 0, results: [] }; } const results = []; - for (const s of settings) { + for (let i = 0; i < settings.length; i++) { + const s = settings[i]; const result = await runAutogenForCategory(s.category); results.push({ category: s.category, ...result }); - if (settings.indexOf(s) < settings.length - 1) { + if (i < settings.length - 1) { await new Promise(r => setTimeout(r, 5000)); } } @@ -227,6 +276,20 @@ async function runAutogen({ forceCategory = null } = {}) { /** * Получить статус автогенерации. */ +/** + * Возвращает категории которые активны сегодня по ротации (4 из 8). + */ +function getTodayCategories(allCategories, dailyCount = 4) { + if (allCategories.length <= dailyCount) return allCategories.map(c => c.category || c); + const now = new Date(); + const start = Date.UTC(now.getUTCFullYear(), 0, 0); + const dayOfYear = Math.floor((now - start) / 86400000); + const offset = dayOfYear % allCategories.length; + return Array.from({ length: dailyCount }, (_, i) => + (allCategories[(offset + i) % allCategories.length].category || allCategories[(offset + i) % allCategories.length]) + ); +} + async function getAutogenStatus() { const { rows: settings } = await query( `SELECT s.*, c.name as cat_name, c.icon as cat_icon, c.color as cat_color, @@ -252,7 +315,12 @@ async function getAutogenStatus() { LEFT JOIN categories c ON c.slug=s.category ORDER BY s.run_hour, s.category` ); - return settings; + // Добавим флаг today_active — входит ли категория в сегодняшнюю ротацию + const todaySet = new Set(getTodayCategories(settings)); + return settings.map(s => ({ + ...s, + today_active: todaySet.has(s.category), + })); } -module.exports = { runAutogen, runAutogenForCategory, getAutogenStatus, TOPIC_BANK }; +module.exports = { runAutogen, runAutogenForCategory, getAutogenStatus, getTodayCategories, TOPIC_BANK };