Updated design, added Video feature, working on documents feature.
This commit is contained in:
parent
fe78b58b87
commit
50109efaff
|
|
@ -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": "",
|
||||
|
|
|
|||
40
public/Potesta_&_Associates/README.md
Normal file
40
public/Potesta_&_Associates/README.md
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
# Potesta & Associates
|
||||
|
||||
Russell County Board of Supervisors has hired Potesta & Associates to study the feasibility of a landfill at the Moss 3 site that Russell County Reclamation, LLC.
|
||||
|
||||
## History and Overview
|
||||
|
||||
Potesta & Associates, Inc. (POTESTA) is an engineering and environmental consulting firm with offices in Charleston, West Virginia, Morgantown, West Virginia, and Winchester, Virginia. Since its establishment in 1997, POTESTA has provided professional services to a wide range of clients across the eastern United States.
|
||||
|
||||
## Engagement with Russell County
|
||||
|
||||
The company conducted an evaluation of information provided by Russell County Reclamation, LLC (RCR) regarding the proposed landfill project for Russell County. They were hired by the Board of Supervisors.
|
||||
|
||||
## Evaluation of Landfill Feasibility
|
||||
|
||||
Potesta & Associates conducted a review of the site, including an analysis of historical land use, geological conditions, and regulatory requirements. The evaluation focused on factors such as floodplains, geological stability, proximity to water sources, and site characteristics affecting landfill construction and operation.
|
||||
|
||||
## Engineering Considerations
|
||||
|
||||
The evaluation identified several site conditions requiring further engineering analysis, including the stability of coal refuse areas, evaluation of underground mine workings, location of disposal unit boundaries, and assessment of existing coal refuse disposal dams. Potesta & Associates emphasized the importance of addressing these considerations to ensure the environmentally sound development and operation of the landfill.
|
||||
|
||||
## Conclusion and Recommendations
|
||||
|
||||
Potesta & Associates concluded that, at the time of the evaluation, no issues were identified that would render the site "unpermittable" for landfill development. However, the company recommended that Russell County obtain additional detailed information from RCR regarding the identified issues and their proposed solutions before moving forward with the project.
|
||||
|
||||
## Invoices
|
||||
|
||||
The following invoices have been presented by the County Administrator:
|
||||
|
||||
| Invoice # | Invoice Date | Due Date | Gross Amount
|
||||
| --------- | ------------ | ---------- | ------------
|
||||
| 166028 | 1/18/2023 | 2/6/2023 | $22,438.87
|
||||
| 167130 | 8/23/2023 | 9/5/2023 | $14,912.18
|
||||
| 167404 | 10/18/2023 | 11/13/2023 | $8,828.31
|
||||
| 167602 | 11/16/2023 | 12/11/2023 | $5,113.48
|
||||
| 167730 | 12/17/2023 | 1/2/2024 | $180.00
|
||||
| **Total** | | | **$51,472.84**
|
||||
|
||||
## Documents
|
||||
|
||||
The following documents have been provided by Russell County:
|
||||
|
|
@ -1,31 +1,77 @@
|
|||
# Contents
|
||||
|
||||
## [Potesta & Associates](/Potesta_&_Associates)
|
||||
Potesta & Associates has been retained by the Russell County Board of Supervisors to study the feasibility of a landfill.
|
||||
|
||||
## [Russell County Board of Supervisors](/Russell_County_BOS)
|
||||
+ ### [Meetings](/Russell_County_BOS/Meetings)
|
||||
+ #### [Agenda Packets](/Russell_County_BOS/Meetings/Agenda_Packets)
|
||||
+ #### [Agendas](/Russell_County_BOS/Meetings/Agendas)
|
||||
+ #### [Minutes](/Russell_County_BOS/Meetings/Minutes)
|
||||
+ ### [Ordinances](/Russell_County_BOS/Ordinances)
|
||||
+ #### [Solid Waste](/Russell_County_BOS/Ordinances/Solid_Waste)
|
||||
+ ### [YouTube Archive](/Russell_County_BOS/YouTube_Archive)
|
||||
+ #### [@russellcountyvirginia8228](/Russell_County_BOS/YouTube_Archive/@russellcountyvirginia8228)
|
||||
## [Russell County](/Russell_County)
|
||||
Russell County is a county located in the Commonwealth of Virginia. As of the 2020 census, the population was 25,781. Its county seat is Lebanon.
|
||||
|
||||
## [Russell County Industrial Development Authority](/Russell_County_IDA)
|
||||
+ ### [Meetings](/Russell_County_IDA/Meetings)
|
||||
+ #### [Agenda Packets](/Russell_County_IDA/Meetings/Agenda_Packets)
|
||||
+ ### [Audit and Budget Information](/Russell_County/Audit_and_Budget_Information)
|
||||
Annual audits and budget proposals for Russell County.
|
||||
|
||||
## [Russell County Tourism](/Russell_County_Tourism)
|
||||
+ ### [Meetings](/Russell_County_Tourism/Meetings)
|
||||
+ #### [Agenda](/Russell_County_Tourism/Meetings/Agenda)
|
||||
+ #### [Minutes](/Russell_County_Tourism/Meetings/Minutes)
|
||||
+ ### [Board of Supervisors](/Russell_County/Board_of_Supervisors)
|
||||
The Board of Supervisors is a governmental body that oversees the operation of the Russell County government in the Commonwealth of Virginia.
|
||||
|
||||
+ #### [Meetings](/Russell_County/Board_of_Supervisors/Meetings)
|
||||
The Board of Supervisors have regular meetings. These meetings are normally streamed live on YouTube.
|
||||
|
||||
+ ##### [Agenda Packets](/Russell_County/Board_of_Supervisors/Meetings/Agenda_Packets)
|
||||
|
||||
+ ##### [Agendas](/Russell_County/Board_of_Supervisors/Meetings/Agendas)
|
||||
|
||||
+ ##### [Minutes](/Russell_County/Board_of_Supervisors/Meetings/Minutes)
|
||||
|
||||
+ #### [YouTube Archive](/Russell_County/Board_of_Supervisors/YouTube_Archive)
|
||||
|
||||
+ ##### [@russellcountyvirginia8228](/Russell_County/Board_of_Supervisors/YouTube_Archive/@russellcountyvirginia8228)
|
||||
|
||||
+ ### [Industrial Development Authority](/Russell_County/Industrial_Development_Authority)
|
||||
The Industrial Development Authority is the primary organization responsible for economic and industrial development in Russell County. They are appointed by the Board of Supervisors.
|
||||
|
||||
+ #### [Meetings](/Russell_County/Industrial_Development_Authority/Meetings)
|
||||
The Industrial Development Authority have regular meetings. There are no known recordings of these meetings, except for the approved minutes which are contained within the agenda packets.
|
||||
|
||||
+ ##### [Agenda Packets](/Russell_County/Industrial_Development_Authority/Meetings/Agenda_Packets)
|
||||
|
||||
+ ### [Ordinances](/Russell_County/Ordinances)
|
||||
|
||||
+ #### [Cigarette](/Russell_County/Ordinances/Cigarette)
|
||||
|
||||
+ #### [Food and Beverage Tax](/Russell_County/Ordinances/Food_and_Beverage_Tax)
|
||||
|
||||
+ #### [Noise](/Russell_County/Ordinances/Noise)
|
||||
|
||||
+ #### [Redistricting](/Russell_County/Ordinances/Redistricting)
|
||||
|
||||
+ #### [Solid Waste](/Russell_County/Ordinances/Solid_Waste)
|
||||
There are solid waste ordinances from
|
||||
[1984](/Russell_County/Ordinances/Solid_Waste/1984-04-03_Amendment_to_Solid_Waste_Ordinance.pdf),
|
||||
[1985](/Russell_County/Ordinances/Solid_Waste/1985-11-01_Solid_Waste_Ordinance.pdf),
|
||||
[1991](/Russell_County/Ordinances/Solid_Waste/1991-11-18_Solid_Waste_Management_Facility_Prohibition_and_Siting_Ordinance.pdf),
|
||||
[2010](/Russell_County/Ordinances/Solid_Waste/2010_12_06_Russell_County_Solid_Waste_Management_Ordinance.pdf), and
|
||||
[2017](/Russell_County/Ordinances/Solid_Waste/2017-03-13_Russell_County_Solid_Waste_Management_Ordinance.pdf).
|
||||
The language in 2010 alludes to only conditional prohibition ("unless permitted") of private solid waste management facilities, a
|
||||
departure from the 1991 language where private solid waste management facilities were prohibited.
|
||||
|
||||
+ ### [Tourism Committee](/Russell_County/Tourism_Committee)
|
||||
|
||||
+ #### [Meetings](/Russell_County/Tourism_Committee/Meetings)
|
||||
|
||||
+ ##### [Agenda](/Russell_County/Tourism_Committee/Meetings/Agenda)
|
||||
|
||||
+ ##### [Minutes](/Russell_County/Tourism_Committee/Meetings/Minutes)
|
||||
|
||||
## [United Mine Workers of America](/United_Mine_Workers_of_America)
|
||||
United Mine Workers of America adamantly oppose the Moss 3 Landfill.
|
||||
|
||||
+ ### [Art](/United_Mine_Workers_of_America/Art)
|
||||
|
||||
+ ### [Press Releases](/United_Mine_Workers_of_America/Press_Releases)
|
||||
|
||||
## [Virginia Energy](/Virginia_Energy)
|
||||
|
||||
+ ### [Russell County Reclamation, LLC](/Virginia_Energy/Russell_County_Reclamation_LLC)
|
||||
|
||||
+ ### [YouTube Archive](/Virginia_Energy/YouTube_Archive)
|
||||
|
||||
+ #### [@VADMME](/Virginia_Energy/YouTube_Archive/@VADMME)
|
||||
|
|
|
|||
|
|
@ -1,6 +0,0 @@
|
|||
# YouTube Video Archives
|
||||
|
||||
These videos are archives of the videos released to the YouTube channel for Russell County Board of Supervisors.
|
||||
|
||||
The original channel for these videos is
|
||||
[@russellcountyvirginia8228](https://www.youtube.com/@russellcountyvirginia8228).
|
||||
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