Compare commits

...

3 Commits

Author SHA1 Message Date
mertalev
476e6bdf3a use libmimalloc 2026-03-18 19:28:29 -04:00
Jason Rasmussen
77020e742a fix: validate accept header before returning html (#27019) 2026-03-18 14:15:48 -04:00
Jason Rasmussen
38b135ff36 fix: bounding box return type (#27014) 2026-03-18 11:58:40 -04:00
6 changed files with 51 additions and 18 deletions

View File

@@ -81,7 +81,7 @@ export const connect = async (url: string, key: string) => {
const [error] = await withError(getMyUser());
if (isHttpError(error)) {
logError(error, 'Failed to connect to server');
logError(error, `Failed to connect to server ${url}`);
process.exit(1);
}

View File

@@ -15,13 +15,12 @@ log_message() {
log_message "Initializing Immich $IMMICH_SOURCE_REF"
# TODO: Update to mimalloc v3 when verified memory isn't released issue is fixed
# lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.3"
# if [ -f "$lib_path" ]; then
# export LD_PRELOAD="$lib_path"
# else
# echo "skipping libmimalloc - path not found $lib_path"
# fi
lib_path="/usr/lib/$(arch)-linux-gnu/libmimalloc.so.3"
if [ -f "$lib_path" ]; then
export LD_PRELOAD="$lib_path"
else
echo "skipping libmimalloc - path not found $lib_path"
fi
export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/usr/lib/jellyfin-ffmpeg/lib"
SERVER_HOME="$(readlink -f "$(dirname "$0")/..")"

View File

@@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common';
import { Injectable, NotAcceptableException } from '@nestjs/common';
import { Interval } from '@nestjs/schedule';
import { NextFunction, Request, Response } from 'express';
import { readFileSync } from 'node:fs';
@@ -72,6 +72,13 @@ export class ApiService {
return next();
}
const responseType = request.accepts('text/html');
if (!responseType) {
throw new NotAcceptableException(
`The route ${request.path} was requested as ${request.header('accept')}, but only returns text/html`,
);
}
let status = 200;
let html = index;
@@ -105,7 +112,7 @@ export class ApiService {
html = render(index, meta);
}
res.status(status).type('text/html').header('Cache-Control', 'no-store').send(html);
res.status(status).type(responseType).header('Cache-Control', 'no-store').send(html);
};
}
}

View File

@@ -155,6 +155,33 @@ describe('transformFaceBoundingBox', () => {
expect(result.boundingBoxX2).toBe(50);
expect(result.boundingBoxY2).toBe(50);
});
it('should always return whole numbers', () => {
const edits: AssetEditActionItem[] = [
{ action: AssetEditAction.Crop, parameters: { x: 50, y: 50, width: 250, height: 250 } },
];
expect(transformFaceBoundingBox(baseFace, edits, { width: 1000, height: 400 })).toMatchObject({
boundingBoxX1: 50,
boundingBoxY1: 0,
boundingBoxX2: 150,
boundingBoxY2: 50,
});
expect(transformFaceBoundingBox(baseFace, edits, { width: 1001, height: 401 })).toMatchObject({
boundingBoxX1: 50,
boundingBoxY1: 0,
boundingBoxX2: 150,
boundingBoxY2: 50,
});
expect(transformFaceBoundingBox(baseFace, edits, { width: 999, height: 399 })).toMatchObject({
boundingBoxX1: 49,
boundingBoxY1: -0,
boundingBoxX2: 149,
boundingBoxY2: 49,
});
});
});
});

View File

@@ -179,10 +179,10 @@ export const transformFaceBoundingBox = (
// Ensure x1,y1 is top-left and x2,y2 is bottom-right
const [p1, p2] = transformedPoints;
return {
boundingBoxX1: Math.min(p1.x, p2.x),
boundingBoxY1: Math.min(p1.y, p2.y),
boundingBoxX2: Math.max(p1.x, p2.x),
boundingBoxY2: Math.max(p1.y, p2.y),
boundingBoxX1: Math.trunc(Math.min(p1.x, p2.x)),
boundingBoxY1: Math.trunc(Math.min(p1.y, p2.y)),
boundingBoxX2: Math.trunc(Math.max(p1.x, p2.x)),
boundingBoxY2: Math.trunc(Math.max(p1.y, p2.y)),
imageWidth: currentWidth,
imageHeight: currentHeight,
};

View File

@@ -591,10 +591,10 @@ describe(PersonService.name, () => {
expect.arrayContaining([
expect.objectContaining({
person: expect.objectContaining({ id: person.id }),
boundingBoxX1: expect.closeTo(25, 1),
boundingBoxY1: expect.closeTo(50, 1),
boundingBoxX2: expect.closeTo(100, 1),
boundingBoxY2: expect.closeTo(100, 1),
boundingBoxX1: 25,
boundingBoxY1: 49,
boundingBoxX2: 99,
boundingBoxY2: 100,
}),
]),
);