You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

170 lines
5.5 KiB

9 months ago
const express = require("express");
const path = require("path");
const fs = require("fs");
const app = express();
// Initial Listing Directory
9 months ago
const listingPath = path.join(__dirname, "public");
// index.html path
const indexPath = path.join(__dirname, "index.html");
// Placeholder in your index.html file where dynamic content will be inserted
const dynamicContentPlaceholder = "<!-- Dynamic Content Placeholder -->";
// Function to read the content of the existing "index.html" file
function readIndexFile() {
return fs.readFileSync(indexPath, "utf-8");
}
// For any path..
9 months ago
app.get("*", (req, res) => {
const decodedPath = decodeURIComponent(req.path);
const filePath = path.join(listingPath, decodedPath);
// Extract the parent directory
const parentDirectory = path.join(req.path, '../');
9 months ago
// Return nothing if path does not exist
9 months ago
if (!fs.existsSync(filePath)) {
return res.status(404).end();
}
// If details of a file directory are returned, create path
9 months ago
if (fs.statSync(filePath).isDirectory()) {
// Read contents of directory
9 months ago
const filesInDir = fs.readdirSync(filePath);
// For each file in the directory
// (1) Encode URI for hyperlinks
// (2) Create HTML for that link
9 months ago
const links = filesInDir.map(file => {
const encodedFile = encodeURIComponent(file);
const fileLink = path.join(req.path, encodedFile);
let linkAttributes = "";
let fileLocationEncoding = ""
let convertedString = fileLink.replace(/\\/g, '/');
let icon = ''
9 months ago
// Check if the file is of a specific type that should open in a new window/tab
const fileExtension = path.extname(file).toLowerCase();
if (isFileTypeToOpenInNewTab(fileExtension)) {
fileLocationEncoding = 'http://localhost:3000/' + convertedString
linkAttributes = `onclick="window.open('${fileLocationEncoding}', 'fileWindow', 'width=600,height=400');"`;
icon = getFileIcon(fileExtension, decodeURIComponent(convertedString))
return `<div class='file' ${linkAttributes}>
${icon}
<span class='info-name'>${file}</span>
</div>`;
9 months ago
} else {
return `<a href="${fileLink}" ${linkAttributes}><div class='folder'><img src='/icons/folder.gif'><span class='info-name'>${file}</span></div></a>`;
9 months ago
}
});
// Read the content of the existing "index.html" file
const indexContent = readIndexFile();
// Replace the placeholder with the dynamically generated content
const finalHtml = indexContent.replace(dynamicContentPlaceholder,
`<div class='index-cont'><span class='index-txt'>Index of ${decodeURIComponent(req.path)}</span>
<a class='return-cont' href='${parentDirectory === '/' ? '/' : parentDirectory}'>
<img src='/icons/back.png'>
<span> Parent Directory </span>
</a>
<span class='line-break'></span>
</div>
<div class='main-cont'>${links.join("")}</div>`);
// Send the modified content as a response
return res.send(finalHtml);
9 months ago
} else {
// If its a 'file' type, then open it in a new window
9 months ago
const fileExtension = path.extname(filePath).toLowerCase();
if (fileExtension === ".pdf") {
// For PDF files, send the file to be displayed in the browser.
const fileStream = fs.createReadStream(filePath);
fileStream.pipe(res);
} else if(fileExtension === ".mp4") {
const fileStream = fs.createReadStream(filePath);
res.set("Content-Type", "video/mp4");
fileStream.pipe(res);
} else if(fileExtension === ".docx") {
const fileStream = fs.createReadStream(filePath);
res.set("Content-Type", "application/vnd.openxmlformats-officedocument.wordprocessingml.document");
fileStream.pipe(res);
} else {
9 months ago
// For other file types, set content type and send file.
const contentType = getContentType(fileExtension);
res.set("Content-Type", contentType);
return res.sendFile(filePath);
}
}
});
// Set file icon
function getFileIcon(fileExtension, filePath){
switch (fileExtension) {
case ".txt":
return "<img src='/icons/generic.gif'>";
case ".png":
return `<img src="${filePath}" alt="${path.basename(filePath)}" class="thumbnail" />`;
case ".jfif":
case ".jpeg":
case ".jpg":
return `<img src="${filePath}" alt="${path.basename(filePath)}" class="thumbnail" />`;
case ".gif":
return `<img src="${filePath}" alt="${path.basename(filePath)}" class="thumbnail" />`;
case ".pdf":
case ".odt":
case ".docx":
return "<img src='/icons/text.png'>"
case ".mp4":
return "<img src='/icons/movie.gif'>"
default:
return "<img src='/icons/unknown.gif'>";
}
}
9 months ago
// Function to get content type based on file extension
function getContentType(fileExtension) {
switch (fileExtension) {
case ".txt":
return "text/plain";
case ".png":
return "image/png";
case ".jpg":
return "image/jpg";
case ".jpeg":
return "image/jpeg";
case ".jfif":
return "image/jpeg";
case ".gif":
return "image/gif";
case ".mp4":
return "video/mp4";
case ".odt":
return "application/vnd.oasis.opendocument.text"
case ".docx":
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
9 months ago
default:
return "application/octet-stream";
}
}
// Function to check if the file type should open in a new window/tab
function isFileTypeToOpenInNewTab(fileExtension) {
const supportedFileTypes = [".pdf", ".png", ".txt", ".mp4", ".jpg", ".jfif", ".gif", ".jpeg", ".odt", ".docx"]; // Add more file types as needed
9 months ago
return supportedFileTypes.includes(fileExtension);
}
const PORT = 3000;
app.listen(PORT, () => {
console.log("Server is running on http://localhost:" + PORT);
});