nm3clol-express-app/app/helpers/functions.mts

208 lines
8.6 KiB
TypeScript

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', '<br/>'); // convert \n to <br/>
}
return webvttText;
};
const renderArchive = (html: string, paths: string[]) => {
// Header and Footer content
const headHeaderContent = ``;
const headFooterContent = `
<!-- Dynamically Inserted Code by ${getSiteName()} -->
<style>
.__archived__content__, .__archived__content__ p { background-color: #f44336; color: #fff; font-size: 12pt; font-family: "Noto Serif", Times, "Times New Roman", serif; text-align: center; }
.__archived__content__ h1 { font-family: "Cinzel Decorative", Verdana, Arial, sans-serif; color: #fff; font-weight: 700; font-size: 18pt; text-align: center; }
.__archived__content__ h2 { font-family: "Covered By Your Grace", Verdana, Arial, sans-serif; color: #fff; font-weight: 700; font-size: 18pt; text-align: center; }
.__archived__content__ { padding: 2rem; }
.__archived__content__:first-of-type { margin-top: 0; margin-bottom: 0; }
.__archived__content__:last-of-type { margin-top: 1rem; margin-bottom: 0; }
.__archived__content__ .__archived__content__ p { margin-top: 1rem; }
.__archived__content__ a:link, .__archived__content__ a:visited { color: #fff; }
.__archived__content__ a:hover, .__archived__content__ a:active { text-decoration: none; }
.__archived__content__ ::selection {
background-color: #fff;
color: #f44336;
}
.__archived__content__ ::-moz-selection {
background-color: #fff;
color: #f44336;
}
</style>
<link href="https://fonts.googleapis.com/css?family=Cinzel+Decorative:100,200,300,400,500,600,700,800,900" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Covered+By+Your+Grace:100,200,300,400,500,600,700,800,900" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Noto+Serif:100,200,300,400,500,600,700,800,900" rel="stylesheet">
<!-- Google tag (gtag.js) -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-HQR3Z1EZQM"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-HQR3Z1EZQM');
</script>
<script async src="https://pagead2.googlesyndication.com/pagead/js/adsbygoogle.js?client=ca-pub-8937572456576531" crossorigin="anonymous"></script>
<!-- End dynamically inserted code -->
`;
const bodyHeaderContent = `
<!-- Dynamically Inserted Code by ${getSiteName()} -->
<div class="__archived__content__">
<h1>${getSiteName()}</h1>
<h2>Archived Web Site</h2>
<p>
This is an archived version of the original website. Online features will not be functional. Do not submit any personal information to this archive.
</p>
<p>
<a href="./">Current Directory Listing</a> | <a href="/">Back to Library Home</a>
</p>
</div>
<!-- End dynamically inserted code -->
`;
const bodyFooterContent = `
<!-- Dynamically Inserted Code by ${getSiteName()} -->
<div class="__archived__content__">
<p>
This is an archived version of the original website. Online features will not be functional. Do not submit any personal information to this archive.
</p>
<p>
<a href="./">Current Directory Listing</a> | <a href="/">Back to Library Home</a>
</p>
</div>
<!-- End dynamically inserted code -->
`;
// Add archive branding
html = html.substring(0, html.indexOf('>', html.indexOf('<head')) + '>'.length) + headHeaderContent + html.substring(html.indexOf('>', html.indexOf('<head')) + '>'.length);
html = html.substring(0, html.indexOf('</head>') + '</head>'.length) + headFooterContent + html.substring(html.indexOf('</head>') + '</head>'.length);
html = html.substring(0, html.indexOf('>', html.indexOf('<body')) + '>'.length) + bodyHeaderContent + html.substring(html.indexOf('>', html.indexOf('<body')) + '>'.length);
html = html.substring(0, html.indexOf('</body>') + '</body>'.length) + bodyFooterContent + html.substring(html.indexOf('</body>') + '</body>'.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,
};