Created
May 16, 2025 21:10
-
-
Save pdaug/d04a6aed7a3c174bd34a57fa90bb1d9a to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sharp from "sharp"; | |
import fileTyper, { FileTypeResult } from "file-type"; | |
import { statSync, readFileSync, existsSync } from "fs"; | |
// utils | |
import Hash from "./Hash"; | |
import Logger from "./Logger"; | |
export type MetadataInfo = { | |
size: number; | |
updatedAt: Date; | |
createdAt: Date; | |
accessedAt: Date; | |
}; | |
export type MetadataImage = { | |
size: number; | |
updatedAt: Date; | |
createdAt: Date; | |
accessedAt: Date; | |
}; | |
class Metadata { | |
pathOrSource: string | Buffer; | |
logger: Logger; | |
constructor(pathOrSource: string | Buffer) { | |
this.pathOrSource = pathOrSource; | |
this.logger = new Logger("src/utils/Metadata.ts"); | |
return; | |
} | |
info(): MetadataInfo | null { | |
if (!this.pathOrSource) return null; | |
if (typeof this.pathOrSource === "string" && existsSync(this.pathOrSource)) { | |
const stats = statSync(this.pathOrSource); | |
const info = { | |
size: stats.size, | |
updatedAt: new Date(stats.mtimeMs), | |
createdAt: new Date(stats.birthtimeMs), | |
accessedAt: new Date(stats.atimeMs), | |
}; | |
return info; | |
} | |
this.logger.debug("warn", "no_info_path", this.pathOrSource); | |
this.logger.send({ | |
action: "METADATA", | |
}); | |
return null; | |
} | |
async md5(): Promise<string | null> { | |
if (!this.pathOrSource) return null; | |
const fileSource = typeof this.pathOrSource === "string" ? readFileSync(this.pathOrSource) : this.pathOrSource; | |
const hasher = new Hash("md5", fileSource); | |
const fileHashed = await hasher.make(); | |
return fileHashed; | |
} | |
async mimetype(): Promise<FileTypeResult | null> { | |
if (!this.pathOrSource) return null; | |
try { | |
let result = null; | |
if (this.pathOrSource instanceof Buffer) result = await fileTyper.fromBuffer(this.pathOrSource); | |
if (typeof this.pathOrSource === "string") result = await fileTyper.fromFile(this.pathOrSource); | |
return result || null; | |
} catch (err) { | |
this.logger.debug("error", "failed_load_metadata", err); | |
await this.logger.send({ | |
action: "METADATA", | |
err, | |
}); | |
return null; | |
} | |
} | |
async image(): Promise<sharp.Metadata | null> { | |
if (!this.pathOrSource) return null; | |
try { | |
const result = await this.mimetype(); | |
if (!result || !result?.mime?.includes("image/")) { | |
this.logger.debug("warn", "not_image", result); | |
this.logger.send({ | |
action: "METADATA", | |
}); | |
return null; | |
} | |
const sharpInstance = sharp(this.pathOrSource); | |
const metadata = await sharpInstance.metadata(); | |
return metadata; | |
} catch (err) { | |
this.logger.debug("error", "failed_image_metadata", err); | |
await this.logger.send({ | |
action: "METADATA", | |
err, | |
}); | |
return null; | |
} | |
} | |
} | |
export default Metadata; | |
describe("Metadata", function () { | |
it("should get info", async function () { | |
const metadataInstance = new Metadata("./src/public/logo.png"); | |
const info = metadataInstance.info(); | |
expect(info).toBeTruthy(); | |
expect(info).not.toBeNull(); | |
expect(typeof info?.size).toBe("number"); | |
expect(info?.updatedAt instanceof Date).toBeTruthy(); | |
expect(info?.createdAt instanceof Date).toBeTruthy(); | |
expect(info?.accessedAt instanceof Date).toBeTruthy(); | |
return; | |
}); | |
it("should get md5", async function () { | |
const metadataInstance = new Metadata("./src/public/logo.png"); | |
const md5 = await metadataInstance.md5(); | |
expect(md5).toBeTruthy(); | |
expect(md5).not.toBeNull(); | |
expect(typeof md5).toBe("string"); | |
return; | |
}); | |
it("should get mimetype", async function () { | |
const metadataInstance = new Metadata("./src/public/logo.png"); | |
const mimetype = await metadataInstance.mimetype(); | |
expect(mimetype).toBeTruthy(); | |
expect(mimetype).not.toBeNull(); | |
expect(mimetype?.ext).toBe("png"); | |
expect(mimetype?.mime).toBe("image/png"); | |
return; | |
}); | |
it("should get image metadata", async function () { | |
const metadataInstance = new Metadata("./src/public/logo.png"); | |
const imageMetadata = await metadataInstance.image(); | |
expect(imageMetadata).toBeTruthy(); | |
expect(imageMetadata).not.toBeNull(); | |
expect(imageMetadata?.format).toBe("png"); | |
expect(typeof imageMetadata?.width).toBe("number"); | |
expect(typeof imageMetadata?.height).toBe("number"); | |
return; | |
}); | |
return; | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment