mirror of
https://github.com/KevinMidboe/immich.git
synced 2025-12-08 12:19:05 +00:00
feat(web,server): add thumbhash support (#2649)
* add thumbhash: server generation and web impl * move logic to infra & use byta in db * remove unnecesary logs * update generated API and simplify thumbhash gen * fix check errors * removed unnecessary library and css tag * style edits * syntax mistake * update server test, change thumbhash job name * fix tests * Update server/src/domain/asset/response-dto/asset-response.dto.ts Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> * add unit test, change migration date * change to official thumbhash impl * update call method to not use eval * "generate missing" looks for thumbhash * improve queue & improve syntax * update syntax again * update tests * fix thumbhash generation * consolidate queueing to avoid duplication * cover all types of incorrect thumbnail cases * split out jest tasks * put back thumbnail duration loading for images without thumbhash * Remove stray package.json --------- Co-authored-by: Luke McCarthy <mail@lukehmcc.com> Co-authored-by: Thomas <9749173+uhthomas@users.noreply.github.com> Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
@@ -54,9 +54,9 @@ describe(MediaService.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should queue all assets with missing thumbnails', async () => {
|
||||
it('should queue all assets with missing resize path', async () => {
|
||||
assetMock.getWithout.mockResolvedValue({
|
||||
items: [assetEntityStub.image],
|
||||
items: [assetEntityStub.noResizePath],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
@@ -69,6 +69,38 @@ describe(MediaService.name, () => {
|
||||
data: { id: assetEntityStub.image.id },
|
||||
});
|
||||
});
|
||||
|
||||
it('should queue all assets with missing webp path', async () => {
|
||||
assetMock.getWithout.mockResolvedValue({
|
||||
items: [assetEntityStub.noWebpPath],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await sut.handleQueueGenerateThumbnails({ force: false });
|
||||
|
||||
expect(assetMock.getAll).not.toHaveBeenCalled();
|
||||
expect(assetMock.getWithout).toHaveBeenCalledWith({ skip: 0, take: 1000 }, WithoutProperty.THUMBNAIL);
|
||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||
name: JobName.GENERATE_WEBP_THUMBNAIL,
|
||||
data: { id: assetEntityStub.image.id },
|
||||
});
|
||||
});
|
||||
|
||||
it('should queue all assets with missing thumbhash', async () => {
|
||||
assetMock.getWithout.mockResolvedValue({
|
||||
items: [assetEntityStub.noThumbhash],
|
||||
hasNextPage: false,
|
||||
});
|
||||
|
||||
await sut.handleQueueGenerateThumbnails({ force: false });
|
||||
|
||||
expect(assetMock.getAll).not.toHaveBeenCalled();
|
||||
expect(assetMock.getWithout).toHaveBeenCalledWith({ skip: 0, take: 1000 }, WithoutProperty.THUMBNAIL);
|
||||
expect(jobMock.queue).toHaveBeenCalledWith({
|
||||
name: JobName.GENERATE_THUMBHASH_THUMBNAIL,
|
||||
data: { id: assetEntityStub.image.id },
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleGenerateJpegThumbnail', () => {
|
||||
@@ -129,6 +161,25 @@ describe(MediaService.name, () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleGenerateThumbhashThumbnail', () => {
|
||||
it('should skip thumbhash generation if resize path is missing', async () => {
|
||||
assetMock.getByIds.mockResolvedValue([assetEntityStub.noResizePath]);
|
||||
await sut.handleGenerateThumbhashThumbnail({ id: assetEntityStub.noResizePath.id });
|
||||
expect(mediaMock.generateThumbhash).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should generate a thumbhash', async () => {
|
||||
const thumbhashBuffer = Buffer.from('a thumbhash', 'utf8');
|
||||
assetMock.getByIds.mockResolvedValue([assetEntityStub.image]);
|
||||
mediaMock.generateThumbhash.mockResolvedValue(thumbhashBuffer);
|
||||
|
||||
await sut.handleGenerateThumbhashThumbnail({ id: assetEntityStub.image.id });
|
||||
|
||||
expect(mediaMock.generateThumbhash).toHaveBeenCalledWith('/uploads/user-id/thumbs/path.ext');
|
||||
expect(assetMock.save).toHaveBeenCalledWith({ id: 'asset-id', thumbhash: thumbhashBuffer });
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleQueueVideoConversion', () => {
|
||||
it('should queue all video assets', async () => {
|
||||
assetMock.getAll.mockResolvedValue({
|
||||
|
||||
Reference in New Issue
Block a user