Fix issue with videos getting stuck due to other videos failing

This commit is contained in:
Ryan Whytsell 2025-10-21 11:51:07 -04:00
parent d2f9045084
commit 0ba2d85006
Signed by: Epithium
GPG Key ID: 940AC18C08E925EA
1 changed files with 52 additions and 45 deletions

View File

@ -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,
};
}