import fs from 'fs'; import util from 'util'; import * as api from './api.mjs'; import {graphToDOT} from './graph.mjs'; // Fetch the output path from command line if (process.argv.length !== 4) { console.error(`Usage: ${process.argv[1]} ROOT DEST Explore videos linked from ROOT and write the resulting graph to DEST.`); process.exit(1); } const root = process.argv[2]; const dest = process.argv[3]; // Store metadata about each visited video const videosNodes = Object.create(null); // List of videos linked from each video either through a card or an // endscreen item const nextVideos = Object.create(null); /** * Recursively explore a video and the video linked from it to fill * the video graph. * * @param videoId Source video identifier. */ const exploreVideo = async videoId => { // Make sure we don’t explore the same video twice if (videoId in videosNodes) { return Promise.resolve(); } videosNodes[videoId] = {}; const playerConfig = await api.getPlayerConfig(videoId); videosNodes[videoId] = api.getVideoMeta(playerConfig); nextVideos[videoId] = new Set(); // Add links between this video and the linked ones api.getEndScreenVideos(playerConfig) .forEach(nextId => nextVideos[videoId].add(nextId)); api.getCardVideos(playerConfig) .forEach(nextId => nextVideos[videoId].add(nextId)); // Recurse on linked videos return Promise.all( Array.from(nextVideos[videoId]) .map(id => exploreVideo(id)) ); }; console.log('Starting to explore!'); exploreVideo(root).then(() => { fs.writeFileSync(dest, graphToDOT(videosNodes, nextVideos)); console.log(`Finished. Result in ${dest}`); }).catch(console.error);