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:
Covalent
2023-06-17 23:22:31 -04:00
committed by GitHub
parent 3512140148
commit 3e804f16df
29 changed files with 354 additions and 29 deletions

View File

@@ -196,7 +196,8 @@ export const assetEntityStub = {
resizePath: null,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.IMAGE,
webpPath: null,
webpPath: '/uploads/user-id/webp/path.ext',
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
@@ -212,7 +213,7 @@ export const assetEntityStub = {
faces: [],
sidecarPath: null,
}),
image: Object.freeze<AssetEntity>({
noWebpPath: Object.freeze<AssetEntity>({
id: 'asset-id',
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
@@ -225,6 +226,67 @@ export const assetEntityStub = {
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.IMAGE,
webpPath: null,
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
mimeType: null,
isFavorite: true,
isArchived: false,
duration: null,
isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null,
tags: [],
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
sidecarPath: null,
}),
noThumbhash: Object.freeze<AssetEntity>({
id: 'asset-id',
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userEntityStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
resizePath: '/uploads/user-id/thumbs/path.ext',
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.IMAGE,
webpPath: '/uploads/user-id/webp/path.ext',
thumbhash: null,
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
mimeType: null,
isFavorite: true,
isArchived: false,
duration: null,
isVisible: true,
livePhotoVideo: null,
livePhotoVideoId: null,
tags: [],
sharedLinks: [],
originalFileName: 'asset-id.ext',
faces: [],
sidecarPath: null,
}),
image: Object.freeze<AssetEntity>({
id: 'asset-id',
deviceAssetId: 'device-asset-id',
fileModifiedAt: new Date('2023-02-23T05:06:29.716Z'),
fileCreatedAt: new Date('2023-02-23T05:06:29.716Z'),
owner: userEntityStub.user1,
ownerId: 'user-id',
deviceId: 'device-id',
originalPath: '/original/path.ext',
resizePath: '/uploads/user-id/thumbs/path.ext',
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.IMAGE,
webpPath: '/uploads/user-id/webp/path.ext',
thumbhash: Buffer.from('blablabla', 'base64'),
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
@@ -255,6 +317,7 @@ export const assetEntityStub = {
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.VIDEO,
webpPath: null,
thumbhash: null,
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
@@ -305,6 +368,7 @@ export const assetEntityStub = {
sidecarPath: null,
type: AssetType.IMAGE,
webpPath: null,
thumbhash: null,
encodedVideoPath: null,
createdAt: new Date('2023-02-23T05:06:29.716Z'),
updatedAt: new Date('2023-02-23T05:06:29.716Z'),
@@ -334,6 +398,7 @@ export const assetEntityStub = {
deviceId: 'device-id',
originalPath: '/original/path.ext',
resizePath: '/uploads/user-id/thumbs/path.ext',
thumbhash: null,
checksum: Buffer.from('file hash', 'utf8'),
type: AssetType.IMAGE,
webpPath: null,
@@ -507,6 +572,7 @@ const assetResponse: AssetResponseDto = {
originalPath: 'fake_path/jpeg',
originalFileName: 'asset_1.jpeg',
resized: false,
thumbhash: null,
fileModifiedAt: today,
fileCreatedAt: today,
updatedAt: today,
@@ -787,6 +853,7 @@ export const sharedLinkStub = {
clipEmbedding: [0.12, 0.13, 0.14],
},
webpPath: '',
thumbhash: null,
encodedVideoPath: '',
duration: null,
isVisible: true,

View File

@@ -3,6 +3,7 @@ import { IMediaRepository } from '@app/domain';
export const newMediaRepositoryMock = (): jest.Mocked<IMediaRepository> => {
return {
extractVideoThumbnail: jest.fn(),
generateThumbhash: jest.fn(),
resize: jest.fn(),
crop: jest.fn(),
probe: jest.fn(),