import path from 'path'; // import { globSync } from 'glob'; import fs from 'fs'; import { config } from '../config.mjs'; import markdownIt from 'markdown-it'; import markdownItAttrs from 'markdown-it-attrs'; import momentJs from 'moment-timezone'; import { inspect } from 'util'; import matter from 'gray-matter'; const moment = momentJs.tz.setDefault("UTC"); const md = markdownIt({ html: true, linkify: true, typographer: true, }).use( markdownItAttrs, { // optional, these are default options leftDelimiter: '{', rightDelimiter: '}', allowedAttributes: [] // empty array = all attributes are allowed } ); const getSiteName = () => config.siteName; const trimSlashes = (dirPath: string) => { return dirPath.replace(/^[\/\\]|[\/\\]$/g, ''); }; const getLeftMostDirectory = (directory: string) => { if (directory.indexOf(path.sep)) { return directory.substring(0, directory.indexOf(path.sep)); } return directory; } const leftTrimFirstDirectory = (directory: string) => { if (directory.indexOf(path.sep)) { return directory.substring(directory.indexOf(path.sep)); } return directory; } const getDirectoryName = (directory: string) => { directory = trimSlashes(directory); const leftMostDirectory = getLeftMostDirectory(directory); let title = trimSlashes(leftTrimFirstDirectory(directory)).replaceAll(path.sep, path.posix.sep); return (trimSlashes(directory)==leftMostDirectory) ? getSiteName() : title; }; const getDirectoryTitle = (directory: string) => { const leftMostDirectory = getLeftMostDirectory(directory); let title = trimSlashes(leftTrimFirstDirectory(directory)) .replaceAll(path.sep, path.posix.sep) .replaceAll('_', ' ') .split('/') .reverse() .join(' - '); return (trimSlashes(directory)==leftMostDirectory) ? getSiteName() : `${title} - ${getSiteName()}`; }; const getSiteWelcomeMessage = () => config.siteWelcomeMessage; const shouldShowDirectorySeparator = (index: number) => (index > 0); const shouldShowSiteWelcomeMessage = (paths: string[]) => (paths.length == 1); const shouldOmitLinkOnLastBreadcrumb = (paths: string[], index: number) => (index == paths.length-1); const resolveReadmeFile: (directory: string) => string|undefined = (directory) => { const resolveFile = (file: string) => { const pathToFile = path.join(config.publicPath, trimSlashes(leftTrimFirstDirectory(directory)), file); return fs.existsSync(pathToFile) ? pathToFile : ""; }; return ( resolveFile("README.md") || resolveFile("README.txt") || resolveFile("README") || resolveFile("README.html") || undefined ); }; const directoryContainsReadme = (directory: string) => resolveReadmeFile(directory); // const printMarkdownFile = (file) => { // }; const readmeFm = (directory: string) => { const readmeFile = resolveReadmeFile(directory); if (readmeFile) { return matter.read(readmeFile).data; } }; const printReadme = (directory: string) => { const readmeFile = resolveReadmeFile(directory); if (readmeFile) { const fm = matter.read(readmeFile); const fmData = { fm: fm.data, excerpt: fm.excerpt }; const content = md.render(fm.content, fmData ); return content; } }; const stripWebVTT = (webvttText: string) => { const searchHeader = "WEBVTT\nKind: captions\nLanguage: en\n\n"; if (webvttText.startsWith(searchHeader)) { webvttText = webvttText.substring(searchHeader.length-1); // remove WEBVTT header webvttText = webvttText.replaceAll(' align:start position:0%', ''); // remove this align and position junk webvttText = webvttText .split('\n') .map((line) => { return line.replaceAll(/.*<\d{2}:\d{2}:\d{2}.\d{3}>.*/g, '').trim() }) // remove all the animated subtitles and trim the whitespace on each line .join('\n'); while (webvttText.indexOf('\n\n\n') > -1) { webvttText = webvttText.replace('\n\n\n', '\n\n'); // remove every instance of triple vertical white space, while allowing double vertical white space } webvttText = webvttText.replaceAll(/(\d{2}:\d{2}:\d{2}.\d{3}) --> (\d{2}:\d{2}:\d{2}.\d{3})\n(.*)\n\n(\2) --> (\d{2}:\d{2}:\d{2}.\d{3})\n\3\n/g, '$1 --> $5\n$3\n'); // remove every duplicate entry detected webvttText = webvttText.replaceAll('\n', '
'); // convert \n to
} return webvttText; }; const renderArchive = (html: string, paths: string[]) => { // Header and Footer content const headHeaderContent = ``; const headFooterContent = ` `; const bodyHeaderContent = `

${getSiteName()}

Archived Web Site

This is an archived version of the original website. Online features will not be functional. Do not submit any personal information to this archive.

Current Directory Listing | Back to Library Home

`; const bodyFooterContent = `

This is an archived version of the original website. Online features will not be functional. Do not submit any personal information to this archive.

Current Directory Listing | Back to Library Home

`; // Add archive branding html = html.substring(0, html.indexOf('>', html.indexOf(''.length) + headHeaderContent + html.substring(html.indexOf('>', html.indexOf(''.length); html = html.substring(0, html.indexOf('') + ''.length) + headFooterContent + html.substring(html.indexOf('') + ''.length); html = html.substring(0, html.indexOf('>', html.indexOf(''.length) + bodyHeaderContent + html.substring(html.indexOf('>', html.indexOf(''.length); html = html.substring(0, html.indexOf('') + ''.length) + bodyFooterContent + html.substring(html.indexOf('') + ''.length); // Output the modified HTML content return html; } export default { leftTrimFirstDirectory, trimSlashes, getSiteName, getDirectoryName, getDirectoryTitle, getSiteWelcomeMessage, shouldShowDirectorySeparator, shouldShowSiteWelcomeMessage, shouldOmitLinkOnLastBreadcrumb, directoryContainsReadme, readmeFm, printReadme, stripWebVTT, renderArchive, config, inspect, md, moment, };