Generate visual representations of the networks underlying video-gamebooks on YouTube https://youtube-maze.delab.re/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

81 lines
2.0 KiB

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 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] === statusPending)
{
res.header('Refresh', '5');
res.send('Exploration in progress… Please wait.');
}
else if (cache[videoId] === statusError)
{
res.status(500).send('Error');
}
else
{
res.send(cache[videoId]);
}
}
else
{
cache[videoId] = statusPending;
res.header('Refresh', '1');
res.send('Exploration in progress… Please wait.');
try
{
const graph = await exploreVideos(req.params.videoId);
const graphviz = toGraphviz(...graph);
const svg = await toSVG(graphviz);
cache[videoId] = svg;
}
catch (err)
{
console.error(err);
cache[videoId] = statusError;
}
}
});