()
| 518 | } |
| 519 | |
| 520 | async saveJobs() { |
| 521 | if (this.isSaving) { |
| 522 | // If a save operation is already in progress, skip this one |
| 523 | logger.debug('Save operation already in progress, skipping'); |
| 524 | return; |
| 525 | } |
| 526 | this.isSaving = true; // Set the locking variable |
| 527 | logger.debug({ jobCount: Object.keys(this.jobs).length }, 'saveJobs() called - processing jobs'); |
| 528 | |
| 529 | for (let jobId in this.jobs) { |
| 530 | let jobDataOriginal = this.jobs[jobId]; |
| 531 | const jobData = { ...jobDataOriginal }; |
| 532 | |
| 533 | // Extract video data if present (download jobs); non-download jobs may not have data |
| 534 | let videos = []; |
| 535 | if (jobData.data) { |
| 536 | videos = jobData.data.videos ? jobData.data.videos : []; |
| 537 | logger.debug({ jobId, videoCount: videos.length }, 'Job has videos to save'); |
| 538 | delete jobData.data; // Remove videos from job data before DB update |
| 539 | } |
| 540 | |
| 541 | try { |
| 542 | // Find the job in the database. |
| 543 | let jobInstance = await Job.findOne({ where: { id: jobId } }); |
| 544 | |
| 545 | // If the job exists, update it. Otherwise, create it. |
| 546 | if (jobInstance) { |
| 547 | await jobInstance.update(jobData); |
| 548 | } else { |
| 549 | jobInstance = await Job.create(jobData); |
| 550 | } |
| 551 | |
| 552 | // Skip updating video data for completed/terminated jobs to avoid overwriting fresher data |
| 553 | // UNLESS the job is marked as needing save (e.g., after saveJobOnly failed) |
| 554 | const isCompletedJob = jobData.status === 'Complete' || |
| 555 | jobData.status === 'Complete with Warnings' || |
| 556 | jobData.status === 'Error' || |
| 557 | jobData.status === 'Terminated' || |
| 558 | jobData.status === 'Killed'; |
| 559 | |
| 560 | if (isCompletedJob && !jobDataOriginal._needsSave) { |
| 561 | logger.debug({ jobId }, 'Skipping video updates for completed job'); |
| 562 | continue; |
| 563 | } |
| 564 | |
| 565 | if (jobDataOriginal._needsSave) { |
| 566 | logger.debug({ jobId, retryAttempt: jobDataOriginal._saveRetries || 1 }, 'Processing job due to previous save failure'); |
| 567 | // Don't clear flags yet - only clear after successful video processing |
| 568 | } |
| 569 | |
| 570 | // For each video, find it in the database. If it exists, update it. Otherwise, create it. |
| 571 | try { |
| 572 | for (let video of videos) { |
| 573 | logger.debug({ youtubeId: video.youtubeId, title: video.youTubeVideoName }, 'Processing video'); |
| 574 | await this.upsertVideoForJob(video, jobInstance); |
| 575 | |
| 576 | // Also upsert into channelvideos so Channel page reflects downloaded items |
| 577 | try { |
no test coverage detected