MCPcopy Create free account
hub / github.com/DialmasterOrg/Youtarr / backfillFromCompleteList

Method backfillFromCompleteList

server/modules/jobModule.js:623–822  ·  view source on GitHub ↗
()

Source from the content-addressed store, hash-verified

621
622 // Backfill Videos and channelvideos tables from complete.list and jobs info JSON
623 async backfillFromCompleteList() {
624 try {
625 const archivePath = path.join(__dirname, '../../config', 'complete.list');
626 let archiveContent;
627 try {
628 archiveContent = await fsPromises.readFile(archivePath, 'utf-8');
629 } catch (e) {
630 if (e && e.code === 'ENOENT') {
631 logger.info('No complete.list found for backfill. Skipping.');
632 return;
633 }
634 throw e;
635 }
636
637 const lines = archiveContent
638 .split(/\r?\n/)
639 .map((l) => l.trim())
640 .filter(Boolean);
641
642 const ids = lines
643 .map((line) => line.split(' ')[1])
644 .filter(Boolean);
645
646 let videosUpserts = 0;
647 let channelVideosUpserts = 0;
648 const missingInfoIds = [];
649
650 // Build fast lookup sets of existing youtube IDs to avoid overwriting fresher DB data
651 const existingVideos = await Video.findAll({ attributes: ['youtubeId'] });
652 const existingVideoIdSet = new Set(existingVideos.map(v => v.youtubeId));
653 const existingChannelVideos = await ChannelVideo.findAll({ attributes: ['youtube_id'] });
654 const existingChannelVideoIdSet = new Set(existingChannelVideos.map(cv => cv.youtube_id));
655
656 // Build candidate list first (IDs needing backfill in either table),
657 // starting from newest entries at the end of complete.list
658 const candidates = [];
659 for (let i = ids.length - 1; i >= 0; i--) {
660 const id = ids[i];
661 const needsVideo = !existingVideoIdSet.has(id);
662 const needsChannelVideo = !existingChannelVideoIdSet.has(id);
663 // Always include in candidates - we may need to update media_type on existing records
664 candidates.push({ id, needsVideo, needsChannelVideo });
665 }
666
667 // Cap per run to 300 items
668 const maxPerRun = 300;
669 const capped = candidates.slice(0, maxPerRun);
670
671 let processed = 0;
672 for (const { id, needsVideo, needsChannelVideo } of capped) {
673 const infoPath = path.join(__dirname, `../../jobs/info/${id}.info.json`);
674
675 let info;
676 try {
677 const content = await fsPromises.readFile(infoPath, 'utf-8');
678 info = JSON.parse(content);
679 } catch (e) {
680 if (e && e.code === 'ENOENT') {

Callers 3

constructorMethod · 0.95
scheduleDailyBackfillMethod · 0.95
jobModule.test.jsFile · 0.80

Calls 1

Tested by

no test coverage detected