Add server, DB, and image processing modules

Introduce initial project scaffold: Express webhook server (server.js) for Immich uploads, DB pool (modules/database.js) using pg, immich repository (repositories/immichRepo.js) with get/update functions, image processing via sharp (modules/image_processor.js), a small execution helper (modules/execution_helper.js), and package.json + package-lock. Server validates a bearer token, filters non-image assets, waits briefly, compresses the image and updates DB path. Requires env vars: DB_HOST, DB_USER, DB_PORT, DB_NAME, DB_PASS, PASS_CODE, IMMICH_DATA_PATH, IMG_COMPRESSION_OUTPUT_FORMAT, IMG_COMPRESSION_OUTPUT_QUALITY, PORT.
This commit is contained in:
2026-09-01 20:12:29 +02:00
parent feb3e9a417
commit d5563ad946
7 changed files with 2152 additions and 0 deletions
+18
View File
@@ -0,0 +1,18 @@
import { Pool } from "pg"
export const pool = new Pool({
host: process.env.DB_HOST,
user: process.env.DB_USER,
port: process.env.DB_PORT,
database: process.env.DB_NAME,
password: process.env.DB_PASS,
})
export async function connect() {
await pool.connect()
}
export default {
pool,
connect
}
+7
View File
@@ -0,0 +1,7 @@
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms))
}
export default {
sleep
}
+43
View File
@@ -0,0 +1,43 @@
import path from "node:path"
import fs from "node:fs/promises"
import sharp from "sharp"
const IMAGE_EXTENSIONS = new Set([ ".jpg", ".jpeg", ".png", ".heic", ".heif", ".gif", ".tiff", ".bmp", ".svg", ".avif", ".raw", ".dng" ])
const VIDEO_EXTENSIONS = new Set([ ".mp4", ".mov", ".avi", ".mkv", ".webm", ".flv", ".wmv", ".m4v", ".3gp", ".ts" ])
function getMediaType(filePath) {
if (!filePath) return "unknown"
const ext = path.extname(filePath).toLowerCase()
if (IMAGE_EXTENSIONS.has(ext)) return "image"
if (VIDEO_EXTENSIONS.has(ext)) return "video"
return "unknown"
}
function changeExtension(filePath, newExt) {
const formattedExt = newExt.startsWith(".") ? newExt : `.${newExt}`
const parsed = path.parse(filePath)
parsed.base = `${parsed.name}${formattedExt}`
parsed.ext = formattedExt
return path.format(parsed)
}
async function processCompression($file) {
const file = $file.replace("/data", process.env.IMMICH_DATA_PATH)
const newFilePath = changeExtension(file, process.env.IMG_COMPRESSION_OUTPUT_FORMAT)
const compressedFile = await sharp(file)
.toFormat(process.env.IMG_COMPRESSION_OUTPUT_FORMAT,
{ quality: parseInt(process.env.IMG_COMPRESSION_OUTPUT_QUALITY) || 80 }
)
.toFile(newFilePath)
}
export default {
getMediaType,
changeExtension,
processCompression
}
+1993
View File
File diff suppressed because it is too large Load Diff
+23
View File
@@ -0,0 +1,23 @@
{
"name": "immich-photo-compressor",
"version": "0.0.1-alpha",
"description": "a webhook tool to compress file post uploaded on immich",
"license": "MIT",
"author": {
"email": "gilleslazure04@gmail.com",
"name": "azures04",
"url": "https://azures.fr"
},
"type": "module",
"main": "server.js",
"scripts": {
"test": "node"
},
"dependencies": {
"dotenv": "^17.4.2",
"express": "^5.2.1",
"nodemon": "^3.1.14",
"pg": "^8.23.0",
"sharp": "^0.35.4"
}
}
+31
View File
@@ -0,0 +1,31 @@
import { pool } from "../modules/database.js"
async function getMediaInDatabase(mediaId) {
try {
const query = "SELECT * FROM asset WHERE id = $1"
const values = [mediaId]
const response = await pool.query(query, values)
return response.rows
} catch (error) {
console.error("Erreur dans getMediaInDatabase:", error)
throw error
}
}
async function updateMediaPathInDatabase(mediaId, newPath) {
try {
const query = "UPDATE asset SET \"originalPath\" = $1 WHERE id = $2"
const values = [newPath, mediaId]
const response = await pool.query(query, values)
return response.rows
} catch (error) {
console.error("Erreur dans updateMediaPathInDatabase:", error)
throw error
}
}
export default {
getMediaInDatabase,
updateMediaPathInDatabase
}
+37
View File
@@ -0,0 +1,37 @@
import "dotenv/config"
import express from "express"
import database from "./modules/database.js"
import immichDb from "./repositories/immichRepo.js"
import execHelper from "./modules/execution_helper.js"
import imageProcessor from "./modules/image_processor.js"
await database.connect()
const app = express()
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.post("/", async (req, res) => {
const authorization = req.headers.authorization
if (authorization != `Bearer ${process.env.PASS_CODE}`) {
res.status(401).send()
}
const assetType = req.body.data.asset.type
if (assetType != "IMAGE") {
res.end()
}
const assetFilePath = req.body.data.asset.originalPath
if (imageProcessor.getMediaType(assetFilePath) != "IMAGE") {
res.end()
}
const assetId = req.body.data.asset.id
await execHelper.sleep(550)
const asset = await immichDb.getMediaInDatabase(assetId)
await imageProcessor.processCompression(asset[0].originalPath)
immichDb.updateMediaPathInDatabase(assetId, imageProcessor.changeExtension(asset[0].originalPath, process.env.IMG_COMPRESSION_OUTPUT_FORMAT))
return res.status(200).send()
})
app.listen(process.env.PORT, () => {
return console.log(`Server listening at port : ${process.env.PORT}`)
})