@ -1,10 +1,16 @@
import { BadRequestException , Injectable , InternalServerErrorException , Logger , StreamableFile } from '@nestjs/common' ;
import {
BadRequestException ,
Injectable ,
InternalServerErrorException ,
Logger ,
NotFoundException ,
StreamableFile ,
} from '@nestjs/common' ;
import { InjectRepository } from '@nestjs/typeorm' ;
import { IsNull , Not , Repository } from 'typeorm' ;
import { AuthUserDto } from '../../decorators/auth-user.decorator' ;
import { CreateAssetDto } from './dto/create-asset.dto' ;
import { AssetEntity , AssetType } from '@app/database/entities/asset.entity' ;
import _ from 'lodash' ;
import { createReadStream , stat } from 'fs' ;
import { ServeFileDto } from './dto/serve-file.dto' ;
import { Response as Res } from 'express' ;
@ -33,7 +39,12 @@ export class AssetService {
return updatedAsset . raw [ 0 ] ;
}
public async createUserAsset ( authUser : AuthUserDto , assetInfo : CreateAssetDto , path : string , mimeType : string ) {
public async createUserAsset (
authUser : AuthUserDto ,
assetInfo : CreateAssetDto ,
path : string ,
mimeType : string ,
) : Promise < AssetEntity | undefined > {
const asset = new AssetEntity ( ) ;
asset . deviceAssetId = assetInfo . deviceAssetId ;
asset . userId = authUser . id ;
@ -44,10 +55,14 @@ export class AssetService {
asset . modifiedAt = assetInfo . modifiedAt ;
asset . isFavorite = assetInfo . isFavorite ;
asset . mimeType = mimeType ;
asset . duration = assetInfo . duration ;
asset . duration = assetInfo . duration || null ;
try {
return await this . assetRepository . save ( asset ) ;
const createdAsset = await this . assetRepository . save ( asset ) ;
if ( ! createdAsset ) {
throw new Error ( 'Asset not created' ) ;
}
return createdAsset ;
} catch ( e ) {
Logger . error ( ` Error Create New Asset ${ e } ` , 'createUserAsset' ) ;
}
@ -62,7 +77,7 @@ export class AssetService {
select : [ 'deviceAssetId' ] ,
} ) ;
const res = [ ] ;
const res : string [ ] = [ ] ;
rows . forEach ( ( v ) = > res . push ( v . deviceAssetId ) ) ;
return res ;
}
@ -119,6 +134,9 @@ export class AssetService {
} ) ;
file = createReadStream ( asset . originalPath ) ;
} else {
if ( ! asset . resizePath ) {
throw new Error ( 'resizePath not set' ) ;
}
const { size } = await fileInfo ( asset . resizePath ) ;
res . set ( {
'Content-Type' : 'image/jpeg' ,
@ -134,16 +152,25 @@ export class AssetService {
}
}
public async getAssetThumbnail ( assetId : string ) {
public async getAssetThumbnail ( assetId : string ) : Promise < StreamableFile > {
try {
const asset = await this . assetRepository . findOne ( { id : assetId } ) ;
if ( ! asset ) {
throw new NotFoundException ( 'Asset not found' ) ;
}
if ( asset . webpPath && asset . webpPath . length > 0 ) {
return new StreamableFile ( createReadStream ( asset . webpPath ) ) ;
} else {
if ( ! asset . resizePath ) {
throw new Error ( 'resizePath not set' ) ;
}
return new StreamableFile ( createReadStream ( asset . resizePath ) ) ;
}
} catch ( e ) {
if ( e instanceof NotFoundException ) {
throw e ;
}
Logger . error ( 'Error serving asset thumbnail ' , e ) ;
throw new InternalServerErrorException ( 'Failed to serve asset thumbnail' , 'GetAssetThumbnail' ) ;
}
@ -154,6 +181,7 @@ export class AssetService {
const asset = await this . findOne ( query . did , query . aid ) ;
if ( ! asset ) {
// TODO: maybe this should be a NotFoundException?
throw new BadRequestException ( 'Asset does not exist' ) ;
}
@ -166,6 +194,10 @@ export class AssetService {
res . set ( {
'Content-Type' : 'image/jpeg' ,
} ) ;
if ( ! asset . resizePath ) {
Logger . error ( 'Error serving IMAGE asset for web' , 'ServeFile' ) ;
throw new InternalServerErrorException ( ` Failed to serve image asset for web ` , 'ServeFile' ) ;
}
return new StreamableFile ( createReadStream ( asset . resizePath ) ) ;
}
@ -189,6 +221,9 @@ export class AssetService {
res . set ( {
'Content-Type' : 'image/jpeg' ,
} ) ;
if ( ! asset . resizePath ) {
throw new Error ( 'resizePath not set' ) ;
}
file = createReadStream ( asset . resizePath ) ;
}
}
@ -297,6 +332,7 @@ export class AssetService {
async getAssetSearchTerm ( authUser : AuthUserDto ) : Promise < string [ ] > {
const possibleSearchTerm = new Set < string > ( ) ;
// TODO: should use query builder
const rows = await this . assetRepository . query (
`
select distinct si . tags , si . objects , e . orientation , e . "lensModel" , e . make , e . model , a . type , e . city , e . state , e . country
@ -308,12 +344,12 @@ export class AssetService {
[ authUser . id ] ,
) ;
rows . forEach ( ( row ) = > {
rows . forEach ( ( row : { [ x : string ] : any } ) = > {
// tags
row [ 'tags' ] ? . map ( ( tag ) = > possibleSearchTerm . add ( tag ? . toLowerCase ( ) ) ) ;
row [ 'tags' ] ? . map ( ( tag : string ) = > possibleSearchTerm . add ( tag ? . toLowerCase ( ) ) ) ;
// objects
row [ 'objects' ] ? . map ( ( object ) = > possibleSearchTerm . add ( object ? . toLowerCase ( ) ) ) ;
row [ 'objects' ] ? . map ( ( object : string ) = > possibleSearchTerm . add ( object ? . toLowerCase ( ) ) ) ;
// asset's tyoe
possibleSearchTerm . add ( row [ 'type' ] ? . toLowerCase ( ) ) ;
@ -345,7 +381,7 @@ export class AssetService {
LEFT JOIN exif e ON a . id = e . "assetId"
WHERE a . "userId" = $1
AND
AND
(
TO_TSVECTOR ( 'english' , ARRAY_TO_STRING ( si . tags , ',' ) ) @ @ PLAINTO_TSQUERY ( 'english' , $2 ) OR
TO_TSVECTOR ( 'english' , ARRAY_TO_STRING ( si . objects , ',' ) ) @ @ PLAINTO_TSQUERY ( 'english' , $2 ) OR
@ -362,7 +398,7 @@ export class AssetService {
select distinct on ( e . city ) a . id , e . city , a . "resizePath" , a . "deviceAssetId" , a . "deviceId"
from assets a
left join exif e on a . id = e . "assetId"
where a . "userId" = $1
where a . "userId" = $1
and e . city is not null
and a . type = 'IMAGE' ;
` ,
@ -376,7 +412,7 @@ export class AssetService {
select distinct on ( unnest ( si . objects ) ) a . id , unnest ( si . objects ) as "object" , a . "resizePath" , a . "deviceAssetId" , a . "deviceId"
from assets a
left join smart_info si on a . id = si . "assetId"
where a . "userId" = $1
where a . "userId" = $1
and si . objects is not null
` ,
[ authUser . id ] ,