diff --git a/backend/src/services/scheduler.ts b/backend/src/services/scheduler.ts index df1b50d..df82cc0 100644 --- a/backend/src/services/scheduler.ts +++ b/backend/src/services/scheduler.ts @@ -1,7 +1,11 @@ -import cron from 'node-cron'; -import { videoOperations, configOperations, channelOperations } from '../db/database'; -import { downloadVideo, getChannelVideos } from './ytdlp'; -import { DownloadProgress } from '../types'; +import cron from "node-cron"; +import { + videoOperations, + configOperations, + channelOperations, +} from "../db/database"; +import { downloadVideo, getChannelVideos } from "./ytdlp"; +import { DownloadProgress } from "../types"; let schedulerTask: cron.ScheduledTask | null = null; let isDownloading = false; @@ -11,7 +15,10 @@ function getRandomVariance(varianceMinutes: number): number { return Math.floor(Math.random() * varianceMinutes * 2) - varianceMinutes; } -function calculateNextRun(intervalMinutes: number, varianceMinutes: number): Date { +function calculateNextRun( + intervalMinutes: number, + varianceMinutes: number, +): Date { const variance = getRandomVariance(varianceMinutes); const totalMinutes = intervalMinutes + variance; @@ -22,22 +29,22 @@ function calculateNextRun(intervalMinutes: number, varianceMinutes: number): Dat async function downloadNextVideo() { if (isDownloading) { - console.log('Already downloading a video, skipping...'); + console.log("Already downloading a video, skipping..."); + return; + } + + isDownloading = true; + currentProgress = null; + + const video = videoOperations.getNextPending(); + if (!video) { + console.log("No pending videos to download"); return; } try { - isDownloading = true; - currentProgress = null; - - const video = videoOperations.getNextPending(); - if (!video) { - console.log('No pending videos to download'); - return; - } - console.log(`Starting download: ${video.title} (${video.videoId})`); - videoOperations.updateStatus(video.id, 'downloading'); + videoOperations.updateStatus(video.id, "downloading"); const result = await downloadVideo(video.videoId, video.url, { onProgress: (progress, speed, eta) => { @@ -45,23 +52,21 @@ async function downloadNextVideo() { videoId: video.videoId, progress, speed, - eta + eta, }; - } + }, }); videoOperations.markCompleted(video.id, result.filePath, result.fileSize); console.log(`Download completed: ${video.title}`); currentProgress = null; - } catch (error) { - console.error('Download error:', error); - const video = videoOperations.getNextPending(); + console.error("Download error:", error); if (video) { videoOperations.updateStatus( video.id, - 'failed', - error instanceof Error ? error.message : 'Unknown error' + "failed", + error instanceof Error ? error.message : "Unknown error", ); } currentProgress = null; @@ -71,7 +76,7 @@ async function downloadNextVideo() { } async function checkChannelsForNewVideos() { - const channels = channelOperations.getAll().filter(c => c.active); + const channels = channelOperations.getAll().filter((c) => c.active); for (const channel of channels) { try { @@ -81,7 +86,7 @@ async function checkChannelsForNewVideos() { for (const videoInfo of videos) { // Check if video already exists const existingVideos = videoOperations.getAll(); - const exists = existingVideos.some(v => v.videoId === videoInfo.id); + const exists = existingVideos.some((v) => v.videoId === videoInfo.id); if (!exists) { console.log(`Found new video: ${videoInfo.title}`); @@ -94,10 +99,10 @@ async function checkChannelsForNewVideos() { duration: videoInfo.duration, thumbnail: videoInfo.thumbnail, uploadDate: videoInfo.uploadDate, - status: 'pending', + status: "pending", filePath: null, fileSize: null, - error: null + error: null, }); } } @@ -111,36 +116,38 @@ async function checkChannelsForNewVideos() { export function startScheduler() { if (schedulerTask) { - console.log('Scheduler already running'); + console.log("Scheduler already running"); return; } const config = configOperations.getAll(); - const enabled = config.enabled === 'true'; + const enabled = config.enabled === "true"; if (!enabled) { - console.log('Scheduler is disabled'); + console.log("Scheduler is disabled"); return; } - const intervalMinutes = parseFloat(config.intervalMinutes || '180'); // Default 180 minutes (3 hours) - const varianceMinutes = parseFloat(config.varianceMinutes || '30'); + const intervalMinutes = parseFloat(config.intervalMinutes || "180"); // Default 180 minutes (3 hours) + const varianceMinutes = parseFloat(config.varianceMinutes || "30"); - console.log(`Starting scheduler: ${intervalMinutes}min ±${varianceMinutes}min`); + console.log( + `Starting scheduler: ${intervalMinutes}min ±${varianceMinutes}min`, + ); // Check for new videos every hour - schedulerTask = cron.schedule('0 * * * *', async () => { - console.log('Checking channels for new videos...'); + schedulerTask = cron.schedule("0 * * * *", async () => { + console.log("Checking channels for new videos..."); await checkChannelsForNewVideos(); }); // Download next video with variable interval async function scheduleNextDownload() { const config = configOperations.getAll(); - const enabled = config.enabled === 'true'; + const enabled = config.enabled === "true"; if (!enabled) { - console.log('Scheduler disabled, stopping...'); + console.log("Scheduler disabled, stopping..."); return; } @@ -148,8 +155,8 @@ export function startScheduler() { await downloadNextVideo(); // AFTER download completes, calculate next run - const intervalMinutes = parseFloat(config.intervalMinutes || '180'); // Default 180 minutes (3 hours) - const varianceMinutes = parseFloat(config.varianceMinutes || '30'); + const intervalMinutes = parseFloat(config.intervalMinutes || "180"); // Default 180 minutes (3 hours) + const varianceMinutes = parseFloat(config.varianceMinutes || "30"); const nextRun = calculateNextRun(intervalMinutes, varianceMinutes); console.log(`Next download scheduled for: ${nextRun.toLocaleString()}`); @@ -161,14 +168,14 @@ export function startScheduler() { // Start the first download cycle scheduleNextDownload(); - console.log('Scheduler started'); + console.log("Scheduler started"); } export function stopScheduler() { if (schedulerTask) { schedulerTask.stop(); schedulerTask = null; - console.log('Scheduler stopped'); + console.log("Scheduler stopped"); } } @@ -181,11 +188,11 @@ export function getSchedulerStatus() { const config = configOperations.getAll(); return { running: schedulerTask !== null, - enabled: config.enabled === 'true', - intervalMinutes: parseFloat(config.intervalMinutes || '180'), - varianceMinutes: parseFloat(config.varianceMinutes || '30'), + enabled: config.enabled === "true", + intervalMinutes: parseFloat(config.intervalMinutes || "180"), + varianceMinutes: parseFloat(config.varianceMinutes || "30"), isDownloading, - currentProgress + currentProgress, }; }