youtube-maze/routes/mazes.mjs

93 lines
2.4 KiB
JavaScript

import express from 'express';
import { exploreVideos, toGraphviz } from '../lib/explore.mjs';
import { toSVG } from '../lib/graphviz.mjs';
const router = express.Router();
export default router;
const statusDone = Symbol('DONE');
const statusPending = Symbol('PENDING');
const statusError = Symbol('ERROR');
const cache = Object.create(null);
// Extract the video ID from a YouTube URL
const YOUTUBE_URL_REGEX = /(?:https?:\/\/)?(?:www\.)?youtube\.com\/watch\?v=([^?&]+)/;
const YOUTUBE_SHORT_URL_REGEX = /(?:https?:\/\/)?(?:www\.)?youtu\.be\/([^?&]+)/;
router.post('/', (req, res) => {
if (req.body.url === '')
{
res.redirect('/');
return;
}
const url = req.body.url.match(YOUTUBE_URL_REGEX);
if (url !== null)
{
res.redirect(`/mazes/${url[1]}`);
return;
}
const shortURL = req.body.url.match(YOUTUBE_SHORT_URL_REGEX);
if (shortURL !== null)
{
res.redirect(`/mazes/${shortURL[1]}`);
return;
}
res.redirect(`/mazes/${req.body.url}`);
});
// Generate the graph for a given video ID
router.get('/:videoId', async (req, res) => {
const {videoId} = req.params;
if (videoId in cache)
{
if (cache[videoId][0] === statusPending)
{
res.header('Refresh', '5');
res.send(`Exploration in progress, please wait.<br>
${cache[videoId][1]}`);
}
else if (cache[videoId][0] === statusError)
{
res.status(500).send('Error');
}
else
{
res.send(cache[videoId][1]);
}
}
else
{
cache[videoId] = [statusPending, 'Starting exploration'];
res.header('Refresh', '1');
res.send('Exploration in progress, please wait.');
try
{
const graph = await exploreVideos(req.params.videoId, (done, rem) =>
{
cache[videoId] = [
statusPending,
`${done} videos explored, ${rem} pending`
];
});
cache[videoId] = [statusPending, 'Converting graph to SVG'];
const graphviz = toGraphviz(...graph);
const svg = await toSVG(graphviz);
cache[videoId] = [statusDone, svg];
}
catch (err)
{
console.error(err);
cache[videoId] = [statusError];
}
}
});