my nvim and vscode are finally using the same settings
This commit is contained in:
parent
58077a5d63
commit
a5e03facbe
11 changed files with 757 additions and 757 deletions
38
.eslintrc.js
38
.eslintrc.js
|
@ -1,21 +1,21 @@
|
||||||
module.exports = {
|
module.exports = {
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
es2021: true,
|
es2021: true,
|
||||||
node: true,
|
node: true,
|
||||||
},
|
},
|
||||||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
||||||
overrides: [],
|
overrides: [],
|
||||||
parser: "@typescript-eslint/parser",
|
parser: "@typescript-eslint/parser",
|
||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: "latest",
|
ecmaVersion: "latest",
|
||||||
sourceType: "module",
|
sourceType: "module",
|
||||||
},
|
},
|
||||||
plugins: ["@typescript-eslint"],
|
plugins: ["@typescript-eslint"],
|
||||||
rules: {
|
rules: {
|
||||||
indent: ["error", 2, { SwitchCase: 1 }],
|
indent: ["error", 4, { SwitchCase: 1 }],
|
||||||
"linebreak-style": ["error", "unix"],
|
"linebreak-style": ["error", "unix"],
|
||||||
quotes: ["error", "double"],
|
quotes: ["error", "double"],
|
||||||
semi: ["error", "always"],
|
semi: ["error", "always"],
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
142
app/app.ts
142
app/app.ts
|
@ -25,17 +25,17 @@ const server = http.createServer(app);
|
||||||
const port = normalizePort(process.env.EBPORT || "3000");
|
const port = normalizePort(process.env.EBPORT || "3000");
|
||||||
|
|
||||||
function normalizePort(val: string) {
|
function normalizePort(val: string) {
|
||||||
const port = parseInt(val, 10);
|
const port = parseInt(val, 10);
|
||||||
|
|
||||||
if (isNaN(port)) {
|
if (isNaN(port)) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (port >= 0) {
|
if (port >= 0) {
|
||||||
return port;
|
return port;
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.set("port", port);
|
app.set("port", port);
|
||||||
|
@ -44,56 +44,56 @@ server.on("error", onError);
|
||||||
server.on("listening", onListening);
|
server.on("listening", onListening);
|
||||||
|
|
||||||
function onError(error: any) {
|
function onError(error: any) {
|
||||||
if (error.syscall !== "listen") {
|
if (error.syscall !== "listen") {
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bind = typeof port === "string"
|
const bind = typeof port === "string"
|
||||||
? "Pipe " + port
|
? "Pipe " + port
|
||||||
: "Port " + port;
|
: "Port " + port;
|
||||||
|
|
||||||
// handle specific listen errors with friendly messages
|
// handle specific listen errors with friendly messages
|
||||||
switch (error.code) {
|
switch (error.code) {
|
||||||
case "EACCES":
|
case "EACCES":
|
||||||
console.error(bind + " requires elevated privileges");
|
console.error(bind + " requires elevated privileges");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
case "EADDRINUSE":
|
case "EADDRINUSE":
|
||||||
console.error(bind + " is already in use");
|
console.error(bind + " is already in use");
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Check if there is an existing DB or not, then check if it needs to be updated to new schema
|
// Check if there is an existing DB or not, then check if it needs to be updated to new schema
|
||||||
db.get("SELECT * FROM sqlite_master WHERE name ='users' and type='table'", async (err, row) => {
|
db.get("SELECT * FROM sqlite_master WHERE name ='users' and type='table'", async (err, row) => {
|
||||||
if (!row) createDatabase(3);
|
if (!row) createDatabase(3);
|
||||||
else checkVersion();
|
else checkVersion();
|
||||||
});
|
});
|
||||||
|
|
||||||
function checkVersion () {
|
function checkVersion () {
|
||||||
db.get("PRAGMA user_version", (err: Error, row: any) => {
|
db.get("PRAGMA user_version", (err: Error, row: any) => {
|
||||||
if (row && row.user_version) {
|
if (row && row.user_version) {
|
||||||
const version = row.user_version;
|
const version = row.user_version;
|
||||||
if (version != 3) console.log("DATABASE IS OUTDATED");
|
if (version != 3) console.log("DATABASE IS OUTDATED");
|
||||||
updateDatabase(version, 3);
|
updateDatabase(version, 3);
|
||||||
} else {
|
} else {
|
||||||
// Because ver 1 does not have user_version set, we can safely assume that it is ver 1
|
// Because ver 1 does not have user_version set, we can safely assume that it is ver 1
|
||||||
updateDatabase(1, 3);
|
updateDatabase(1, 3);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function onListening() {
|
function onListening() {
|
||||||
const addr = server.address();
|
const addr = server.address();
|
||||||
const bind = typeof addr === "string"
|
const bind = typeof addr === "string"
|
||||||
? "pipe " + addr
|
? "pipe " + addr
|
||||||
: "port " + addr.port;
|
: "port " + addr.port;
|
||||||
console.log("Embedder version: " + version);
|
console.log("Embedder version: " + version);
|
||||||
console.log("Listening on " + bind);
|
console.log("Listening on " + bind);
|
||||||
}
|
}
|
||||||
|
|
||||||
app.enable("trust proxy");
|
app.enable("trust proxy");
|
||||||
|
@ -104,20 +104,20 @@ app.set("view engine", "ejs");
|
||||||
|
|
||||||
app.use(express.json());
|
app.use(express.json());
|
||||||
app.use(express.urlencoded({
|
app.use(express.urlencoded({
|
||||||
extended: false
|
extended: false
|
||||||
}));
|
}));
|
||||||
app.use(cookieParser());
|
app.use(cookieParser());
|
||||||
app.use(express.static(path.join(__dirname, "public")));
|
app.use(express.static(path.join(__dirname, "public")));
|
||||||
|
|
||||||
app.use(express.static(path.join(__dirname, "public")));
|
app.use(express.static(path.join(__dirname, "public")));
|
||||||
app.use(session({
|
app.use(session({
|
||||||
secret: process.env.EBSECRET || "pleasechangeme",
|
secret: process.env.EBSECRET || "pleasechangeme",
|
||||||
resave: false,
|
resave: false,
|
||||||
saveUninitialized: false,
|
saveUninitialized: false,
|
||||||
store: new SQLiteStore({
|
store: new SQLiteStore({
|
||||||
db: "sessions.db",
|
db: "sessions.db",
|
||||||
dir: "./var/db"
|
dir: "./var/db"
|
||||||
}) as session.Store
|
}) as session.Store
|
||||||
}));
|
}));
|
||||||
app.use(passport.authenticate("session"));
|
app.use(passport.authenticate("session"));
|
||||||
|
|
||||||
|
@ -129,26 +129,26 @@ app.use("/", settingsRouter);
|
||||||
app.use("/uploads", express.static("uploads"));
|
app.use("/uploads", express.static("uploads"));
|
||||||
|
|
||||||
async function prune () {
|
async function prune () {
|
||||||
db.all("SELECT * FROM media", (err: Error, rows: []) => {
|
db.all("SELECT * FROM media", (err: Error, rows: []) => {
|
||||||
console.log("Uploaded files: " + rows.length);
|
console.log("Uploaded files: " + rows.length);
|
||||||
console.log(rows);
|
console.log(rows);
|
||||||
});
|
|
||||||
|
|
||||||
console.log("Vacuuming database...");
|
|
||||||
db.run("VACUUM");
|
|
||||||
|
|
||||||
db.each("SELECT path FROM media WHERE expire < ?", [Date.now()], (err: Error, row: MediaRow) => {
|
|
||||||
console.log(`Expired row: ${row}`);
|
|
||||||
fs.unlink(`uploads/${row.path}`, (err) => {
|
|
||||||
if (err && err.errno == -4058) {
|
|
||||||
console.log("File already deleted");
|
|
||||||
} else {
|
|
||||||
if (err) console.log(err);
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
|
||||||
|
|
||||||
await expire("media", "expire", Date.now());
|
console.log("Vacuuming database...");
|
||||||
|
db.run("VACUUM");
|
||||||
|
|
||||||
|
db.each("SELECT path FROM media WHERE expire < ?", [Date.now()], (err: Error, row: MediaRow) => {
|
||||||
|
console.log(`Expired row: ${row}`);
|
||||||
|
fs.unlink(`uploads/${row.path}`, (err) => {
|
||||||
|
if (err && err.errno == -4058) {
|
||||||
|
console.log("File already deleted");
|
||||||
|
} else {
|
||||||
|
if (err) console.log(err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
await expire("media", "expire", Date.now());
|
||||||
}
|
}
|
||||||
|
|
||||||
setInterval(prune, 1000 * 60); //prune every minute
|
setInterval(prune, 1000 * 60); //prune every minute
|
194
app/lib/db.ts
194
app/lib/db.ts
|
@ -9,176 +9,176 @@ export const db = new sqlite3.Database("./var/db/media.db");
|
||||||
|
|
||||||
/**Create the database schema for the embedders app*/
|
/**Create the database schema for the embedders app*/
|
||||||
export function createDatabase(version: number) {
|
export function createDatabase(version: number) {
|
||||||
console.log("Creating database");
|
console.log("Creating database");
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"CREATE TABLE IF NOT EXISTS users ( \
|
"CREATE TABLE IF NOT EXISTS users ( \
|
||||||
id INTEGER PRIMARY KEY, \
|
id INTEGER PRIMARY KEY, \
|
||||||
username TEXT UNIQUE, \
|
username TEXT UNIQUE, \
|
||||||
hashed_password BLOB, \
|
hashed_password BLOB, \
|
||||||
expire INTEGER, \
|
expire INTEGER, \
|
||||||
salt BLOB \
|
salt BLOB \
|
||||||
)",
|
)",
|
||||||
() => createUser("admin", process.env.EBPASS || "changeme"),
|
() => createUser("admin", process.env.EBPASS || "changeme"),
|
||||||
);
|
);
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"CREATE TABLE IF NOT EXISTS media ( \
|
"CREATE TABLE IF NOT EXISTS media ( \
|
||||||
id INTEGER PRIMARY KEY, \
|
id INTEGER PRIMARY KEY, \
|
||||||
path TEXT NOT NULL, \
|
path TEXT NOT NULL, \
|
||||||
expire INTEGER, \
|
expire INTEGER, \
|
||||||
username TEXT \
|
username TEXT \
|
||||||
)",
|
)",
|
||||||
);
|
);
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"CREATE TABLE IF NOT EXISTS settings ( \
|
"CREATE TABLE IF NOT EXISTS settings ( \
|
||||||
id INTEGER PRIMARY KEY, \
|
id INTEGER PRIMARY KEY, \
|
||||||
downsclaing BOOLEAN, \
|
downsclaing BOOLEAN, \
|
||||||
namerandomization BOOLEAN \
|
namerandomization BOOLEAN \
|
||||||
)",
|
)",
|
||||||
);
|
);
|
||||||
|
|
||||||
db.run(`PRAGMA user_version = ${version}`);
|
db.run(`PRAGMA user_version = ${version}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Updates old Database schema to new */
|
/**Updates old Database schema to new */
|
||||||
export function updateDatabase(oldVersion: number, newVersion: number) {
|
export function updateDatabase(oldVersion: number, newVersion: number) {
|
||||||
if (oldVersion == 1) {
|
if (oldVersion == 1) {
|
||||||
console.log(`Updating database from ${oldVersion} to ${newVersion}`);
|
console.log(`Updating database from ${oldVersion} to ${newVersion}`);
|
||||||
db.run("PRAGMA user_version = 3", (err) => {
|
db.run("PRAGMA user_version = 3", (err) => {
|
||||||
if (err) return;
|
if (err) return;
|
||||||
});
|
});
|
||||||
|
|
||||||
db.run("ALTER TABLE media ADD COLUMN username TEXT", (err) => {
|
db.run("ALTER TABLE media ADD COLUMN username TEXT", (err) => {
|
||||||
if (err) return;
|
if (err) return;
|
||||||
});
|
});
|
||||||
|
|
||||||
db.run("ALTER TABLE users ADD COLUMN expire TEXT", (err) => {
|
db.run("ALTER TABLE users ADD COLUMN expire TEXT", (err) => {
|
||||||
if (err) return;
|
if (err) return;
|
||||||
});
|
});
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"CREATE TABLE IF NOT EXISTS settings ( \
|
"CREATE TABLE IF NOT EXISTS settings ( \
|
||||||
id INTEGER PRIMARY KEY, \
|
id INTEGER PRIMARY KEY, \
|
||||||
downsclaing BOOLEAN, \
|
downsclaing BOOLEAN, \
|
||||||
namerandomization BOOLEAN \
|
namerandomization BOOLEAN \
|
||||||
)",
|
)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (oldVersion == 2) {
|
if (oldVersion == 2) {
|
||||||
console.log(`Updating database from ${oldVersion} to ${newVersion}`);
|
console.log(`Updating database from ${oldVersion} to ${newVersion}`);
|
||||||
db.run("PRAGMA user_version = 3", (err) => {
|
db.run("PRAGMA user_version = 3", (err) => {
|
||||||
if (err) return;
|
if (err) return;
|
||||||
});
|
});
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"CREATE TABLE IF NOT EXISTS settings ( \
|
"CREATE TABLE IF NOT EXISTS settings ( \
|
||||||
id INTEGER PRIMARY KEY, \
|
id INTEGER PRIMARY KEY, \
|
||||||
downsclaing BOOLEAN, \
|
downsclaing BOOLEAN, \
|
||||||
namerandomization BOOLEAN \
|
namerandomization BOOLEAN \
|
||||||
)",
|
)",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Inserts into the media table */
|
/**Inserts into the media table */
|
||||||
export function insertToDB(
|
export function insertToDB(
|
||||||
filename: string,
|
filename: string,
|
||||||
expireDate: Date,
|
expireDate: Date,
|
||||||
username: string,
|
username: string,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const params: MediaParams = [filename, expireDate, username];
|
const params: MediaParams = [filename, expireDate, username];
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"INSERT INTO media (path, expire, username) VALUES (?, ?, ?)",
|
"INSERT INTO media (path, expire, username) VALUES (?, ?, ?)",
|
||||||
params,
|
params,
|
||||||
function (err) {
|
function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
reject(err);
|
reject(err);
|
||||||
} else {
|
} else {
|
||||||
console.log(`Uploaded ${filename} to database`);
|
console.log(`Uploaded ${filename} to database`);
|
||||||
if (expireDate == null) console.log("It will not expire");
|
if (expireDate == null) console.log("It will not expire");
|
||||||
else if (expireDate != null || expireDate != undefined)
|
else if (expireDate != null || expireDate != undefined)
|
||||||
console.log(`It will expire on ${expireDate}`);
|
console.log(`It will expire on ${expireDate}`);
|
||||||
resolve();
|
resolve();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Searches the database and returns images with partial or exact keysearches */
|
/**Searches the database and returns images with partial or exact keysearches */
|
||||||
export function searchImages(imagename: string, partial: boolean) {
|
export function searchImages(imagename: string, partial: boolean) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(`searching for ${imagename}`);
|
console.log(`searching for ${imagename}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export function updateImageName(oldimagename: string, newname: string) {
|
export function updateImageName(oldimagename: string, newname: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(`updating ${oldimagename} to ${newname}`);
|
console.log(`updating ${oldimagename} to ${newname}`);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Inserts a new user to the database */
|
/**Inserts a new user to the database */
|
||||||
export function createUser(username: string, password: string) {
|
export function createUser(username: string, password: string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
console.log(`Creating user ${username}`);
|
console.log(`Creating user ${username}`);
|
||||||
const salt = crypto.randomBytes(16);
|
const salt = crypto.randomBytes(16);
|
||||||
|
|
||||||
db.run(
|
db.run(
|
||||||
"INSERT OR IGNORE INTO users (username, hashed_password, salt) VALUES (?, ?, ?)",
|
"INSERT OR IGNORE INTO users (username, hashed_password, salt) VALUES (?, ?, ?)",
|
||||||
[username, crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256"), salt],
|
[username, crypto.pbkdf2Sync(password, salt, 310000, 32, "sha256"), salt],
|
||||||
);
|
);
|
||||||
|
|
||||||
resolve(null);
|
resolve(null);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Selects the path for a file given ID */
|
/**Selects the path for a file given ID */
|
||||||
export function getPath(id: number | string) {
|
export function getPath(id: number | string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const query = "SELECT path FROM media WHERE id = ?";
|
const query = "SELECT path FROM media WHERE id = ?";
|
||||||
|
|
||||||
db.get(query, [id], (err: Error, path: object) => {
|
db.get(query, [id], (err: Error, path: object) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
resolve(path);
|
resolve(path);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Deletes from database given an ID */
|
/**Deletes from database given an ID */
|
||||||
export function deleteId(database: string, id: number | string) {
|
export function deleteId(database: string, id: number | string) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const query = `DELETE FROM ${database} WHERE id = ?`;
|
const query = `DELETE FROM ${database} WHERE id = ?`;
|
||||||
|
|
||||||
db.run(query, [id], (err: Error) => {
|
db.run(query, [id], (err: Error) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
resolve(null);
|
resolve(null);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**Expires a database row given a Date in unix time */
|
/**Expires a database row given a Date in unix time */
|
||||||
export function expire(database: string, column: string, expiration: number) {
|
export function expire(database: string, column: string, expiration: number) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const query = `SELECT * FROM ${database} WHERE ${column} < ?`;
|
const query = `SELECT * FROM ${database} WHERE ${column} < ?`;
|
||||||
|
|
||||||
db.each(query, [expiration], async (err: Error, row: GenericRow) => {
|
db.each(query, [expiration], async (err: Error, row: GenericRow) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
await deleteId(database, row.id);
|
await deleteId(database, row.id);
|
||||||
|
|
||||||
resolve(null);
|
resolve(null);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**A generic database row */
|
/**A generic database row */
|
||||||
|
|
|
@ -37,7 +37,7 @@ export let currentEncoding: EncodingType = EncodingType.CPU;
|
||||||
* @param {EncodingType} type - The encoding type to set.
|
* @param {EncodingType} type - The encoding type to set.
|
||||||
*/
|
*/
|
||||||
export const setEncodingType = (type: EncodingType) => {
|
export const setEncodingType = (type: EncodingType) => {
|
||||||
currentEncoding = type;
|
currentEncoding = type;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,31 +52,31 @@ export const setEncodingType = (type: EncodingType) => {
|
||||||
* @throws Will throw an error if the executable is not found and the installer path is not available.
|
* @throws Will throw an error if the executable is not found and the installer path is not available.
|
||||||
*/
|
*/
|
||||||
const getExecutablePath = (
|
const getExecutablePath = (
|
||||||
envVar: string,
|
envVar: string,
|
||||||
executable: string,
|
executable: string,
|
||||||
installer: { path: string },
|
installer: { path: string },
|
||||||
): string => {
|
): string => {
|
||||||
if (process.env[envVar]) {
|
if (process.env[envVar]) {
|
||||||
return process.env[envVar];
|
return process.env[envVar];
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return which.sync(executable);
|
return which.sync(executable);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return installer.path;
|
return installer.path;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const ffmpegPath = getExecutablePath(
|
const ffmpegPath = getExecutablePath(
|
||||||
"EB_FFMPEG_PATH",
|
"EB_FFMPEG_PATH",
|
||||||
"ffmpeg",
|
"ffmpeg",
|
||||||
ffmpegInstaller,
|
ffmpegInstaller,
|
||||||
);
|
);
|
||||||
|
|
||||||
const ffprobePath = getExecutablePath(
|
const ffprobePath = getExecutablePath(
|
||||||
"EB_FFPROBE_PATH",
|
"EB_FFPROBE_PATH",
|
||||||
"ffprobe",
|
"ffprobe",
|
||||||
ffprobeInstaller,
|
ffprobeInstaller,
|
||||||
);
|
);
|
||||||
|
|
||||||
console.log(`Using ffmpeg from path: ${ffmpegPath}`);
|
console.log(`Using ffmpeg from path: ${ffmpegPath}`);
|
||||||
|
@ -86,20 +86,20 @@ ffmpeg.setFfmpegPath(ffmpegPath!);
|
||||||
ffmpeg.setFfprobePath(ffprobePath!);
|
ffmpeg.setFfprobePath(ffprobePath!);
|
||||||
|
|
||||||
const checkEnvForEncoder = () => {
|
const checkEnvForEncoder = () => {
|
||||||
const envEncoder = process.env.EB_ENCODER?.toUpperCase();
|
const envEncoder = process.env.EB_ENCODER?.toUpperCase();
|
||||||
|
|
||||||
if (envEncoder && Object.keys(EncodingType).includes(envEncoder)) {
|
if (envEncoder && Object.keys(EncodingType).includes(envEncoder)) {
|
||||||
setEncodingType(
|
setEncodingType(
|
||||||
EncodingType[envEncoder as keyof typeof EncodingType] as EncodingType,
|
EncodingType[envEncoder as keyof typeof EncodingType] as EncodingType,
|
||||||
);
|
);
|
||||||
console.log(
|
console.log(
|
||||||
`Setting encoding type to ${envEncoder} based on environment variable.`,
|
`Setting encoding type to ${envEncoder} based on environment variable.`,
|
||||||
);
|
);
|
||||||
} else if (envEncoder) {
|
} else if (envEncoder) {
|
||||||
console.warn(
|
console.warn(
|
||||||
`Invalid encoder value "${envEncoder}" in environment variable, defaulting to CPU.`,
|
`Invalid encoder value "${envEncoder}" in environment variable, defaulting to CPU.`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
checkEnvForEncoder();
|
checkEnvForEncoder();
|
||||||
|
@ -120,57 +120,57 @@ checkEnvForEncoder();
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export const ffmpegDownscale = (
|
export const ffmpegDownscale = (
|
||||||
path: string,
|
path: string,
|
||||||
filename: string,
|
filename: string,
|
||||||
extension: string,
|
extension: string,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const outputOptions = [
|
const outputOptions = [
|
||||||
"-vf",
|
"-vf",
|
||||||
"scale=-2:720",
|
"scale=-2:720",
|
||||||
"-c:v",
|
"-c:v",
|
||||||
currentEncoding,
|
currentEncoding,
|
||||||
"-c:a",
|
"-c:a",
|
||||||
"copy",
|
"copy",
|
||||||
"-pix_fmt",
|
"-pix_fmt",
|
||||||
"yuv420p",
|
"yuv420p",
|
||||||
];
|
];
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
const progressFile = `uploads/${filename}${extension}-progress.json`;
|
const progressFile = `uploads/${filename}${extension}-progress.json`;
|
||||||
|
|
||||||
ffmpeg()
|
ffmpeg()
|
||||||
.input(path)
|
.input(path)
|
||||||
.outputOptions(outputOptions)
|
.outputOptions(outputOptions)
|
||||||
.output(`uploads/720p-${filename}${extension}`)
|
.output(`uploads/720p-${filename}${extension}`)
|
||||||
.on("progress", function (progress) {
|
.on("progress", function (progress) {
|
||||||
fs.writeFileSync(
|
fs.writeFileSync(
|
||||||
progressFile,
|
progressFile,
|
||||||
JSON.stringify({ progress: progress.percent / 100 }),
|
JSON.stringify({ progress: progress.percent / 100 }),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.on("end", () => {
|
.on("end", () => {
|
||||||
console.log(
|
console.log(
|
||||||
`720p copy complete using ${currentEncoding}, took ${
|
`720p copy complete using ${currentEncoding}, took ${
|
||||||
Date.now() - startTime
|
Date.now() - startTime
|
||||||
}ms to complete`,
|
}ms to complete`,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Delete the .processing file
|
// Delete the .processing file
|
||||||
fs.unlinkSync(progressFile);
|
fs.unlinkSync(progressFile);
|
||||||
|
|
||||||
resolve();
|
resolve();
|
||||||
})
|
})
|
||||||
.on("error", (e) => {
|
.on("error", (e) => {
|
||||||
// Ensure to delete the .processing file even on error
|
// Ensure to delete the .processing file even on error
|
||||||
if (fs.existsSync(progressFile)) {
|
if (fs.existsSync(progressFile)) {
|
||||||
fs.unlinkSync(progressFile);
|
fs.unlinkSync(progressFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
reject(new Error(e));
|
reject(new Error(e));
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -189,80 +189,80 @@ export const ffmpegDownscale = (
|
||||||
* });
|
* });
|
||||||
*/
|
*/
|
||||||
export const ffmpegConvert = (
|
export const ffmpegConvert = (
|
||||||
path: string,
|
path: string,
|
||||||
filename: string,
|
filename: string,
|
||||||
extension: string,
|
extension: string,
|
||||||
): Promise<void> => {
|
): Promise<void> => {
|
||||||
const startTime = Date.now();
|
const startTime = Date.now();
|
||||||
const outputOptions = [
|
const outputOptions = [
|
||||||
"-vf",
|
"-vf",
|
||||||
"scale=-2:720",
|
"scale=-2:720",
|
||||||
"-c:v",
|
"-c:v",
|
||||||
currentEncoding,
|
currentEncoding,
|
||||||
"-c:a",
|
"-c:a",
|
||||||
"copy",
|
"copy",
|
||||||
"-movflags",
|
"-movflags",
|
||||||
"+faststart",
|
"+faststart",
|
||||||
"-pix_fmt",
|
"-pix_fmt",
|
||||||
"yuv420p",
|
"yuv420p",
|
||||||
];
|
];
|
||||||
|
|
||||||
let outputFormat: string;
|
let outputFormat: string;
|
||||||
|
|
||||||
|
if (videoExtensions.includes(extension)) {
|
||||||
|
outputFormat = ".gif";
|
||||||
|
} else if (extension == ".gif") {
|
||||||
|
outputFormat = ".mp4";
|
||||||
|
} else {
|
||||||
|
return new Promise<void>((resolve, reject) => {
|
||||||
|
reject(`Submitted file is neither a video nor a gif: ${path}`);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (videoExtensions.includes(extension)) {
|
|
||||||
outputFormat = ".gif";
|
|
||||||
} else if (extension == ".gif") {
|
|
||||||
outputFormat = ".mp4";
|
|
||||||
} else {
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
reject(`Submitted file is neither a video nor a gif: ${path}`);
|
const progressFile = `uploads/${filename}${extension}-progress.json`;
|
||||||
|
|
||||||
|
ffmpeg()
|
||||||
|
.input(path)
|
||||||
|
.outputOptions(outputOptions)
|
||||||
|
.output("uploads/")
|
||||||
|
.outputFormat(outputFormat)
|
||||||
|
.output(`uploads/${filename}${outputFormat}`)
|
||||||
|
.on("progress", function (progress) {
|
||||||
|
fs.writeFileSync(
|
||||||
|
progressFile,
|
||||||
|
JSON.stringify({ progress: progress.percent / 100 }),
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.on("end", function () {
|
||||||
|
console.log(
|
||||||
|
`Conversion complete, took ${Date.now() - startTime} to complete`,
|
||||||
|
);
|
||||||
|
console.log(`uploads/${filename}${outputFormat}`);
|
||||||
|
resolve();
|
||||||
|
})
|
||||||
|
.on("error", (e) => reject(e))
|
||||||
|
.run();
|
||||||
});
|
});
|
||||||
}
|
|
||||||
|
|
||||||
return new Promise<void>((resolve, reject) => {
|
|
||||||
const progressFile = `uploads/${filename}${extension}-progress.json`;
|
|
||||||
|
|
||||||
ffmpeg()
|
|
||||||
.input(path)
|
|
||||||
.outputOptions(outputOptions)
|
|
||||||
.output("uploads/")
|
|
||||||
.outputFormat(outputFormat)
|
|
||||||
.output(`uploads/${filename}${outputFormat}`)
|
|
||||||
.on("progress", function (progress) {
|
|
||||||
fs.writeFileSync(
|
|
||||||
progressFile,
|
|
||||||
JSON.stringify({ progress: progress.percent / 100 }),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.on("end", function () {
|
|
||||||
console.log(
|
|
||||||
`Conversion complete, took ${Date.now() - startTime} to complete`,
|
|
||||||
);
|
|
||||||
console.log(`uploads/${filename}${outputFormat}`);
|
|
||||||
resolve();
|
|
||||||
})
|
|
||||||
.on("error", (e) => reject(e))
|
|
||||||
.run();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ffProbe = async (
|
export const ffProbe = async (
|
||||||
path: string,
|
path: string,
|
||||||
filename: string,
|
filename: string,
|
||||||
extension: string,
|
extension: string,
|
||||||
) => {
|
) => {
|
||||||
return new Promise<FfprobeData>((resolve, reject) => {
|
return new Promise<FfprobeData>((resolve, reject) => {
|
||||||
if (
|
if (
|
||||||
!videoExtensions.includes(extension) &&
|
!videoExtensions.includes(extension) &&
|
||||||
!imageExtensions.includes(extension)
|
!imageExtensions.includes(extension)
|
||||||
) {
|
) {
|
||||||
console.log(`Extension is ${extension}`);
|
console.log(`Extension is ${extension}`);
|
||||||
reject(`Submitted file is neither a video nor an image: ${path}`);
|
reject(`Submitted file is neither a video nor an image: ${path}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
ffprobe(path, (err, data) => {
|
ffprobe(path, (err, data) => {
|
||||||
if (err) reject(err);
|
if (err) reject(err);
|
||||||
resolve(data);
|
resolve(data);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -11,11 +11,11 @@ declare global {
|
||||||
}
|
}
|
||||||
/**Splits a file name into its name and then its extension */
|
/**Splits a file name into its name and then its extension */
|
||||||
export function extension(str: string) {
|
export function extension(str: string) {
|
||||||
const file = str.split("/").pop();
|
const file = str.split("/").pop();
|
||||||
return [
|
return [
|
||||||
file.substr(0, file.lastIndexOf(".")),
|
file.substr(0, file.lastIndexOf(".")),
|
||||||
file.substr(file.lastIndexOf("."), file.length).toLowerCase(),
|
file.substr(file.lastIndexOf("."), file.length).toLowerCase(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
/**Type for user data */
|
/**Type for user data */
|
||||||
export interface User {
|
export interface User {
|
||||||
|
@ -37,21 +37,21 @@ export interface oembedObj {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const videoExtensions = [
|
export const videoExtensions = [
|
||||||
".mp4",
|
".mp4",
|
||||||
".mov",
|
".mov",
|
||||||
".avi",
|
".avi",
|
||||||
".flv",
|
".flv",
|
||||||
".mkv",
|
".mkv",
|
||||||
".wmv",
|
".wmv",
|
||||||
".webm",
|
".webm",
|
||||||
];
|
];
|
||||||
export const imageExtensions = [
|
export const imageExtensions = [
|
||||||
".jpg",
|
".jpg",
|
||||||
".jpeg",
|
".jpeg",
|
||||||
".png",
|
".png",
|
||||||
".gif",
|
".gif",
|
||||||
".bmp",
|
".bmp",
|
||||||
".svg",
|
".svg",
|
||||||
".tiff",
|
".tiff",
|
||||||
".webp",
|
".webp",
|
||||||
];
|
];
|
||||||
|
|
|
@ -8,40 +8,40 @@ import { insertToDB } from "./db";
|
||||||
import { ffmpegDownscale, ffProbe } from "./ffmpeg";
|
import { ffmpegDownscale, ffProbe } from "./ffmpeg";
|
||||||
|
|
||||||
export const checkAuth: Middleware = (req, res, next) => {
|
export const checkAuth: Middleware = (req, res, next) => {
|
||||||
if (!req.user) {
|
if (!req.user) {
|
||||||
return res.status(401);
|
return res.status(401);
|
||||||
}
|
}
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**Checks shareX auth key */
|
/**Checks shareX auth key */
|
||||||
export const checkSharexAuth: Middleware = (req, res, next) => {
|
export const checkSharexAuth: Middleware = (req, res, next) => {
|
||||||
const auth =
|
const auth =
|
||||||
process.env.EBAPI_KEY || process.env.EBPASS || "pleaseSetAPI_KEY";
|
process.env.EBAPI_KEY || process.env.EBPASS || "pleaseSetAPI_KEY";
|
||||||
let key = null;
|
let key = null;
|
||||||
|
|
||||||
if (req.headers["key"]) {
|
if (req.headers["key"]) {
|
||||||
key = req.headers["key"];
|
key = req.headers["key"];
|
||||||
} else {
|
} else {
|
||||||
return res
|
return res
|
||||||
.status(400)
|
.status(400)
|
||||||
.send(
|
.send(
|
||||||
"{success: false, message: 'No key provided', fix: 'Provide a key'}",
|
"{success: false, message: 'No key provided', fix: 'Provide a key'}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (auth != key) {
|
if (auth != key) {
|
||||||
return res
|
return res
|
||||||
.status(401)
|
.status(401)
|
||||||
.send(
|
.send(
|
||||||
"{success: false, message: 'Invalid key', fix: 'Provide a valid key'}",
|
"{success: false, message: 'Invalid key', fix: 'Provide a valid key'}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const shortKey = key.substr(0, 3) + "...";
|
const shortKey = key.substr(0, 3) + "...";
|
||||||
console.log(`Authenicated user with key: ${shortKey}`);
|
console.log(`Authenicated user with key: ${shortKey}`);
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -53,50 +53,50 @@ export const checkSharexAuth: Middleware = (req, res, next) => {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const createEmbedData: Middleware = async (req, res, next) => {
|
export const createEmbedData: Middleware = async (req, res, next) => {
|
||||||
const files = req.files as Express.Multer.File[];
|
const files = req.files as Express.Multer.File[];
|
||||||
for (const file in files) {
|
for (const file in files) {
|
||||||
const [filename, fileExtension] = extension(files[file].filename);
|
const [filename, fileExtension] = extension(files[file].filename);
|
||||||
const isMedia =
|
const isMedia =
|
||||||
videoExtensions.includes(fileExtension) ||
|
videoExtensions.includes(fileExtension) ||
|
||||||
imageExtensions.includes(fileExtension);
|
imageExtensions.includes(fileExtension);
|
||||||
|
|
||||||
const oembed: oembedObj = {
|
const oembed: oembedObj = {
|
||||||
type: "video",
|
type: "video",
|
||||||
version: "1.0",
|
version: "1.0",
|
||||||
provider_name: "embedder",
|
provider_name: "embedder",
|
||||||
provider_url: "https://github.com/WaveringAna/embedder",
|
provider_url: "https://github.com/WaveringAna/embedder",
|
||||||
cache_age: 86400,
|
cache_age: 86400,
|
||||||
html: `<iframe src='${req.protocol}://${req.get(
|
html: `<iframe src='${req.protocol}://${req.get(
|
||||||
"host",
|
"host",
|
||||||
)}/gifv/${filename}${fileExtension}'></iframe>`,
|
)}/gifv/${filename}${fileExtension}'></iframe>`,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isMedia) {
|
if (isMedia) {
|
||||||
let ffProbeData;
|
let ffProbeData;
|
||||||
try {
|
try {
|
||||||
ffProbeData = await ffProbe(
|
ffProbeData = await ffProbe(
|
||||||
`uploads/${files[file].filename}`,
|
`uploads/${files[file].filename}`,
|
||||||
filename,
|
filename,
|
||||||
fileExtension,
|
fileExtension,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
console.log(`Error: ${error}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
oembed.width = ffProbeData.streams[0].width;
|
||||||
|
oembed.height = ffProbeData.streams[0].height;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFile(
|
||||||
|
`uploads/oembed-${filename}${fileExtension}.json`,
|
||||||
|
JSON.stringify(oembed),
|
||||||
|
function (err) {
|
||||||
|
if (err) return next(err);
|
||||||
|
console.log(`oembed file created ${filename}${fileExtension}.json`);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
} catch (error) {
|
|
||||||
console.log(`Error: ${error}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
oembed.width = ffProbeData.streams[0].width;
|
|
||||||
oembed.height = ffProbeData.streams[0].height;
|
|
||||||
}
|
}
|
||||||
|
next();
|
||||||
fs.writeFile(
|
|
||||||
`uploads/oembed-${filename}${fileExtension}.json`,
|
|
||||||
JSON.stringify(oembed),
|
|
||||||
function (err) {
|
|
||||||
if (err) return next(err);
|
|
||||||
console.log(`oembed file created ${filename}${fileExtension}.json`);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
next();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -108,59 +108,59 @@ export const createEmbedData: Middleware = async (req, res, next) => {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
export const convertTo720p: Middleware = (req, res, next) => {
|
export const convertTo720p: Middleware = (req, res, next) => {
|
||||||
const files = req.files as Express.Multer.File[];
|
const files = req.files as Express.Multer.File[];
|
||||||
console.log("convert to 720p running");
|
console.log("convert to 720p running");
|
||||||
for (const file in files) {
|
for (const file in files) {
|
||||||
const [filename, fileExtension] = extension(files[file].filename);
|
const [filename, fileExtension] = extension(files[file].filename);
|
||||||
|
|
||||||
//Skip if not a video
|
//Skip if not a video
|
||||||
if (!videoExtensions.includes(fileExtension) && fileExtension !== ".gif") {
|
if (!videoExtensions.includes(fileExtension) && fileExtension !== ".gif") {
|
||||||
console.log(`${files[file].filename} is not a video file`);
|
console.log(`${files[file].filename} is not a video file`);
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(`Creating 720p for ${files[file].filename}`);
|
||||||
|
|
||||||
|
ffmpegDownscale(
|
||||||
|
`uploads/${filename}${fileExtension}`,
|
||||||
|
filename,
|
||||||
|
fileExtension,
|
||||||
|
)
|
||||||
|
.then(() => {
|
||||||
|
//Nothing for now, can fire event flag that it is done to front end when react conversion is done
|
||||||
|
})
|
||||||
|
.catch((error) => {
|
||||||
|
console.log(`Error: ${error}`);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Creating 720p for ${files[file].filename}`);
|
next();
|
||||||
|
|
||||||
ffmpegDownscale(
|
|
||||||
`uploads/${filename}${fileExtension}`,
|
|
||||||
filename,
|
|
||||||
fileExtension,
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
//Nothing for now, can fire event flag that it is done to front end when react conversion is done
|
|
||||||
})
|
|
||||||
.catch((error) => {
|
|
||||||
console.log(`Error: ${error}`);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**Middleware for handling uploaded files. Inserts it into the database */
|
/**Middleware for handling uploaded files. Inserts it into the database */
|
||||||
export const handleUpload: Middleware = async (req, res, next) => {
|
export const handleUpload: Middleware = async (req, res, next) => {
|
||||||
if (!req.file && !req.files) {
|
if (!req.file && !req.files) {
|
||||||
console.log("No files were uploaded");
|
console.log("No files were uploaded");
|
||||||
return res.status(400).send("No files were uploaded.");
|
return res.status(400).send("No files were uploaded.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const files = req.files ? (req.files as Express.Multer.File[]) : req.file;
|
const files = req.files ? (req.files as Express.Multer.File[]) : req.file;
|
||||||
const username = req.user ? req.user.username : "sharex";
|
const username = req.user ? req.user.username : "sharex";
|
||||||
const expireDate: Date = req.body.expire
|
const expireDate: Date = req.body.expire
|
||||||
? new Date(Date.now() + req.body.expire * 24 * 60 * 60 * 1000)
|
? new Date(Date.now() + req.body.expire * 24 * 60 * 60 * 1000)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (files instanceof Array) {
|
if (files instanceof Array) {
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
files.map((file) => insertToDB(file.filename, expireDate, username)),
|
files.map((file) => insertToDB(file.filename, expireDate, username)),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
await insertToDB(files.filename, expireDate, username);
|
await insertToDB(files.filename, expireDate, username);
|
||||||
|
}
|
||||||
|
next();
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Error in handleUpload:", error);
|
||||||
|
res.status(500).send("Error processing files.");
|
||||||
}
|
}
|
||||||
next();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Error in handleUpload:", error);
|
|
||||||
res.status(500).send("Error processing files.");
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -14,126 +14,126 @@ export type FileNameCallback = (error: Error | null, filename: string) => void;
|
||||||
let randomizeNames = false;
|
let randomizeNames = false;
|
||||||
|
|
||||||
if (process.env["EB_RANDOMIZE_NAMES"] === "true") {
|
if (process.env["EB_RANDOMIZE_NAMES"] === "true") {
|
||||||
randomizeNames = true;
|
randomizeNames = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(`Randomize names is set ${randomizeNames}`);
|
console.log(`Randomize names is set ${randomizeNames}`);
|
||||||
|
|
||||||
export const fileStorage = multer.diskStorage({
|
export const fileStorage = multer.diskStorage({
|
||||||
destination: (
|
destination: (
|
||||||
request: Request,
|
request: Request,
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
callback: DestinationCallback,
|
callback: DestinationCallback,
|
||||||
): void => {
|
): void => {
|
||||||
callback(null, __dirname + "/../../uploads");
|
callback(null, __dirname + "/../../uploads");
|
||||||
},
|
},
|
||||||
filename: (
|
filename: (
|
||||||
request: Request,
|
request: Request,
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
callback: FileNameCallback,
|
callback: FileNameCallback,
|
||||||
): void => {
|
): void => {
|
||||||
const [filename, fileExtension] = extension(file.originalname);
|
const [filename, fileExtension] = extension(file.originalname);
|
||||||
console.log(`Uploading ${file}`);
|
console.log(`Uploading ${file}`);
|
||||||
db.all(
|
db.all(
|
||||||
"SELECT * FROM media WHERE path = ?",
|
"SELECT * FROM media WHERE path = ?",
|
||||||
[filename + fileExtension],
|
[filename + fileExtension],
|
||||||
(err: Error, exists: []) => {
|
(err: Error, exists: []) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log(err);
|
console.log(err);
|
||||||
callback(err, null);
|
callback(err, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
let filenameSet = true;
|
let filenameSet = true;
|
||||||
let existsBool = false;
|
let existsBool = false;
|
||||||
let suffix: number;
|
let suffix: number;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
request.body.title != "" ||
|
request.body.title != "" ||
|
||||||
request.body.title != null ||
|
request.body.title != null ||
|
||||||
request.body.title != undefined
|
request.body.title != undefined
|
||||||
) {
|
) {
|
||||||
filenameSet = false;
|
filenameSet = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exists.length != 0) {
|
if (exists.length != 0) {
|
||||||
existsBool = true;
|
existsBool = true;
|
||||||
suffix = new Date().getTime() / 1000;
|
suffix = new Date().getTime() / 1000;
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log(request.body.title);
|
console.log(request.body.title);
|
||||||
|
|
||||||
if (randomizeNames) {
|
if (randomizeNames) {
|
||||||
//Random string of 8 alphanumeric characters
|
//Random string of 8 alphanumeric characters
|
||||||
//Chance of collision is extremely low, not worth checking for
|
//Chance of collision is extremely low, not worth checking for
|
||||||
console.log("Randomizing name");
|
console.log("Randomizing name");
|
||||||
callback(
|
callback(
|
||||||
null,
|
null,
|
||||||
Math.random().toString(36).slice(2, 10) + fileExtension,
|
Math.random().toString(36).slice(2, 10) + fileExtension,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filenameSet && existsBool) {
|
if (filenameSet && existsBool) {
|
||||||
console.log(
|
console.log(
|
||||||
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
||||||
);
|
);
|
||||||
callback(null, request.body.title + "-" + suffix + fileExtension);
|
callback(null, request.body.title + "-" + suffix + fileExtension);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filenameSet && existsBool) {
|
if (!filenameSet && existsBool) {
|
||||||
console.log(
|
console.log(
|
||||||
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
||||||
);
|
);
|
||||||
callback(null, filename + "-" + suffix + fileExtension);
|
callback(null, filename + "-" + suffix + fileExtension);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (filenameSet && !existsBool) {
|
if (filenameSet && !existsBool) {
|
||||||
console.log(
|
console.log(
|
||||||
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
||||||
);
|
);
|
||||||
callback(null, request.body.title + fileExtension);
|
callback(null, request.body.title + fileExtension);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!filenameSet && !existsBool) {
|
if (!filenameSet && !existsBool) {
|
||||||
console.log(
|
console.log(
|
||||||
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
`filenameSet is ${filenameSet} and existsBool is ${existsBool}`,
|
||||||
);
|
);
|
||||||
callback(null, filename + fileExtension);
|
callback(null, filename + fileExtension);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export let allowedMimeTypes = [
|
export let allowedMimeTypes = [
|
||||||
"image/png",
|
"image/png",
|
||||||
"image/jpg",
|
"image/jpg",
|
||||||
"image/jpeg",
|
"image/jpeg",
|
||||||
"image/gif",
|
"image/gif",
|
||||||
"image/webp",
|
"image/webp",
|
||||||
"video/mp4",
|
"video/mp4",
|
||||||
"video/mov",
|
"video/mov",
|
||||||
"video/webm",
|
"video/webm",
|
||||||
"audio/mpeg",
|
"audio/mpeg",
|
||||||
"audio/ogg",
|
"audio/ogg",
|
||||||
];
|
];
|
||||||
|
|
||||||
export const setAllowedMimeTypes = (mimeTypes: string[]): void => {
|
export const setAllowedMimeTypes = (mimeTypes: string[]): void => {
|
||||||
allowedMimeTypes = mimeTypes;
|
allowedMimeTypes = mimeTypes;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const fileFilter = (
|
export const fileFilter = (
|
||||||
request: Request,
|
request: Request,
|
||||||
file: Express.Multer.File,
|
file: Express.Multer.File,
|
||||||
callback: FileFilterCallback,
|
callback: FileFilterCallback,
|
||||||
): void => {
|
): void => {
|
||||||
if (allowedMimeTypes.includes(file.mimetype)) {
|
if (allowedMimeTypes.includes(file.mimetype)) {
|
||||||
callback(null, true);
|
callback(null, true);
|
||||||
} else {
|
} else {
|
||||||
callback(null, false);
|
callback(null, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,24 +6,24 @@ import {createUser} from "../lib/db";
|
||||||
const router: Router = express.Router();
|
const router: Router = express.Router();
|
||||||
/**Middleware to check if a user is actually signed in */
|
/**Middleware to check if a user is actually signed in */
|
||||||
const adminCheck: Middleware = (req: Request, res: Response, next: NextFunction) => {
|
const adminCheck: Middleware = (req: Request, res: Response, next: NextFunction) => {
|
||||||
if (!req.user)
|
if (!req.user)
|
||||||
return res.status(403).send("You are not authorized to perform this action");
|
return res.status(403).send("You are not authorized to perform this action");
|
||||||
else {
|
else {
|
||||||
if (req.user.username != "admin")
|
if (req.user.username != "admin")
|
||||||
return res.status(403).send("You are not authorized to perform this action");
|
return res.status(403).send("You are not authorized to perform this action");
|
||||||
}
|
}
|
||||||
|
|
||||||
next();
|
next();
|
||||||
};
|
};
|
||||||
|
|
||||||
router.get("/adduser", adminCheck, (req: Request, res: Response) => {
|
router.get("/adduser", adminCheck, (req: Request, res: Response) => {
|
||||||
res.locals.filter = null;
|
res.locals.filter = null;
|
||||||
res.render("adduser", { user: req.user });
|
res.render("adduser", { user: req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post("/adduser", adminCheck, (req: Request, res: Response) => {
|
router.post("/adduser", adminCheck, (req: Request, res: Response) => {
|
||||||
createUser(req.body.username, req.body.password);
|
createUser(req.body.username, req.body.password);
|
||||||
res.redirect("/");
|
res.redirect("/");
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
|
@ -9,77 +9,77 @@ import { db, UserRow } from "../lib/db";
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
passport.use(
|
passport.use(
|
||||||
new LocalStrategy(function verify(username, password, cb) {
|
new LocalStrategy(function verify(username, password, cb) {
|
||||||
db.get(
|
db.get(
|
||||||
"SELECT * FROM users WHERE username = ?",
|
"SELECT * FROM users WHERE username = ?",
|
||||||
[username],
|
[username],
|
||||||
function (err: Error, row: UserRow) {
|
function (err: Error, row: UserRow) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
if (!row) {
|
if (!row) {
|
||||||
return cb(null, false, {
|
return cb(null, false, {
|
||||||
message: "Incorrect username or password.",
|
message: "Incorrect username or password.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
crypto.pbkdf2(
|
crypto.pbkdf2(
|
||||||
password,
|
password,
|
||||||
row.salt,
|
row.salt,
|
||||||
310000,
|
310000,
|
||||||
32,
|
32,
|
||||||
"sha256",
|
"sha256",
|
||||||
function (err, hashedPassword) {
|
function (err, hashedPassword) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return cb(err);
|
return cb(err);
|
||||||
}
|
}
|
||||||
if (!crypto.timingSafeEqual(row.hashed_password, hashedPassword)) {
|
if (!crypto.timingSafeEqual(row.hashed_password, hashedPassword)) {
|
||||||
return cb(null, false, {
|
return cb(null, false, {
|
||||||
message: "Incorrect username or password.",
|
message: "Incorrect username or password.",
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return cb(null, row);
|
return cb(null, row);
|
||||||
},
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
}),
|
||||||
);
|
|
||||||
}),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
passport.serializeUser(function (user: User, cb) {
|
passport.serializeUser(function (user: User, cb) {
|
||||||
process.nextTick(function () {
|
process.nextTick(function () {
|
||||||
cb(null, {
|
cb(null, {
|
||||||
id: user.id,
|
id: user.id,
|
||||||
username: user.username,
|
username: user.username,
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|
||||||
passport.deserializeUser(function (user: User, cb) {
|
passport.deserializeUser(function (user: User, cb) {
|
||||||
process.nextTick(function () {
|
process.nextTick(function () {
|
||||||
return cb(null, user);
|
return cb(null, user);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get("/login", function (req, res) {
|
router.get("/login", function (req, res) {
|
||||||
res.render("login");
|
res.render("login");
|
||||||
});
|
});
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/login/password",
|
"/login/password",
|
||||||
passport.authenticate("local", {
|
passport.authenticate("local", {
|
||||||
successRedirect: "/",
|
successRedirect: "/",
|
||||||
failureRedirect: "/login",
|
failureRedirect: "/login",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post("/logout", function (req, res, next) {
|
router.post("/logout", function (req, res, next) {
|
||||||
req.logout(function (err) {
|
req.logout(function (err) {
|
||||||
if (err) {
|
if (err) {
|
||||||
return next(err);
|
return next(err);
|
||||||
}
|
}
|
||||||
res.redirect("/");
|
res.redirect("/");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import type {
|
import type {
|
||||||
RequestHandler as Middleware,
|
RequestHandler as Middleware,
|
||||||
Request,
|
Request,
|
||||||
Response,
|
Response,
|
||||||
NextFunction,
|
NextFunction,
|
||||||
} from "express";
|
} from "express";
|
||||||
|
|
||||||
import multer from "multer";
|
import multer from "multer";
|
||||||
|
@ -18,184 +18,184 @@ import { extension, videoExtensions } from "../lib/lib";
|
||||||
import { db, MediaRow, getPath, deleteId } from "../lib/db";
|
import { db, MediaRow, getPath, deleteId } from "../lib/db";
|
||||||
import { fileStorage } from "../lib/multer";
|
import { fileStorage } from "../lib/multer";
|
||||||
import {
|
import {
|
||||||
checkAuth,
|
checkAuth,
|
||||||
checkSharexAuth,
|
checkSharexAuth,
|
||||||
convertTo720p,
|
convertTo720p,
|
||||||
createEmbedData,
|
createEmbedData,
|
||||||
handleUpload,
|
handleUpload,
|
||||||
} from "../lib/middleware";
|
} from "../lib/middleware";
|
||||||
|
|
||||||
const upload = multer({ storage: fileStorage /**, fileFilter: fileFilter**/ }); //maybe make this a env variable?
|
const upload = multer({ storage: fileStorage /**, fileFilter: fileFilter**/ }); //maybe make this a env variable?
|
||||||
/**Middleware to grab media from media database */
|
/**Middleware to grab media from media database */
|
||||||
|
|
||||||
const fetchMedia: Middleware = (req, res, next) => {
|
const fetchMedia: Middleware = (req, res, next) => {
|
||||||
const admin: boolean = req.user.username == "admin" ? true : false;
|
const admin: boolean = req.user.username == "admin" ? true : false;
|
||||||
/**Check if the user is an admin, if so, show all posts from all users */
|
/**Check if the user is an admin, if so, show all posts from all users */
|
||||||
const query: string =
|
const query: string =
|
||||||
admin == true
|
admin == true
|
||||||
? "SELECT * FROM media"
|
? "SELECT * FROM media"
|
||||||
: `SELECT * FROM media WHERE username = '${req.user.username}'`;
|
: `SELECT * FROM media WHERE username = '${req.user.username}'`;
|
||||||
|
|
||||||
db.all(query, (err: Error, rows: []) => {
|
db.all(query, (err: Error, rows: []) => {
|
||||||
if (err) return next(err);
|
if (err) return next(err);
|
||||||
const files = rows.map((row: MediaRow) => {
|
const files = rows.map((row: MediaRow) => {
|
||||||
return {
|
return {
|
||||||
id: row.id,
|
id: row.id,
|
||||||
path: row.path,
|
path: row.path,
|
||||||
expire: row.expire,
|
expire: row.expire,
|
||||||
username: row.username,
|
username: row.username,
|
||||||
url: "/" + row.id,
|
url: "/" + row.id,
|
||||||
};
|
};
|
||||||
|
});
|
||||||
|
res.locals.files = files.reverse(); //reverse so newest files appear first
|
||||||
|
res.locals.Count = files.length;
|
||||||
|
next();
|
||||||
});
|
});
|
||||||
res.locals.files = files.reverse(); //reverse so newest files appear first
|
|
||||||
res.locals.Count = files.length;
|
|
||||||
next();
|
|
||||||
});
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/",
|
"/",
|
||||||
(req: Request, res: Response, next: NextFunction) => {
|
(req: Request, res: Response, next: NextFunction) => {
|
||||||
if (!req.user) return res.render("home");
|
if (!req.user) return res.render("home");
|
||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
fetchMedia,
|
fetchMedia,
|
||||||
(req: Request, res: Response) => {
|
(req: Request, res: Response) => {
|
||||||
res.locals.filter = null;
|
res.locals.filter = null;
|
||||||
res.render("index", { user: req.user });
|
res.render("index", { user: req.user });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
router.get("/media-list", fetchMedia, (req: Request, res: Response) => {
|
router.get("/media-list", fetchMedia, (req: Request, res: Response) => {
|
||||||
res.render("partials/_fileList", { user: req.user });
|
res.render("partials/_fileList", { user: req.user });
|
||||||
});
|
});
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/gifv/:file",
|
"/gifv/:file",
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const url = `${req.protocol}://${req.get("host")}/uploads/${
|
const url = `${req.protocol}://${req.get("host")}/uploads/${
|
||||||
req.params.file
|
req.params.file
|
||||||
}`;
|
}`;
|
||||||
let width;
|
let width;
|
||||||
let height;
|
let height;
|
||||||
|
|
||||||
const [filename, fileExtension] = extension(`uploads/${req.params.file}`);
|
const [filename, fileExtension] = extension(`uploads/${req.params.file}`);
|
||||||
if (
|
if (
|
||||||
fileExtension == ".mp4" ||
|
fileExtension == ".mp4" ||
|
||||||
fileExtension == ".mov" ||
|
fileExtension == ".mov" ||
|
||||||
fileExtension == ".webm" ||
|
fileExtension == ".webm" ||
|
||||||
fileExtension == ".gif"
|
fileExtension == ".gif"
|
||||||
) {
|
) {
|
||||||
const imageData = ffProbe(
|
const imageData = ffProbe(
|
||||||
`uploads/${req.params.file}`,
|
`uploads/${req.params.file}`,
|
||||||
filename,
|
filename,
|
||||||
fileExtension
|
fileExtension
|
||||||
);
|
);
|
||||||
|
|
||||||
width = (await imageData).streams[0].width;
|
width = (await imageData).streams[0].width;
|
||||||
height = (await imageData).streams[0].height;
|
height = (await imageData).streams[0].height;
|
||||||
|
|
||||||
return res.render("gifv", {
|
return res.render("gifv", {
|
||||||
url: url,
|
url: url,
|
||||||
host: `${req.protocol}://${req.get("host")}`,
|
host: `${req.protocol}://${req.get("host")}`,
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const imageData = await imageProbe(
|
const imageData = await imageProbe(
|
||||||
fs.createReadStream(`uploads/${req.params.file}`)
|
fs.createReadStream(`uploads/${req.params.file}`)
|
||||||
);
|
);
|
||||||
return res.render("gifv", {
|
return res.render("gifv", {
|
||||||
url: url,
|
url: url,
|
||||||
host: `${req.protocol}://${req.get("host")}`,
|
host: `${req.protocol}://${req.get("host")}`,
|
||||||
width: imageData.width,
|
width: imageData.width,
|
||||||
height: imageData.height,
|
height: imageData.height,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/",
|
"/",
|
||||||
[
|
[
|
||||||
checkAuth,
|
checkAuth,
|
||||||
upload.array("fileupload"),
|
upload.array("fileupload"),
|
||||||
convertTo720p,
|
convertTo720p,
|
||||||
createEmbedData,
|
createEmbedData,
|
||||||
handleUpload,
|
handleUpload,
|
||||||
fetchMedia,
|
fetchMedia,
|
||||||
],
|
],
|
||||||
(req: Request, res: Response) => {
|
(req: Request, res: Response) => {
|
||||||
return res.render("partials/_fileList", { user: req.user }); // Render only the file list partial
|
return res.render("partials/_fileList", { user: req.user }); // Render only the file list partial
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
router.post(
|
router.post(
|
||||||
"/sharex",
|
"/sharex",
|
||||||
[checkSharexAuth, upload.single("fileupload"), createEmbedData, handleUpload],
|
[checkSharexAuth, upload.single("fileupload"), createEmbedData, handleUpload],
|
||||||
(req: Request, res: Response) => {
|
(req: Request, res: Response) => {
|
||||||
return res.send(
|
return res.send(
|
||||||
`${req.protocol}://${req.get("host")}/uploads/${req.file.filename}`
|
`${req.protocol}://${req.get("host")}/uploads/${req.file.filename}`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
router.get(
|
router.get(
|
||||||
"/:id(\\d+)/delete",
|
"/:id(\\d+)/delete",
|
||||||
[checkAuth],
|
[checkAuth],
|
||||||
async (req: Request, res: Response, next: NextFunction) => {
|
async (req: Request, res: Response, next: NextFunction) => {
|
||||||
const filename: any = await getPath(req.params.id);
|
const filename: any = await getPath(req.params.id);
|
||||||
const filePath = path.join(__dirname , "../../uploads/" + filename.path);
|
const filePath = path.join(__dirname , "../../uploads/" + filename.path);
|
||||||
const oembed = path.join(
|
const oembed = path.join(
|
||||||
__dirname , "../../uploads/oembed-" + filename.path + ".json"
|
__dirname , "../../uploads/oembed-" + filename.path + ".json"
|
||||||
);
|
);
|
||||||
|
|
||||||
const [fileName, fileExtension] = extension(filePath);
|
const [fileName, fileExtension] = extension(filePath);
|
||||||
const filesToDelete = [filePath, oembed];
|
const filesToDelete = [filePath, oembed];
|
||||||
|
|
||||||
if (
|
if (
|
||||||
videoExtensions.includes(fileExtension) ||
|
videoExtensions.includes(fileExtension) ||
|
||||||
fileExtension == ".gif"
|
fileExtension == ".gif"
|
||||||
) {
|
) {
|
||||||
filesToDelete.push(
|
filesToDelete.push(
|
||||||
path.join(__dirname , "../../uploads/720p-" + filename.path)
|
path.join(__dirname , "../../uploads/720p-" + filename.path)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait for all file deletions and database operations to complete
|
// Wait for all file deletions and database operations to complete
|
||||||
await Promise.all(
|
await Promise.all(
|
||||||
filesToDelete.map(async (path) => {
|
filesToDelete.map(async (path) => {
|
||||||
return new Promise<void>((resolve, reject) => {
|
return new Promise<void>((resolve, reject) => {
|
||||||
fs.unlink(path, async (err) => {
|
fs.unlink(path, async (err) => {
|
||||||
console.log(`Deleting ${path}`);
|
console.log(`Deleting ${path}`);
|
||||||
if (err) {
|
if (err) {
|
||||||
if ([-4058, -2].includes(err.errno)) {
|
if ([-4058, -2].includes(err.errno)) {
|
||||||
//file not found
|
//file not found
|
||||||
console.log("File not found, deleting from database");
|
console.log("File not found, deleting from database");
|
||||||
await deleteId("media", req.params.id);
|
await deleteId("media", req.params.id);
|
||||||
}
|
}
|
||||||
console.error(`Error deleting file ${path}:`, err);
|
console.error(`Error deleting file ${path}:`, err);
|
||||||
reject(err);
|
reject(err);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
await deleteId("media", req.params.id);
|
await deleteId("media", req.params.id);
|
||||||
resolve();
|
resolve();
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
).catch((err) => {
|
||||||
|
console.error("Error deleting files:", err);
|
||||||
|
return next(err);
|
||||||
});
|
});
|
||||||
})
|
|
||||||
).catch((err) => {
|
|
||||||
console.error("Error deleting files:", err);
|
|
||||||
return next(err);
|
|
||||||
});
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
},
|
},
|
||||||
[fetchMedia],
|
[fetchMedia],
|
||||||
(req: Request, res: Response) => {
|
(req: Request, res: Response) => {
|
||||||
return res.render("partials/_fileList", { user: req.user });
|
return res.render("partials/_fileList", { user: req.user });
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
export default router;
|
export default router;
|
||||||
|
|
|
@ -20,7 +20,7 @@ const fetchUsers = (): Promise<[UserRow]> => {
|
||||||
resolve(rows);
|
resolve(rows);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
};
|
||||||
|
|
||||||
const fetchSettings: Middleware = async (req, res, next) => {
|
const fetchSettings: Middleware = async (req, res, next) => {
|
||||||
res.locals.users = req.user.username == "admin" ? await fetchUsers() : null;
|
res.locals.users = req.user.username == "admin" ? await fetchUsers() : null;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue