console.log(`Loading nm3clol-express-app directory router module...`); import { config } from '../config.mjs'; import express from 'express'; import serve from './vercel-serve.mjs'; import path from 'path'; import { globSync } from 'glob'; import matter from 'gray-matter'; import ejs from 'ejs'; import helpers from '../helpers/functions.mjs'; import fs from 'fs'; import { readFile } from 'fs/promises'; import { Breadcrumb } from '../helpers/breadcrumbs.mjs'; export default function () { const pageRouter = express.Router(); // // Serve static files (CSS, JavaScript, images, etc.) // app.use(serve('../public', { // dotfiles: 'ignore', // index: false, // })); // app.get('/', (req, res) => { // res.send('Hello World!'); // }) // console.log("Setting route for /ads.txt"); // app.get('/ads.txt', (req, res) => { // res.setHeader("Content-Type", "text/plain"); // res.setHeader("Cache-Control", "no-cache"); // res.send(`google.com, pub-8937572456576531, DIRECT, f08c47fec0942fa0`); // }); console.log(`Serving /robots.txt from memory.`); pageRouter.get('/robots.txt', (req, res) => { res.setHeader("Content-Type", "text/plain"); res.setHeader("Cache-Control", "no-cache"); // TODO: Implement Site Map feature and provide sitemap url in robots.txt res.send( `User-agent: * Allow: / # TODO: Implement Site Map feature and provide sitemap url in robots.txt #sitemap: https://no-moss-3-carbo-landfill-library.online/sitemap.xml` );//end of res.send() for robots.txt }); // Endpoints for all the site's pages. console.log(`Scanning for pages in ${config.pagesPath} to create routes.`); globSync('**/*.md', { cwd: config.pagesPath, matchBase: true, follow: true, }).forEach((filePath) => { const expressRoutePathFromFilePath = (filePath: string) => { filePath = filePath.substring(0, filePath.length - path.extname(filePath).length).replaceAll(path.sep, path.posix.sep); if (!filePath.startsWith('/') && filePath.length > 0) { filePath = `/${filePath}`; } return filePath; }; const route = expressRoutePathFromFilePath(filePath); const fullFilePath = path.join(config.pagesPath, filePath); let paths = route.split(path.posix.sep); console.log(`Serving ${route} route as a page at ${fullFilePath}.`); pageRouter.get(route, async (req, res) => { const fm = matter.read(fullFilePath); const fmData = { fm: fm.data, excerpt: fm.excerpt }; const content = helpers.md.render(fm.content, fmData ); let breadcrumbs: Breadcrumb[] = []; paths.forEach((path, index) => { if (index == 0) { breadcrumbs.push({ title: config.siteName, url: '/' }); } else { breadcrumbs.push({ title: fmData.fm['title']||path.replaceAll('_', ' ').replaceAll('-', ' '), url: helpers.trimSlashes(helpers.leftTrimFirstDirectory(path)) }); } }); const renderData = { breadcrumbs, content, filePath, fullFilePath, paths, req, route, ...fmData }; res.render("page", { h: helpers, ...renderData }); }); }); // console.log("Scanning for documents to create routes."); // glob.globSync('**/*{.pdf,.docx,.xlsx,.pptx,.doc,.xls,.ppt}', { // cwd: path.join(config.publicPath), // matchBase: true, // follow: true, // }).forEach((filePath) => { // const expressRoutePathFromFilePath = (filePath) => { // return filePath.substring(0, filePath.length - path.extname(filePath).length).replaceAll(path.sep, path.posix.sep); // }; // const route = expressRoutePathFromFilePath(filePath); // const fullFilePath = path.join(config.publicPath, filePath); // let paths = route.split(path.posix.sep); // paths[0] = 'public'; // console.log(`Setting route for ${route}`); // app.get(route, async (req, res) => { // const fm = matter.read(fullFilePath); // const fmData = { fm: fm.data, excerpt: fm.excerpt }; // const content = helpers.md.render(fm.content, fmData ); // const renderData = { content, route, filePath, fullFilePath, req, paths, ...fmData }; // res.render("page", { h: helpers, ...renderData }); // }); // }); //TODO: Rewrite this facility so that it utilizes Git index as a filesystem. console.log("Scanning for web archive HTML documents to create routes."); globSync('Web_Site_Archives/**/*{.htm,.html}', { cwd: config.publicPath, matchBase: true, follow: true, }).forEach((filePath) => { const expressRoutePathFromFilePath = (filePath: string) => { return '/' + filePath.replaceAll(path.sep, path.posix.sep); }; const route = expressRoutePathFromFilePath(filePath); const fullFilePath = path.join(config.publicPath, filePath); let paths = route.split(path.posix.sep); paths[0] = 'public'; console.log(`Setting route for ${route}`); pageRouter.get(route, async (req, res) => { const html = fs.readFileSync(fullFilePath).toString(); const renderData = { route, filePath, fullFilePath, req, paths, html }; res.render("archive", { h: helpers, ...renderData }); }); }); //TODO: Rewrite this facility so that it utilizes Git index as a filesystem. console.log("Scanning for archived videos to create routes."); globSync(['Russell_County/Board_of_Supervisors/YouTube_Archive/**/*.info.json', 'Virginia_Energy/YouTube_Archive/**/*.info.json', 'Virginia_Governor/**/*.info.json'], { cwd: config.publicPath, matchBase: true, follow: true, }).forEach((filePath: string) => { const expressRoutePathFromFilePath = (filePath: string) => { return path.posix.sep+filePath.substring(0, filePath.lastIndexOf(path.sep)).replaceAll(path.sep, path.posix.sep); }; const dirFromFilePath = (filePath: string) => { return filePath.substring(0, filePath.lastIndexOf(path.sep)); } const directory = dirFromFilePath(filePath); let videoURL = ""+globSync("*.{mpg,mpeg,mp4,mkv,webm}", { cwd: path.join(config.publicPath, directory), matchBase: true, follow: true, }).pop(); let subtitleURL = ""+globSync("*.en.vtt", { cwd: path.join(config.publicPath, directory), matchBase: true, follow: true, }).pop(); let subtitleFile = path.join(config.publicPath, directory, subtitleURL); const route = encodeURI(expressRoutePathFromFilePath(filePath)); let paths = filePath .substring(0, filePath.lastIndexOf(path.sep) > 0 ? filePath.lastIndexOf(path.sep) : filePath.length-1) .split(path.sep) .map((name, idx, aPaths) => { let url = aPaths.slice(0, idx+1).join(path.posix.sep); return { name, url, }; }); const fullFilePath = path.join(config.publicPath, filePath); console.log(`Setting route for ${route}`); pageRouter.get(route, async (req, res) => { if (!req.path.endsWith('/')) { res.redirect(req.path + '/'); } else { let info = JSON.parse((await readFile(fullFilePath)).toString()); let subtitleVTT = fs.existsSync(subtitleFile) ? (await readFile(subtitleFile)).toString() : ''; const renderData = { route, filePath, fullFilePath, req, paths, directory: path.join('public', directory), videoURL, subtitleURL, subtitleVTT, info }; res.render("video-player", { h: helpers, ...renderData }); } }); }); //app.get('/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding**', rewriter.rewrite('/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding/$1')); console.log(`Serving /vendor/**/* route for all files in ${path.join(config.assetsPath, 'vendor')}`);; pageRouter.get('/vendor/**/*', async (req, res) => { await serve(req, res, { public: config.assetsPath, symlinks: true, trailingSlash: true, cleanUrls: false, renderSingle: false, unlisted: [ ".DS_Store", ".git", "Thumbs.db", "README*", ], }); }); console.log(`Serving /css/*.css route for all files in ${path.join(config.assetsPath, 'css')}`);; pageRouter.get('/css/*.css', async (req, res) => { await serve(req, res, { public: config.assetsPath, symlinks: true, trailingSlash: true, cleanUrls: false, renderSingle: false, unlisted: [ ".DS_Store", ".git", "Thumbs.db", "README*", ], }); }); console.log(`Serving /svg/*.svg route for all files in ${path.join(config.assetsPath, 'svg')}`);; pageRouter.get('/svg/*.svg', async (req, res) => { await serve(req, res, { public: config.assetsPath, symlinks: true, trailingSlash: true, cleanUrls: false, renderSingle: false, unlisted: [ ".DS_Store", ".git", "Thumbs.db", "README*", ], }); }); //TODO: Rewrite this facility so that it utilizes Git index as a filesystem. console.log(`Serving * default route for all files in ${config.publicPath}`);; pageRouter.get('*', async (req, res) => { await serve(req, res, { public: config.publicPath, symlinks: true, trailingSlash: true, cleanUrls: false, renderSingle: false, unlisted: [ ".*", //dot files/folders "Thumbs.db" ], redirects: [ { source: "/:year(\d{4})-:mo(\d{2})-:dd(\d{2})_:hh(\d{2})_:mm(\d{2})/", destination: "/Web_Site_Archives/Russell_County_Web_Site-:year-:mo-:dd_:hh_:mm/" }, { source: "/OCR-Encoded-PDFs", destination: "/Web_Site_Archives" }, { source: "/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding.zip", destination: "/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding.zip" }, { source: "/OCR-Encoded-PDFs/Russell-County-Web-Site_2024-02-13_19_50_Modified-With-OCR-Encoding/:u(.*)", destination: "/Web_Site_Archives/Russell_County_Web_Site-2024-02-13_19_50_Modified_With_OCR_Encoding:u" }, { source: '/YouTube Channel', destination: '/Russell_County/Board_of_Supervisors/YouTube_Archive/@russellcountyvirginia8228' }, // { source: '/YouTube Channel.zip', destination: '/Russell_County_BOS/YouTube_Channel.zip' }, // { source: '/YouTube Channel/:u?', destination: '/Russell_County_BOS/YouTube_Channel/:u' }, { source: '/Project Reclaim [WI19KR9Ogwg].mkv', destination: '/YouTube_Archives/@VADMME/Project Reclaim [WI19KR9Ogwg].mkv' }, ] }); }); return pageRouter; };