forked from nm3clol/nm3clol-express-app
Updated design, added Video feature, working on documents feature.
This commit is contained in:
parent
9947355d32
commit
9dbe87e166
|
@ -8,6 +8,7 @@ const matter = require('gray-matter');
|
|||
const ejs = require('ejs');
|
||||
const helpers = require('../views/helpers/functions');
|
||||
const search = require('../routes/search');
|
||||
const fs = require('fs');
|
||||
// const advancedSearch = require('../routes/advanced-search');
|
||||
|
||||
// Port number for HTTP server
|
||||
|
@ -57,7 +58,7 @@ Allow: /
|
|||
});
|
||||
|
||||
// Search endpoints
|
||||
console.log("Setting route for /search");
|
||||
console.log("Setting routes for /search");
|
||||
app.use('/search', search.router);
|
||||
// app.use('/advanced-search', advancedSearch.router);
|
||||
|
||||
|
@ -85,9 +86,32 @@ glob.globSync('pages/**/*.md', {
|
|||
});
|
||||
});
|
||||
|
||||
console.log("Scanning for documents to create routes");
|
||||
glob.globSync('**/*{.pdf,.docx,.xlsx,.pptx,.doc,.xls,.ppt}', {
|
||||
cwd: path.join(__dirname, '..', 'public'),
|
||||
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(__dirname, '..', 'public', 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 });
|
||||
});
|
||||
});
|
||||
|
||||
// Endpoints for all the site's YouTube videos.
|
||||
console.log("Scanning for archived videos to create routes");
|
||||
glob.globSync('Russell_County/Board_of_Supervisors/YouTube_Archive/**/*.info.json', {
|
||||
glob.globSync(['Russell_County/Board_of_Supervisors/YouTube_Archive/**/*.info.json', 'Virginia_Energy/YouTube_Archive/**/*.info.json'], {
|
||||
cwd: path.join(__dirname, '..', 'public'),
|
||||
matchBase: true,
|
||||
follow: true,
|
||||
|
@ -99,16 +123,17 @@ glob.globSync('Russell_County/Board_of_Supervisors/YouTube_Archive/**/*.info.jso
|
|||
return filePath.substring(0, filePath.lastIndexOf(path.sep));
|
||||
}
|
||||
const directory = dirFromFilePath(filePath);
|
||||
let videoURL = glob.globSync("*.{mpg,mpeg,mp4,mkv,webm}", {
|
||||
let videoURL = ""+glob.globSync("*.{mpg,mpeg,mp4,mkv,webm}", {
|
||||
cwd: path.join(__dirname, '..', 'public', directory),
|
||||
matchBase: true,
|
||||
follow: true,
|
||||
}).pop();
|
||||
let subtitleURL = glob.globSync("*.en.vtt", {
|
||||
let subtitleURL = ""+glob.globSync("*.en.vtt", {
|
||||
cwd: path.join(__dirname, '..', 'public', directory),
|
||||
matchBase: true,
|
||||
follow: true,
|
||||
}).pop();
|
||||
let subtitleFile = path.join(__dirname, '..', 'public', 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);
|
||||
paths = paths.map((name, idx, aPaths) => {
|
||||
|
@ -122,13 +147,48 @@ glob.globSync('Russell_County/Board_of_Supervisors/YouTube_Archive/**/*.info.jso
|
|||
console.log(`Setting route for ${route}`);
|
||||
app.get(route, async (req, res) => {
|
||||
let info = require(fullFilePath);
|
||||
const renderData = { route, filePath, fullFilePath, req, paths, directory, videoURL, subtitleURL, info };
|
||||
res.render("video-player", { h: helpers, ...renderData });
|
||||
let subtitleVTT = fs.existsSync(subtitleFile)?fs.readFileSync(subtitleFile, 'utf8'):undefined;
|
||||
const renderData = { route, filePath, fullFilePath, req, paths, directory, videoURL, subtitleURL, subtitleVTT, info };
|
||||
res.render("video-player", { h: helpers, require, ...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(`Setting routes for /css/*.css`);;
|
||||
app.get('/css/*.css', async (req, res) => {
|
||||
await serve(req, res, {
|
||||
public: path.join(__dirname, '..', 'static'),
|
||||
symlinks: true,
|
||||
trailingSlash: true,
|
||||
cleanUrls: false,
|
||||
renderSingle: false,
|
||||
unlisted: [
|
||||
".DS_Store",
|
||||
".git",
|
||||
"Thumbs.db",
|
||||
// "README*",
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`Setting routes for /svg/*.svg`);;
|
||||
app.get('/svg/*.svg', async (req, res) => {
|
||||
await serve(req, res, {
|
||||
public: path.join(__dirname, '..', 'static'),
|
||||
symlinks: true,
|
||||
trailingSlash: true,
|
||||
cleanUrls: false,
|
||||
renderSingle: false,
|
||||
unlisted: [
|
||||
".DS_Store",
|
||||
".git",
|
||||
"Thumbs.db",
|
||||
// "README*",
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
console.log(`Setting route for *`);
|
||||
app.get('*', async (req, res) => {
|
||||
await serve(req, res, {
|
||||
|
@ -140,7 +200,8 @@ app.get('*', async (req, res) => {
|
|||
unlisted: [
|
||||
".DS_Store",
|
||||
".git",
|
||||
"README*"
|
||||
"Thumbs.db",
|
||||
// "README*",
|
||||
],
|
||||
redirects: [
|
||||
{
|
||||
|
@ -159,9 +220,9 @@ app.get('*', async (req, res) => {
|
|||
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_BOS/YouTube_Channel' },
|
||||
{ source: '/YouTube Channel.zip', destination: '/Russell_County_BOS/YouTube_Channel.zip' },
|
||||
{ source: '/YouTube Channel/:u?', destination: '/Russell_County_BOS/YouTube_Channel/:u' },
|
||||
{ source: '/YouTube Channel', destination: '/Russell_County/Board_of_Supervisors/YouTube_Channel' },
|
||||
// { 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' },
|
||||
]
|
||||
});
|
||||
|
|
|
@ -48,7 +48,10 @@ const errorTemplate = (vals) => {
|
|||
|
||||
const isDirectoryOrDirectorySymbolicLink = (path, max_recursion_depth = 10, cb) => {
|
||||
lstat(path, {}, (err, sym_stats) => {
|
||||
if (sym_stats.isSymbolicLink() && max_recursion_depth > 0) {
|
||||
if (err) {
|
||||
cb(err);
|
||||
}
|
||||
else if (sym_stats.isSymbolicLink() && max_recursion_depth > 0) {
|
||||
readlink(path, {}, (err, path) => {
|
||||
isDirectoryOrDirectorySymbolicLink(path, max_recursion_depth-1, cb);
|
||||
});
|
||||
|
|
180
gulpfile.js
180
gulpfile.js
|
@ -13,6 +13,7 @@ const relPathToFiles = './public';
|
|||
const baseUrl = 'https://no-moss-3-carbo-landfill-library.online'; // URL of the document to download and index
|
||||
const tikaUrl = 'http://solr.services.cleveland.daball.me:9998'; // URL of the Tika instance
|
||||
const solrUrl = 'http://solr.services.cleveland.daball.me:8983/solr/my_core'; // URL of your Solr instance
|
||||
const solrVirginiaLawUrl = 'http://solr.services.cleveland.daball.me:8983/solr/va_code'; // URL of your Solr instance
|
||||
|
||||
// Task to clear out previous Solr data
|
||||
gulp.task('index:clear', async () => {
|
||||
|
@ -44,6 +45,19 @@ async function calculateSHA256Hash(filePath) {
|
|||
});
|
||||
}
|
||||
|
||||
// Function to retrieve metadata of a file from Solr
|
||||
async function retrieveVirginiaLawMetadataFromSolr(url) {
|
||||
// Retrieve metadata from Solr based on the file URL or unique identifier
|
||||
// const response = await axios.get(`${solrUrl}/select?q=id:"${encodeURIComponent(url)}"&fl=${encodeURIComponent('sha256sum, content_length')}`, {
|
||||
// responseType: 'json'
|
||||
// });
|
||||
const fl = encodeURIComponent("sha256sum, content_length");
|
||||
const q = encodeURIComponent("id:")+"\""+encodeURIComponent(url)+"\"";//encodeURIComponent(`id:"${url}"`);
|
||||
const uri = `${solrVirginiaLawUrl}/select?q=${q}&fl=${fl}`;
|
||||
const response = await request({ uri: `${uri}`, json: true });
|
||||
return response && response.response && response.response.docs && response.response.docs[0];
|
||||
}
|
||||
|
||||
// Function to retrieve metadata of a file from Solr
|
||||
async function retrieveMetadataFromSolr(url) {
|
||||
// Retrieve metadata from Solr based on the file URL or unique identifier
|
||||
|
@ -71,6 +85,20 @@ async function indexDocumentInSolr(document) {
|
|||
}
|
||||
}
|
||||
|
||||
async function indexLawDocumentInSolr(document) {
|
||||
try {
|
||||
// Send document to Solr using the Solr REST API or a Solr client library
|
||||
// Example code to send document using Axios:
|
||||
await axios.post(solrVirginiaLawUrl + '/update/json/docs', document, {
|
||||
params: {
|
||||
commit: true, // Commit changes immediately
|
||||
},
|
||||
});
|
||||
} catch (error) {
|
||||
throw new Error('Error indexing document in Solr: ' + error.message);
|
||||
}
|
||||
}
|
||||
|
||||
function extToMime(file_name) {
|
||||
switch (path.extname(file_name)) {
|
||||
case '.htm':
|
||||
|
@ -80,6 +108,8 @@ function extToMime(file_name) {
|
|||
return 'application/pdf';
|
||||
case '.md':
|
||||
case '.txt':
|
||||
case '.mkv':
|
||||
return 'video/x-matroska';
|
||||
default:
|
||||
return 'text/plain';
|
||||
}
|
||||
|
@ -87,17 +117,12 @@ function extToMime(file_name) {
|
|||
|
||||
|
||||
// Task to index files into Solr
|
||||
gulp.task('index:docs', async () => {
|
||||
gulp.task('index:laws', async () => {
|
||||
//let scanExts = ''; //set to empty string to scan all
|
||||
let scanExts = '.{pdf,docx,pptx,xlsx,jpg,png,txt}';
|
||||
let globs = [
|
||||
'Potesta_&_Associates/**/*.{pdf, docx, jpg, png, txt}',
|
||||
// 'Russell_County_BOS/Documents/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Russell_County_BOS/Meetings/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Russell_County_BOS/Ordinances/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Russell_County_IDA/Meetings/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Russell_County_Tourism/Agenda/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Russell_County_Tourism/Minutes/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'United_Mine_Workers_of_America/**/*.{pdf, docx, jpg, png, txt}',
|
||||
'Virginia_Energy/**/*.{pdf, docx, jpg, png, txt}',
|
||||
`Russell_County/Ordinances/**/*${scanExts}`,
|
||||
`Virginia_Law_Library/**/*${scanExts}`,
|
||||
];
|
||||
// Use glob to match files in the local directories
|
||||
let files = [];
|
||||
|
@ -121,7 +146,7 @@ gulp.task('index:docs', async () => {
|
|||
console.log('URL: ' + url);
|
||||
|
||||
// Retrieve metadata of the file from Solr (if it exists)
|
||||
const metadata = await retrieveMetadataFromSolr(url);
|
||||
const metadata = await retrieveVirginiaLawMetadataFromSolr(url);
|
||||
|
||||
// Calculate file size
|
||||
const stats = fs.statSync(fileFullPath);
|
||||
|
@ -152,7 +177,7 @@ gulp.task('index:docs', async () => {
|
|||
});
|
||||
|
||||
// Use the TikaClient's pipe method to extract text content
|
||||
await client.pipe(f, writableStream, 'text/plain', path.basename(file));
|
||||
await client.pipe(f, writableStream, 'text/plain', encodeURI(path.basename(file)));
|
||||
console.log("Extracted Text:", extractedText);
|
||||
|
||||
// Create Solr document
|
||||
|
@ -167,6 +192,129 @@ gulp.task('index:docs', async () => {
|
|||
// Add additional fields as needed (e.g., title, author, etc.)
|
||||
};
|
||||
|
||||
// Send document to Solr for indexing
|
||||
// Index the file with its text content and metadata
|
||||
console.log(`Indexing ${url}`);
|
||||
await indexLawDocumentInSolr(solrDocument);
|
||||
|
||||
// Continue
|
||||
console.log(`Done.`);
|
||||
} else {
|
||||
// Metadata matches, skip the file
|
||||
console.log(`Skipping file '${file}' as metadata matches existing metadata in Solr index.`);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Task to index files into Solr
|
||||
gulp.task('index:docs', async () => {
|
||||
//let scanExts = ''; //set to empty string to scan all
|
||||
let scanExts = '.{pdf,docx,pptx,xlsx,jpg,png,txt,mkv}';
|
||||
let globs = [
|
||||
`Amys_Drop_Box/**/*${scanExts}`,
|
||||
`CRS_Reports/**/*${scanExts}`,
|
||||
`Mine_Safety_and_Health_Administration/**/*${scanExts}`,
|
||||
`Potesta_&_Associates/**/*${scanExts}`,
|
||||
`Russell_County/**/*${scanExts}`,
|
||||
`Russell_County_Reclamation_LLC/**/*${scanExts}`,
|
||||
`Tobacco_Region_Revitalization_Commission/**/*${scanExts}`,
|
||||
`United_Mine_Workers_of_America/**/*${scanExts}`,
|
||||
`Virginia_Energy/**/*${scanExts}`,
|
||||
// I want to put Virginia Law in its own search category first.
|
||||
// `Virginia_Law_Library/**/*${scanExts}`,
|
||||
];
|
||||
// Use glob to match files in the local directories
|
||||
let files = [];
|
||||
let cwd = path.resolve(__dirname, relPathToFiles.replaceAll('/', path.sep));
|
||||
globs.forEach(async (globPattern) => {
|
||||
files = files.concat(glob.globSync(globPattern, {
|
||||
cwd,
|
||||
matchBase: true,
|
||||
follow: true,
|
||||
}));
|
||||
});
|
||||
console.log(`Found ${files.length} files to index using ${globs.length} glob patterns.`);
|
||||
// Loop through each file and process them
|
||||
for (let f = 0; f < files.length; f++) {
|
||||
const file = files[f];
|
||||
console.log(`${f+1}/${files.length}: ${file}`);
|
||||
|
||||
const fileFullPath = path.join(cwd, file);
|
||||
|
||||
let url = `https://no-moss-3-carbo-landfill-library.online/${file.replaceAll(path.sep, '/')}`;
|
||||
console.log('URL: ' + url);
|
||||
|
||||
// Retrieve metadata of the file from Solr (if it exists)
|
||||
const metadata = await retrieveMetadataFromSolr(url);
|
||||
|
||||
// Calculate file size
|
||||
const stats = fs.statSync(fileFullPath);
|
||||
const fileSize = stats.size;
|
||||
|
||||
// Calculate SHA256 checksum
|
||||
// const checksum = crypto.createHash('sha256').update(fileContents).digest('hex');
|
||||
const checksum = await calculateSHA256Hash(fileFullPath);
|
||||
|
||||
// Compare metadata
|
||||
if (!metadata || parseInt(metadata.content_length[0]) != fileSize || metadata.sha256sum[0] != checksum) {
|
||||
// Metadata mismatch or file not found in Solr, proceed with indexing
|
||||
console.log(`Processing text from file using Tika.`);
|
||||
const client = new TikaClient({ host: tikaUrl });
|
||||
const version = await client.getVersion();
|
||||
console.info(`Tika Server Version: ${version}`);
|
||||
|
||||
let extractedText = '';
|
||||
|
||||
let subtitleExt = ".en.vtt";
|
||||
if (url.endsWith(".webm") || url.endsWith(".mkv") || url.endsWith(".mpg") || url.endsWith(".mpeg") || url.endsWith(".mp4")) {
|
||||
let subtitleFilePath = fileFullPath.substring(0, fileFullPath.lastIndexOf('.')) + subtitleExt;
|
||||
if (fs.existsSync(subtitleFilePath)) {
|
||||
console.log("Found VTT subtitle file at:", subtitleFilePath);
|
||||
extractedText = fs.readFileSync(subtitleFilePath, 'utf8');
|
||||
url = url.substring(0, url.lastIndexOf('/')+1);
|
||||
}
|
||||
else {
|
||||
console.log("No subtitles found at: ", subtitleFilePath);
|
||||
console.log("Skipping this video file. Not adding this to the index until subtitles are available.")
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Create a Readable stream for the file contents
|
||||
let f = fs.createReadStream(fileFullPath);
|
||||
// Create a writable stream to capture the extracted text content into a string
|
||||
const writableStream = new Writable({
|
||||
write(chunk, encoding, callback) {
|
||||
extractedText += chunk.toString(); // Append the chunk to the extracted text
|
||||
callback();
|
||||
}
|
||||
});
|
||||
// Use the TikaClient's pipe method to extract text content
|
||||
await client.pipe(f, writableStream, 'text/plain', encodeURI(path.basename(file)));
|
||||
}
|
||||
if (!extractedText) {
|
||||
console.log("Skipping document because no text was detected.");
|
||||
continue;
|
||||
}
|
||||
else if (extractedText.length < 100) {
|
||||
console.log("Extracted Text:", extractedText);
|
||||
}
|
||||
else {
|
||||
console.log("Extracted Text (excerpt):", extractedText.substring(0, 99));
|
||||
}
|
||||
|
||||
// Create Solr document
|
||||
const solrDocument = {
|
||||
id: url, // Replace with a unique identifier for the document
|
||||
text: extractedText, // Add the extracted text content
|
||||
sha256sum: checksum, // Add the checksum
|
||||
//html: response.data,
|
||||
url: url,
|
||||
content_length: fileSize,
|
||||
content_type: extToMime(url),
|
||||
// Add additional fields as needed (e.g., title, author, etc.)
|
||||
};
|
||||
|
||||
// Send document to Solr for indexing
|
||||
// Index the file with its text content and metadata
|
||||
console.log(`Indexing ${url}`);
|
||||
|
@ -181,11 +329,11 @@ gulp.task('index:docs', async () => {
|
|||
}
|
||||
});
|
||||
|
||||
// Task to optionally run both clearing and indexing
|
||||
gulp.task('index:reindex', gulp.series('index:clear', 'index:docs'));
|
||||
|
||||
// Default task to run indexing
|
||||
gulp.task('index', gulp.series('index:docs'));
|
||||
gulp.task('index', gulp.series('index:docs', 'index:laws'));
|
||||
|
||||
// Task to optionally run both clearing and indexing
|
||||
gulp.task('index:reindex', gulp.series('index:clear', 'index'));
|
||||
|
||||
// Default task to run indexing
|
||||
gulp.task('default', gulp.series('index'));
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
"index": "gulp index",
|
||||
"index:clear": "gulp index:clear",
|
||||
"index:docs": "gulp index:docs",
|
||||
"index:laws": "gulp index:laws",
|
||||
"index:reindex": "gulp index:reindex"
|
||||
},
|
||||
"author": "",
|
||||
|
|
230
static/css/nm3clol.css
Normal file
230
static/css/nm3clol.css
Normal file
|
@ -0,0 +1,230 @@
|
|||
.result-highlight { background-color: #FBF719; font-weight: normal; }
|
||||
.pt-1500 { padding-top: 100vh; }
|
||||
:root {
|
||||
--bs-body-font-size: 1.2rem !important;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
font-family: "Saira Extra Condensed", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
p, li {
|
||||
font-family: "Noto Serif", "Times New Roman", Times, serif;
|
||||
}
|
||||
#files li {
|
||||
font-family: inherit;
|
||||
}
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
font-family: "Alegreya SC", system-ui, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||
font-weight: 700;
|
||||
}
|
||||
.list-group-item {
|
||||
background-color: transparent;
|
||||
}
|
||||
.list-group-item-action:focus,.list-group-item-action:hover {
|
||||
background-color: rgba(244, 67, 54, 0.75);
|
||||
color: #fff;
|
||||
}
|
||||
.list-group-item-action:focus a,.list-group-item-action:hover a:visited {
|
||||
background-color: rgba(244, 67, 54, 0.75);
|
||||
color: #fff;
|
||||
}
|
||||
.list-group-item-action:focus a:focus,.list-group-item-action:hover a:hover {
|
||||
color: #fff !important;
|
||||
text-decoration: underline;
|
||||
}
|
||||
.bg-primary {
|
||||
background-color: #f44336 !important;
|
||||
}
|
||||
.nmc3clol-navbar-brand {
|
||||
font-family: "Cinzel Decorative";
|
||||
text-transform: capitalize !important;
|
||||
}
|
||||
.daball-navbar-brand {
|
||||
font-family: "Saira Extra Condensed";
|
||||
}
|
||||
main {
|
||||
max-width: 100vw;
|
||||
margin-top: 50px;
|
||||
}
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.nm3clol-navbar-brand, .navbar {
|
||||
font-size: 1.2rem !important;
|
||||
}
|
||||
@media (min-width: 0px) and (max-width: 576px) {
|
||||
.nm3clol-navbar-brand, .navbar {
|
||||
font-size: 0.55rem !important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 576px) and (max-width: 768px) {
|
||||
.nm3clol-navbar-brand, .navbar {
|
||||
font-size: 0.75rem !important;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) and (max-width: 1200px) {
|
||||
.nm3clol-navbar-brand, .navbar {
|
||||
font-size: 1.0rem !important;
|
||||
}
|
||||
}
|
||||
.btn-outline-search {
|
||||
color: #fff;
|
||||
border-color: #fff;
|
||||
}
|
||||
.btn-outline-search:hover {
|
||||
color: #f44336;
|
||||
border-color: #f44336;
|
||||
background-color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
h1 i {
|
||||
font-style: normal;
|
||||
}
|
||||
ul#files {
|
||||
margin: 0 0 0 -2px;
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
ul#files li {
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
ul#files a {
|
||||
color: #000;
|
||||
padding: 10px 5px;
|
||||
margin: 0 -5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
a {
|
||||
color: #f44336;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
}
|
||||
a:hover, a:active {
|
||||
color: #0076FF;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
}
|
||||
a .pretty, a .cool {
|
||||
display: none;
|
||||
}
|
||||
a:hover .david, a:active .david, a:hover .cool, a:active .cool {
|
||||
display: inline;
|
||||
color: #0076FF;
|
||||
}
|
||||
a:hover .allen, a:active .allen {
|
||||
display: inline;
|
||||
color: #fff;
|
||||
}
|
||||
a:hover .ball, a:active .ball, a:hover .pretty, a:active .pretty {
|
||||
display: inline;
|
||||
color: #f44336;
|
||||
}
|
||||
svg {
|
||||
height: 13px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
ul#files a::before {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
line-height: 12px;
|
||||
}
|
||||
/* file-icon – svg inlined here, but it should also be possible to separate out. */
|
||||
ul#files a.file::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='black'/></svg>");
|
||||
}
|
||||
ul#files a.file:hover::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='white'/></svg>");
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* folder-icon */
|
||||
ul#files a.folder::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='20' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M18.784 3.87a1.565 1.565 0 0 0-.565-.356V2.426c0-.648-.523-1.171-1.15-1.171H8.996L7.908.25A.89.89 0 0 0 7.302 0H2.094C1.445 0 .944.523.944 1.171v2.3c-.21.085-.398.21-.565.356a1.348 1.348 0 0 0-.377 1.004l.398 9.83C.42 15.393 1.048 16 1.8 16h15.583c.753 0 1.36-.586 1.4-1.339l.398-9.83c.021-.313-.125-.69-.397-.962zM1.843 3.41V1.191c0-.146.104-.272.25-.272H7.26l1.234 1.088c.083.042.167.104.293.104h8.282c.125 0 .25.126.25.272V3.41H1.844zm15.54 11.712H1.78a.47.47 0 0 1-.481-.46l-.397-9.83c0-.147.041-.252.125-.356a.504.504 0 0 1 .377-.147H17.78c.125 0 .272.063.377.147.083.083.125.209.125.334l-.418 9.83c-.021.272-.23.482-.481.482z' fill='black'/></svg>");
|
||||
}
|
||||
ul#files a.folder:hover::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='20' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M18.784 3.87a1.565 1.565 0 0 0-.565-.356V2.426c0-.648-.523-1.171-1.15-1.171H8.996L7.908.25A.89.89 0 0 0 7.302 0H2.094C1.445 0 .944.523.944 1.171v2.3c-.21.085-.398.21-.565.356a1.348 1.348 0 0 0-.377 1.004l.398 9.83C.42 15.393 1.048 16 1.8 16h15.583c.753 0 1.36-.586 1.4-1.339l.398-9.83c.021-.313-.125-.69-.397-.962zM1.843 3.41V1.191c0-.146.104-.272.25-.272H7.26l1.234 1.088c.083.042.167.104.293.104h8.282c.125 0 .25.126.25.272V3.41H1.844zm15.54 11.712H1.78a.47.47 0 0 1-.481-.46l-.397-9.83c0-.147.041-.252.125-.356a.504.504 0 0 1 .377-.147H17.78c.125 0 .272.063.377.147.083.083.125.209.125.334l-.418 9.83c-.021.272-.23.482-.481.482z' fill='white'/></svg>");
|
||||
}
|
||||
/* image-icon */
|
||||
ul#files a.file.gif::before,
|
||||
ul#files a.file.jpg::before,
|
||||
ul#files a.file.png::before,
|
||||
ul#files a.file.svg::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='16' height='16' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='black' stroke-width='5' stroke-linecap='round' stroke-linejoin='round'><rect x='6' y='6' width='68' height='68' rx='5' ry='5'/><circle cx='24' cy='24' r='8'/><path d='M73 49L59 34 37 52m16 20L27 42 7 58'/></svg>");
|
||||
}
|
||||
::selection {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
header h1 .separator {
|
||||
font-size: 4.0rem;
|
||||
line-height: 1rem;
|
||||
vertical-align: -.75vh;
|
||||
}
|
||||
@media (max-width: 1200px) {
|
||||
header h1 {
|
||||
font-size: 1.5rem;
|
||||
}
|
||||
header h1 .separator {
|
||||
font-size: 2em;
|
||||
line-height: 1em;
|
||||
vertical-align: -.75vh;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
ul#files {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
/* body {
|
||||
padding: 45px;
|
||||
} */
|
||||
ul#files li {
|
||||
font-size: 16pt;
|
||||
box-sizing: border-box;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
img.no-trash-svg {
|
||||
z-index: -10000;
|
||||
position: fixed;
|
||||
width: 1.5%;
|
||||
opacity: 0.04;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin-top: -0.5vh;
|
||||
margin-left: -1.5vh;
|
||||
transform: scale(35, 35);
|
||||
}
|
||||
|
||||
table {
|
||||
margin-bottom: 5pt;
|
||||
}
|
||||
|
||||
tbody, td, tfoot, th, thead, tr {
|
||||
font-family: 'Sometype Mono';
|
||||
padding: 5pt;
|
||||
}
|
3796
static/svg/no-trash.svg
Normal file
3796
static/svg/no-trash.svg
Normal file
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 98 KiB |
5
sync-youtube-videos.cmd
Normal file
5
sync-youtube-videos.cmd
Normal file
|
@ -0,0 +1,5 @@
|
|||
@echo off
|
||||
S:\bin\yt-dlp.exe -U
|
||||
S:\bin\yt-dlp.exe --live-from-start --yes-playlist -N 8 -R infinite -c --no-force-overwrites --mtime --write-description --write-info-json --write-playlist-metafiles --write-comments --no-cookies-from-browser --cookies S:\srv\www\no-moss-3-carbo-landfill-library.online\youtube-cookies.txt --write-thumbnail --write-all-thumbnails --write-url-link --write-webloc-link --write-desktop-link --progress --video-multistreams --audio-multistreams --write-subs --write-auto-subs --embed-subs --embed-thumbnail --embed-metadata --embed-chapters --embed-info-json -o "S:\srv\www\no-moss-3-carbo-landfill-library.online\YouTube\%%(uploader_id)s\%%(upload_date>%%Y-%%m-%%d)s-%%(title)s\%%(id)s.%%(ext)s" "https://www.youtube.com/@russellcountyvirginia8228"
|
||||
S:\bin\yt-dlp.exe --live-from-start --yes-playlist -N 8 -R infinite -c --no-force-overwrites --mtime --write-description --write-info-json --write-playlist-metafiles --write-comments --no-cookies-from-browser --cookies S:\srv\www\no-moss-3-carbo-landfill-library.online\youtube-cookies.txt --write-thumbnail --write-all-thumbnails --write-url-link --write-webloc-link --write-desktop-link --progress --video-multistreams --audio-multistreams --write-subs --write-auto-subs --embed-subs --embed-thumbnail --embed-metadata --embed-chapters --embed-info-json -o "S:\srv\www\no-moss-3-carbo-landfill-library.online\YouTube\%%(uploader_id)s\%%(upload_date>%%Y-%%m-%%d)s-%%(title)s\%%(id)s.%%(ext)s" "https://www.youtube.com/@VADMME"
|
||||
npm run-script index:docs
|
|
@ -9,21 +9,23 @@
|
|||
|
||||
<%- include('./includes/top-navbar.ejs') %>
|
||||
|
||||
<%- include('./includes/no-trash-svg.ejs') %>
|
||||
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1 class="mt-5">
|
||||
<i> </i>
|
||||
<h1 class="mt-5" style="font-family: 'Covered By Your Grace'">
|
||||
<% paths.forEach(function(value, index) { %>
|
||||
<% if (h.shouldShowDirectorySeparator({index})) { %>
|
||||
<span class="separator">› </span>
|
||||
<% } %>
|
||||
<% if (h.shouldShowWelcomeBanner({paths})) { %>
|
||||
Welcome to <%= h.getDirectoryTitle({directory}) %>
|
||||
<i> </i>
|
||||
Get Informed! Stay Informed!
|
||||
<% } else if (h.shouldOmitLinkOnLastBreadcrumb({paths, index})) { %>
|
||||
<%= h.trimSlashes({path: value.name}) %>
|
||||
<%= h.trimSlashes({path: value.name}).replaceAll('_', ' ') %>
|
||||
<% } else { %>
|
||||
<a href="/<%= value.url %>">
|
||||
<%= h.getDirectoryName({directory: value.name}) %>
|
||||
<%= h.getDirectoryName({directory: value.name}).replaceAll('_', ' ') %>
|
||||
</a>
|
||||
<% } %>
|
||||
<% }); %>
|
||||
|
@ -32,7 +34,7 @@
|
|||
|
||||
<% if (h.directoryContainsReadme({directory})) {%>
|
||||
<div class="row p-4 pb-0 pe-lg-0 pt-lg-5 align-items-center rounded-3 border shadow-lg">
|
||||
<div class="col-lg-7 p-3 p-lg-5 pt-lg-3">
|
||||
<div class="col-lg-12 p-3 p-lg-5 pt-lg-3">
|
||||
<%- h.printReadme({directory}) %>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -36,7 +36,8 @@ const getDirectoryTitle = ({directory}) => {
|
|||
return (directory=="public") ? getSiteName() : `${title} Listing - ${getSiteName()}`;
|
||||
};
|
||||
const getWelcomeBanner = ({directory}) => {
|
||||
return trimSlashes({path: directory.replace("public", `Welcome to ${getSiteName()}`)});
|
||||
//return trimSlashes({path: directory.replace("public", `Welcome to ${getSiteName()}`)});
|
||||
return "Get Informed! Stay Informed!";
|
||||
};
|
||||
const shouldShowDirectorySeparator = ({index}) => (index > 0);
|
||||
const shouldShowWelcomeBanner = ({paths}) => (paths.length == 1);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<nav class="navbar navbar-dark bg-dark sticky-bottom pt-1500 mt-5">
|
||||
<div class="container center">
|
||||
<a class="navbar-brand" href="https://daball.me">A website by David A. Ball.</a>
|
||||
<a class="navbar-brand daball-navbar-brand" href="https://daball.me">A <span class="pretty">pretty</span> <span class="cool">cool</span> website by <span class="david">David</span> <span class="allen">A.</span> <span class="ball">Ball</span>.</a>
|
||||
</div>
|
||||
<div class="container">
|
||||
<p style="text-transform: none; font-weight: 300; justify-content: left; color: #eee; padding-top: 1em; padding-bottom: 1em;">
|
||||
|
|
|
@ -14,143 +14,15 @@
|
|||
<!-- Bootstrap CSS -->
|
||||
<link href="https://daball.me/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Saira+Extra+Condensed:100,200,300,400,500,600,700,800,900" rel="stylesheet">
|
||||
<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=Alegreya+SC: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=Sometype+Mono: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">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300,300i,400,400i,600,600i,700,700i,800,800i" rel="stylesheet">
|
||||
<link href="https://daball.me/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet">
|
||||
<link href="https://daball.me/vendor/devicons/css/devicons.min.css" rel="stylesheet">
|
||||
<link href="https://daball.me/vendor/devicon/devicon.min.css" rel="stylesheet">
|
||||
<link href="https://daball.me/vendor/simple-line-icons/css/simple-line-icons.css" rel="stylesheet">
|
||||
<link href="https://daball.me/layouts/blog/css/blog.min.css" rel="stylesheet">
|
||||
<style type="text/css">
|
||||
.result-highlight { background-color: #FBF719; font-weight: normal; }
|
||||
.pt-1500 { padding-top: 100vh; }
|
||||
:root {
|
||||
--bs-body-font-size: 1.2rem !important;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
background: #fff;
|
||||
font-family: "Saira Extra Condensed", -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
main {
|
||||
max-width: 100vw;
|
||||
margin-top: 50px;
|
||||
}
|
||||
header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
h1 i {
|
||||
font-style: normal;
|
||||
}
|
||||
ul#files {
|
||||
margin: 0 0 0 -2px;
|
||||
padding: 20px 0 0 0;
|
||||
}
|
||||
ul#files li {
|
||||
list-style: none;
|
||||
font-size: 14px;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
ul#files a {
|
||||
color: #000;
|
||||
padding: 10px 5px;
|
||||
margin: 0 -5px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
display: block;
|
||||
width: 100%;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
a {
|
||||
color: #0076FF;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
}
|
||||
a:hover, a:active {
|
||||
color: #f44336;
|
||||
display: inline-block;
|
||||
line-height: 20px;
|
||||
}
|
||||
svg {
|
||||
height: 13px;
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
ul#files a::before {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
margin-right: 10px;
|
||||
width: 24px;
|
||||
text-align: center;
|
||||
line-height: 12px;
|
||||
}
|
||||
/* file-icon – svg inlined here, but it should also be possible to separate out. */
|
||||
ul#files a.file::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M10 8C8.34 8 7 6.66 7 5V1H3c-1.1 0-2 .9-2 2v13c0 1.1.9 2 2 2h9c1.1 0 2-.9 2-2V8h-4zM8 5c0 1.1.9 2 2 2h3.59L8 1.41V5zM3 0h5l7 7v9c0 1.66-1.34 3-3 3H3c-1.66 0-3-1.34-3-3V3c0-1.66 1.34-3 3-3z' fill='black'/></svg>");
|
||||
}
|
||||
ul#files a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
/* folder-icon */
|
||||
ul#files a.folder::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='20' height='16' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M18.784 3.87a1.565 1.565 0 0 0-.565-.356V2.426c0-.648-.523-1.171-1.15-1.171H8.996L7.908.25A.89.89 0 0 0 7.302 0H2.094C1.445 0 .944.523.944 1.171v2.3c-.21.085-.398.21-.565.356a1.348 1.348 0 0 0-.377 1.004l.398 9.83C.42 15.393 1.048 16 1.8 16h15.583c.753 0 1.36-.586 1.4-1.339l.398-9.83c.021-.313-.125-.69-.397-.962zM1.843 3.41V1.191c0-.146.104-.272.25-.272H7.26l1.234 1.088c.083.042.167.104.293.104h8.282c.125 0 .25.126.25.272V3.41H1.844zm15.54 11.712H1.78a.47.47 0 0 1-.481-.46l-.397-9.83c0-.147.041-.252.125-.356a.504.504 0 0 1 .377-.147H17.78c.125 0 .272.063.377.147.083.083.125.209.125.334l-.418 9.83c-.021.272-.23.482-.481.482z' fill='black'/></svg>");
|
||||
}
|
||||
ul#files a.lambda::before {
|
||||
content: url("data:image/svg+xml; utf8,<svg width='15' height='19' fill='none' xmlns='http://www.w3.org/2000/svg'><path d='M3.5 14.4354H5.31622L7.30541 9.81311H7.43514L8.65315 13.0797C9.05676 14.1643 9.55405 14.5 10.7 14.5C11.0171 14.5 11.291 14.4677 11.5 14.4032V13.1572C11.3847 13.1766 11.2622 13.2024 11.1541 13.2024C10.6351 13.2024 10.3829 13.0281 10.1595 12.4664L8.02613 7.07586C7.21171 5.01646 6.54865 4.5 5.11441 4.5C4.83333 4.5 4.62432 4.53228 4.37207 4.59038V5.83635C4.56667 5.81052 4.66036 5.79761 4.77568 5.79761C5.64775 5.79761 5.9 6.0042 6.4045 7.19852L6.64234 7.77954L3.5 14.4354Z' fill='black'/><rect x='0.5' y='0.5' width='14' height='18' rx='2.5' stroke='black'/></svg>");
|
||||
}
|
||||
/* image-icon */
|
||||
ul#files a.file.gif::before,
|
||||
ul#files a.file.jpg::before,
|
||||
ul#files a.file.png::before,
|
||||
ul#files a.file.svg::before {
|
||||
content: url("data:image/svg+xml;utf8,<svg width='16' height='16' viewBox='0 0 80 80' xmlns='http://www.w3.org/2000/svg' fill='none' stroke='black' stroke-width='5' stroke-linecap='round' stroke-linejoin='round'><rect x='6' y='6' width='68' height='68' rx='5' ry='5'/><circle cx='24' cy='24' r='8'/><path d='M73 49L59 34 37 52m16 20L27 42 7 58'/></svg>");
|
||||
}
|
||||
::selection {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
::-moz-selection {
|
||||
background-color: #f44336;
|
||||
color: #fff;
|
||||
}
|
||||
header h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
header h1 .separator {
|
||||
font-size: 4.0rem;
|
||||
line-height: 1rem;
|
||||
vertical-align: -.75vh;
|
||||
}
|
||||
@media (max-width: 1250px) {
|
||||
header h1 {
|
||||
font-size: 1.0rem;
|
||||
}
|
||||
header h1 .separator {
|
||||
font-size: 2em;
|
||||
line-height: 1em;
|
||||
vertical-align: -.75vh;
|
||||
}
|
||||
}
|
||||
@media (min-width: 768px) {
|
||||
ul#files {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
/* body {
|
||||
padding: 45px;
|
||||
} */
|
||||
ul#files li {
|
||||
font-size: 16pt;
|
||||
box-sizing: border-box;
|
||||
justify-content: flex-start;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<link href="/css/nm3clol.css" rel="stylesheet">
|
||||
|
|
18
views/includes/no-trash-svg.ejs
Normal file
18
views/includes/no-trash-svg.ejs
Normal file
|
@ -0,0 +1,18 @@
|
|||
<img id="no-trash-svg" alt="" src="/svg/no-trash.svg" class="no-trash-svg" onload="" />
|
||||
<script>
|
||||
function is_iOS() {
|
||||
return [
|
||||
'iPad Simulator',
|
||||
'iPhone Simulator',
|
||||
'iPod Simulator',
|
||||
'iPad',
|
||||
'iPhone',
|
||||
'iPod'
|
||||
].includes(navigator.platform)
|
||||
// iPad on iOS 13 detection
|
||||
|| (navigator.userAgent.includes("Mac") && "ontouchend" in document)
|
||||
}
|
||||
if (is_iOS() && navigator.userAgent.indexOf('AppleWebKit')) {
|
||||
document.getElementById("no-trash-svg").style.visibility = "hidden";
|
||||
}
|
||||
</script>
|
|
@ -1,16 +1,15 @@
|
|||
<div class="navbar navbar-expand-lg fixed-top navbar-dark bg-primary">
|
||||
<div class="container">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarResponsive" aria-controls="navbarResponsive" aria-expanded="false" aria-label="Toggle navigation"><span class="navbar-toggler-icon"></span></button>
|
||||
<a class="navbar-brand nmc3clol-navbar-brand" href="/">No Moss 3 Carbo Landfill Online Library</a>
|
||||
<div class="collapse navbar-collapse" id="navbarResponsive">
|
||||
<a class="navbar-brand" href="/">No Moss 3 Carbo Landfill Online Library</a>
|
||||
<!-- <ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link" href="/Russell_County_BOS/">Board of Supervisors</a></li>
|
||||
<li class="nav-item"><a class="nav-link" href="/Russell_County_IDA/">IDA</a></li>
|
||||
</ul> -->
|
||||
<ul class="navbar-nav">
|
||||
<li class="nav-item"><a class="nav-link" href="/">Home</a></li>
|
||||
</ul>
|
||||
<!-- Search form -->
|
||||
<form class="d-flex ms-auto" method="get" action="/search">
|
||||
<input class="form-control me-2" type="search" placeholder="Search" aria-label="Search" value="<%=(typeof query !='undefined')?query:''%>" name="q">
|
||||
<button class="btn btn-outline-success" type="submit">Search</button>
|
||||
<button class="btn btn-outline-search" type="submit">Search</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,12 +7,11 @@
|
|||
|
||||
<body onload="initPage()">
|
||||
|
||||
<%- include('./includes/top-navbar.ejs') %>
|
||||
<%- include('./includes/no-trash-svg.ejs') %>
|
||||
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1 class="mt-5">
|
||||
<i> </i>
|
||||
<h1 class="mt-5" style="font-family: 'Covered By Your Grace'">
|
||||
<% paths.forEach(function(value, index) { %>
|
||||
<% if (h.shouldShowDirectorySeparator({index})) { %>
|
||||
<span class="separator">› </span>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
</head>
|
||||
<body>
|
||||
<%- include('./includes/top-navbar.ejs') %>
|
||||
<%- include('./includes/no-trash-svg.ejs') %>
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1 class="mt-5">
|
||||
<i> </i>
|
||||
<h1 class="mt-5" style="font-family: 'Covered By Your Grace'">
|
||||
<a href="/">No Moss 3 Carbo Landfill Online Library</a>
|
||||
<span class="separator">› </span>
|
||||
Search Error<% if ((typeof query != undefined) && query != '') { %> for <%- query %><% } %>
|
||||
|
|
|
@ -6,10 +6,10 @@
|
|||
</head>
|
||||
<body>
|
||||
<%- include('./includes/top-navbar.ejs') %>
|
||||
<%- include('./includes/no-trash-svg.ejs') %>
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1 class="mt-5">
|
||||
<i> </i>
|
||||
<h1 class="mt-5" style="font-family: 'Covered By Your Grace'">
|
||||
<a href="/">No Moss 3 Carbo Landfill Online Library</a>
|
||||
<span class="separator">› </span>
|
||||
Search Results for <%- query %>
|
||||
|
@ -47,7 +47,7 @@
|
|||
</div>
|
||||
<% } %>
|
||||
<!-- Pagination controls -->
|
||||
<% if (typeof totalPages !== "undefined") { %>
|
||||
<% if (typeof totalPages !== "undefined" && totalPages) { %>
|
||||
<nav aria-label="Search results pagination">
|
||||
<ul class="pagination justify-content-center mt-4">
|
||||
<% if (page > 1) { %>
|
||||
|
|
|
@ -8,11 +8,11 @@
|
|||
<body onload="initPage()">
|
||||
|
||||
<%- include('./includes/top-navbar.ejs') %>
|
||||
<%- include('./includes/no-trash-svg.ejs') %>
|
||||
|
||||
<main class="container">
|
||||
<header>
|
||||
<h1 class="mt-5">
|
||||
<i> </i>
|
||||
<h1 class="mt-5" style="font-family: 'Covered By Your Grace'">
|
||||
<% paths.forEach(function(value, index) { %>
|
||||
<% if (h.shouldShowDirectorySeparator({index})) { %>
|
||||
<span class="separator">› </span>
|
||||
|
@ -30,19 +30,50 @@
|
|||
</h1>
|
||||
</header>
|
||||
|
||||
<% if (typeof info !== 'undefined') {%>
|
||||
<% if (typeof videoURL !== 'undefined') {%>
|
||||
<div class="row p-4 pb-0 pe-lg-0 pt-lg-5 align-items-center rounded-3 border shadow-lg">
|
||||
<div class="col-lg-12 p-3 p-lg-5 pt-lg-3">
|
||||
<h1 class="title"><%= (typeof info.title !== 'undefined') ? info.title : "" %> </h1>
|
||||
<h1 class="title"><%= (typeof info.title !== 'undefined') ? info.fulltitle : "" %></h1>
|
||||
<video class="object-fit-fill ratio ratio-16x9" controls allowfullscreen>
|
||||
<source src="<%-videoURL%>">
|
||||
<source src="<%-encodeURI(videoURL)%>">
|
||||
<track
|
||||
label="English"
|
||||
kind="subtitles"
|
||||
srclang="en"
|
||||
src="<%-subtitleURL%>"
|
||||
src="<%-encodeURI(subtitleURL)%>"
|
||||
default />
|
||||
</video>
|
||||
<% if (typeof info !== 'undefined') {%>
|
||||
<p><%=info.description%></p>
|
||||
<p>
|
||||
<b>View Original:</b>
|
||||
<a href="<%=info.webpage_url%>" target="_blank"><%=info.title%> (Video)</a>
|
||||
| <a href="<%=info.channel_url%>" target="_blank"><%=info.channel%> (Channel)</a>
|
||||
| <a href="<%=info.uploader_url%>" target="_blank"><%=info.uploader%> (Uploader)</a>
|
||||
</p>
|
||||
<p>
|
||||
<b>Download/View:</b>
|
||||
<a href="<%=encodeURI(videoURL)%>" target="_blank">Video (.<%=info.ext%>)</a>
|
||||
| <a href="<%=encodeURI(subtitleURL)%>" target="_blank">Subtitles (.vtt)</a>
|
||||
</p>
|
||||
<!-- <pre><%=require('util').inspect(info)%></pre> -->
|
||||
<%}%>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
||||
<% if (typeof subtitleVTT !== 'undefined') {%>
|
||||
<div class="row p-4 pb-0 pe-lg-0 pt-lg-5 align-items-center rounded-3 border shadow-lg" style="max-height:65vh;overflow-y:scroll">
|
||||
<div class="col-lg-12 p-3 p-lg-5 pt-lg-3">
|
||||
<h2 class="title">Video Transcript (approximately)</h1>
|
||||
<p>
|
||||
This transcript may contain automatically generated subtitles as generated using YouTube's
|
||||
automatic subtitles feature. They may not be correct. No effort has been made to correct
|
||||
them (so far). These transcripts, whether or not generated, are also used in the site's
|
||||
Search feature. Please review the <a href="/search-policy" target="_blank">Search Policy</a>
|
||||
for details about the site features.
|
||||
</p>
|
||||
<pre style="white-space:pre-wrap;overflow-wrap:anywhere"><%- subtitleVTT %></pre>
|
||||
</div>
|
||||
</div>
|
||||
<% } %>
|
||||
|
|
Loading…
Reference in New Issue
Block a user