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