mirror of
https://github.com/immich-app/immich.git
synced 2026-05-22 07:32:32 -04:00
feat(server): track video metadata (#28023)
* track video metadata * earlier duration check * revert colorspace change * duplicate constant * formatting * linting * add comments * redundant variable * simplify tests * use totalDuration instead of format.duration * medium tests * install ffmpeg * install noble * update test-assets commit * make timeBase non-nullable * linting * use proper smallint * add ffmpeg to mise * simplify duration * regenerate migration
This commit is contained in:
@@ -17,11 +17,11 @@ import { jsonArrayFrom, jsonObjectFrom } from 'kysely/helpers/postgres';
|
||||
import { Notice, PostgresError } from 'postgres';
|
||||
import { columns, lockableProperties, LockableProperty, Person } from 'src/database';
|
||||
import { AssetEditActionItem } from 'src/dtos/editing.dto';
|
||||
import { AssetFileType, AssetVisibility, DatabaseExtension } from 'src/enum';
|
||||
import { AssetFileType, AssetVisibility, DatabaseExtension, ExifOrientation } from 'src/enum';
|
||||
import { AssetSearchBuilderOptions } from 'src/repositories/search.repository';
|
||||
import { DB } from 'src/schema';
|
||||
import { AssetExifTable } from 'src/schema/tables/asset-exif.table';
|
||||
import { VectorExtension } from 'src/types';
|
||||
import { AudioStreamInfo, VectorExtension, VideoFormat, VideoStreamInfo } from 'src/types';
|
||||
|
||||
export const getKyselyConfig = (connection: DatabaseConnectionParams): KyselyConfig => {
|
||||
return {
|
||||
@@ -99,6 +99,65 @@ export function withExifInner<O>(qb: SelectQueryBuilder<DB, 'asset', O>) {
|
||||
.$narrowType<{ exifInfo: NotNull }>();
|
||||
}
|
||||
|
||||
export const dummy = sql`(select 1)`.as('dummy');
|
||||
|
||||
export function withAudioStream(eb: ExpressionBuilder<DB, 'asset_exif' | 'asset_audio'>) {
|
||||
return jsonObjectFrom(
|
||||
eb
|
||||
.selectFrom(dummy)
|
||||
.select(['asset_audio.index', 'asset_audio.codecName', 'asset_audio.profile', 'asset_audio.bitrate'])
|
||||
.where('asset_audio.assetId', 'is not', sql.lit(null))
|
||||
.$castTo<AudioStreamInfo | null>(),
|
||||
);
|
||||
}
|
||||
|
||||
export function withVideoStream(eb: ExpressionBuilder<DB, 'asset_exif' | 'asset_video'>) {
|
||||
return jsonObjectFrom(
|
||||
eb
|
||||
.selectFrom(dummy)
|
||||
.select((eb) => [
|
||||
'asset_video.index',
|
||||
'asset_video.codecName',
|
||||
'asset_video.profile',
|
||||
'asset_video.level',
|
||||
'asset_video.bitrate',
|
||||
'asset_exif.exifImageWidth as width',
|
||||
'asset_exif.exifImageHeight as height',
|
||||
'asset_video.pixelFormat',
|
||||
'asset_video.frameCount',
|
||||
'asset_exif.fps as frameRate',
|
||||
'asset_video.timeBase',
|
||||
eb
|
||||
.case()
|
||||
.when('asset_exif.orientation', '=', sql.lit(ExifOrientation.Rotate90CW.toString()))
|
||||
.then(sql.lit(-90))
|
||||
.when('asset_exif.orientation', '=', sql.lit(ExifOrientation.Rotate270CW.toString()))
|
||||
.then(sql.lit(90))
|
||||
.when('asset_exif.orientation', '=', sql.lit(ExifOrientation.Rotate180.toString()))
|
||||
.then(sql.lit(180))
|
||||
.else(0)
|
||||
.end()
|
||||
.as('rotation'),
|
||||
'asset_video.colorPrimaries',
|
||||
'asset_video.colorMatrix',
|
||||
'asset_video.colorTransfer',
|
||||
'asset_video.dvProfile',
|
||||
'asset_video.dvLevel',
|
||||
'asset_video.dvBlSignalCompatibilityId',
|
||||
])
|
||||
.where('asset_video.assetId', 'is not', sql.lit(null)),
|
||||
).$castTo<(VideoStreamInfo & { timeBase: NotNull }) | null>();
|
||||
}
|
||||
|
||||
export function withVideoFormat(eb: ExpressionBuilder<DB, 'asset' | 'asset_video'>) {
|
||||
return jsonObjectFrom(
|
||||
eb
|
||||
.selectFrom(dummy)
|
||||
.select(['asset_video.formatName', 'asset_video.formatLongName', 'asset.duration', 'asset_video.bitrate'])
|
||||
.where('asset_video.assetId', 'is not', sql.lit(null)),
|
||||
).$castTo<VideoFormat | null>();
|
||||
}
|
||||
|
||||
export function withSmartSearch<O>(qb: SelectQueryBuilder<DB, 'asset', O>) {
|
||||
return qb
|
||||
.leftJoin('smart_search', 'asset.id', 'smart_search.assetId')
|
||||
@@ -445,5 +504,3 @@ export const updateLockedColumns = <T extends Record<string, unknown> & { locked
|
||||
exif.lockedProperties = lockableProperties.filter((property) => property in exif);
|
||||
return exif;
|
||||
};
|
||||
|
||||
export const dummy = sql`(select 1)`.as('dummy');
|
||||
|
||||
Reference in New Issue
Block a user