Better error handling
Remove `image-size` dependency as sharp covers the needed functionality.
This commit is contained in:
parent
6513cd7d76
commit
a7c4a17ecc
|
|
@ -35,7 +35,6 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"express": "4.17.3",
|
||||
"image-size": "1.0.1",
|
||||
"sharp": "0.30.3",
|
||||
"winston": "3.7.2",
|
||||
"express-winston": "4.2.0"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import express from "express";
|
||||
import * as path from "path";
|
||||
import { a, Folders } from "./models";
|
||||
import { walk } from "./fsExtension";
|
||||
import { initThumbnailsAsync } from "./thumbnails";
|
||||
import { publicPath } from "./paths";
|
||||
|
|
@ -31,8 +30,8 @@ const imagesPath = "/images";
|
|||
|
||||
app.get(`${imagesPath}(/*)?`, getImages(imagesPath));
|
||||
|
||||
app.get("/directories", (req, res) => {
|
||||
res.json(a<Folders>(walk("")));
|
||||
app.get("/directories", async (req, res) => {
|
||||
res.json(await walk(""));
|
||||
});
|
||||
|
||||
// All other GET requests not handled before will return our React app
|
||||
|
|
|
|||
|
|
@ -1,13 +1,20 @@
|
|||
import fs from "fs";
|
||||
import sizeOf from "image-size";
|
||||
import express from "express";
|
||||
import sharp from "sharp";
|
||||
import { publicPath, thumbnailPath, thumbnailPublicPath } from "../paths";
|
||||
import { a, Folder, Image } from "../models";
|
||||
import { createThumbnailAsyncForImage } from "../thumbnails";
|
||||
import { consoleLogger } from "../logging";
|
||||
|
||||
function notEmpty<TValue>(
|
||||
value: TValue | void | null | undefined
|
||||
): value is TValue {
|
||||
return value !== null && value !== undefined;
|
||||
}
|
||||
|
||||
export const getImages =
|
||||
(imagesPath: string) => (req: express.Request, res: express.Response) => {
|
||||
(imagesPath: string) =>
|
||||
async (req: express.Request, res: express.Response) => {
|
||||
const requestedPath = decodeURI(req.path.substring(imagesPath.length));
|
||||
const normalizedPath = requestedPath === "/" ? "" : requestedPath;
|
||||
|
||||
|
|
@ -17,24 +24,32 @@ export const getImages =
|
|||
});
|
||||
const thumbnails = fs.readdirSync(thumbnailPublicPath + requestedPath);
|
||||
|
||||
const images: Image[] = dirents
|
||||
const imagesToBeLoaded = dirents
|
||||
.filter((f) => f.isFile())
|
||||
.map((f) => {
|
||||
const thumbnailExists: boolean = thumbnails.includes(f.name);
|
||||
if (!thumbnailExists) {
|
||||
createThumbnailAsyncForImage(`${requestedPath}/${f.name}`);
|
||||
}
|
||||
|
||||
const dimensions = sizeOf(`${publicPath}${requestedPath}/${f.name}`);
|
||||
const widthAndHeightSwap = dimensions.orientation > 4; // see https://exiftool.org/TagNames/EXIF.html
|
||||
return {
|
||||
src: thumbnailExists
|
||||
? `/staticImages${thumbnailPath}${normalizedPath}/${f.name}`
|
||||
: `/staticImages${normalizedPath}/${f.name}`,
|
||||
width: widthAndHeightSwap ? dimensions.height : dimensions.width,
|
||||
height: widthAndHeightSwap ? dimensions.width : dimensions.height,
|
||||
};
|
||||
return sharp(`${publicPath}${requestedPath}/${f.name}`)
|
||||
.metadata()
|
||||
.then((metadata) => {
|
||||
const widthAndHeightSwap = metadata.orientation > 4; // see https://exiftool.org/TagNames/EXIF.html
|
||||
return a<Image>({
|
||||
src: thumbnailExists
|
||||
? `/staticImages${thumbnailPath}${normalizedPath}/${f.name}`
|
||||
: `/staticImages${normalizedPath}/${f.name}`,
|
||||
width: widthAndHeightSwap ? metadata.height : metadata.width,
|
||||
height: widthAndHeightSwap ? metadata.width : metadata.height,
|
||||
});
|
||||
})
|
||||
.catch((err) => {
|
||||
consoleLogger.error(
|
||||
`Reading metadata from ${publicPath}${requestedPath}/${f.name} produced the following error: ${err.message}`
|
||||
);
|
||||
});
|
||||
});
|
||||
const images = (await Promise.all(imagesToBeLoaded)).filter(notEmpty);
|
||||
res.json(a<Folder>({ images }));
|
||||
} catch (e) {
|
||||
consoleLogger.warn(`Error when trying to access ${req.path}: ${e}`);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,48 @@
|
|||
import fs from "fs";
|
||||
import * as path from "path";
|
||||
import sharp from "sharp";
|
||||
import { Folders } from "./models";
|
||||
import { publicPath, thumbnailPath } from "./paths";
|
||||
import { consoleLogger } from "./logging";
|
||||
|
||||
export const walk = (dirPath: string): Folders => {
|
||||
const dirEnts = fs.readdirSync(`${publicPath}/${dirPath}`, {
|
||||
const isImageProcessable = async (filePath: string): Promise<boolean> =>
|
||||
sharp(filePath)
|
||||
.metadata()
|
||||
.then(() => true)
|
||||
.catch((err) => {
|
||||
consoleLogger.error(
|
||||
`Reading metadata from ${filePath} produced the following error: ${err.message}`
|
||||
);
|
||||
return false;
|
||||
});
|
||||
|
||||
export const walk = async (dirPath: string): Promise<Folders> => {
|
||||
const dirEnts = fs.readdirSync(path.posix.join(publicPath, dirPath), {
|
||||
withFileTypes: true,
|
||||
});
|
||||
|
||||
dirEnts.filter((f) => f.isFile());
|
||||
|
||||
const numberOfFiles = (
|
||||
await Promise.all(
|
||||
dirEnts
|
||||
.filter((f) => f.isFile())
|
||||
.map((f) => path.posix.join(publicPath, dirPath, f.name))
|
||||
.map(isImageProcessable)
|
||||
)
|
||||
).filter((a) => a).length;
|
||||
|
||||
const children = await Promise.all(
|
||||
dirEnts
|
||||
.filter((d) => d.isDirectory())
|
||||
.filter((d) => !d.name.includes(thumbnailPath.substring(1)))
|
||||
.map((d) => walk(path.posix.join(dirPath, d.name)))
|
||||
);
|
||||
|
||||
return {
|
||||
name: path.basename(dirPath) || "Home",
|
||||
fullPath: dirPath,
|
||||
numberOfFiles: dirEnts.filter((f) => f.isFile()).length,
|
||||
children: dirEnts
|
||||
.filter((d) => d.isDirectory())
|
||||
.filter((d) => !d.name.includes(thumbnailPath.substring(1)))
|
||||
.map((d) => walk(path.posix.join(dirPath, d.name))),
|
||||
numberOfFiles,
|
||||
children,
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import sharp from "sharp";
|
|||
import fs from "fs";
|
||||
import path from "path";
|
||||
import { publicPath, thumbnailPath, thumbnailPublicPath } from "./paths";
|
||||
import { consoleLogger } from "./logging";
|
||||
|
||||
const percentage = 25;
|
||||
const minimumPixelForThumbnail = 1024;
|
||||
|
|
@ -29,6 +30,11 @@ export const createThumbnailAsyncForImage = (image: string) => {
|
|||
.toFile(`${thumbnailPublicPath}${image}`);
|
||||
}
|
||||
);
|
||||
})
|
||||
.catch((err) => {
|
||||
consoleLogger.error(
|
||||
`Thumbnail creation of ${publicPath}${image} produced the following error: ${err.message}`
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue