mirror of
https://github.com/immich-app/immich.git
synced 2025-05-31 04:05:39 -04:00
refactor: migrate media repository (#15536)
This commit is contained in:
parent
30b8864d2d
commit
66849d0d45
@ -12,7 +12,7 @@ import {
|
|||||||
VideoContainer,
|
VideoContainer,
|
||||||
} from 'src/enum';
|
} from 'src/enum';
|
||||||
import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface';
|
import { ConcurrentQueueName, QueueName } from 'src/interfaces/job.interface';
|
||||||
import { ImageOptions } from 'src/interfaces/media.interface';
|
import { ImageOptions } from 'src/types';
|
||||||
|
|
||||||
export interface SystemConfig {
|
export interface SystemConfig {
|
||||||
backup: {
|
backup: {
|
||||||
|
@ -1,151 +0,0 @@
|
|||||||
import { Writable } from 'node:stream';
|
|
||||||
import { ExifOrientation, ImageFormat, TranscodeTarget, VideoCodec } from 'src/enum';
|
|
||||||
|
|
||||||
export const IMediaRepository = 'IMediaRepository';
|
|
||||||
|
|
||||||
export interface CropOptions {
|
|
||||||
top: number;
|
|
||||||
left: number;
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageOptions {
|
|
||||||
format: ImageFormat;
|
|
||||||
quality: number;
|
|
||||||
size: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface RawImageInfo {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
channels: 1 | 2 | 3 | 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface DecodeImageOptions {
|
|
||||||
colorspace: string;
|
|
||||||
crop?: CropOptions;
|
|
||||||
processInvalidImages: boolean;
|
|
||||||
raw?: RawImageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface DecodeToBufferOptions extends DecodeImageOptions {
|
|
||||||
size: number;
|
|
||||||
orientation?: ExifOrientation;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type GenerateThumbnailOptions = ImageOptions & DecodeImageOptions;
|
|
||||||
|
|
||||||
export type GenerateThumbnailFromBufferOptions = GenerateThumbnailOptions & { raw: RawImageInfo };
|
|
||||||
|
|
||||||
export type GenerateThumbhashOptions = DecodeImageOptions;
|
|
||||||
|
|
||||||
export type GenerateThumbhashFromBufferOptions = GenerateThumbhashOptions & { raw: RawImageInfo };
|
|
||||||
|
|
||||||
export interface GenerateThumbnailsOptions {
|
|
||||||
colorspace: string;
|
|
||||||
crop?: CropOptions;
|
|
||||||
preview?: ImageOptions;
|
|
||||||
processInvalidImages: boolean;
|
|
||||||
thumbhash?: boolean;
|
|
||||||
thumbnail?: ImageOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoStreamInfo {
|
|
||||||
index: number;
|
|
||||||
height: number;
|
|
||||||
width: number;
|
|
||||||
rotation: number;
|
|
||||||
codecName?: string;
|
|
||||||
frameCount: number;
|
|
||||||
isHDR: boolean;
|
|
||||||
bitrate: number;
|
|
||||||
pixelFormat: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AudioStreamInfo {
|
|
||||||
index: number;
|
|
||||||
codecName?: string;
|
|
||||||
frameCount: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoFormat {
|
|
||||||
formatName?: string;
|
|
||||||
formatLongName?: string;
|
|
||||||
duration: number;
|
|
||||||
bitrate: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageDimensions {
|
|
||||||
width: number;
|
|
||||||
height: number;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface InputDimensions extends ImageDimensions {
|
|
||||||
inputPath: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoInfo {
|
|
||||||
format: VideoFormat;
|
|
||||||
videoStreams: VideoStreamInfo[];
|
|
||||||
audioStreams: AudioStreamInfo[];
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TranscodeCommand {
|
|
||||||
inputOptions: string[];
|
|
||||||
outputOptions: string[];
|
|
||||||
twoPass: boolean;
|
|
||||||
progress: {
|
|
||||||
frameCount: number;
|
|
||||||
percentInterval: number;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface BitrateDistribution {
|
|
||||||
max: number;
|
|
||||||
target: number;
|
|
||||||
min: number;
|
|
||||||
unit: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ImageBuffer {
|
|
||||||
data: Buffer;
|
|
||||||
info: RawImageInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoCodecSWConfig {
|
|
||||||
getCommand(
|
|
||||||
target: TranscodeTarget,
|
|
||||||
videoStream: VideoStreamInfo,
|
|
||||||
audioStream: AudioStreamInfo,
|
|
||||||
format?: VideoFormat,
|
|
||||||
): TranscodeCommand;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoCodecHWConfig extends VideoCodecSWConfig {
|
|
||||||
getSupportedCodecs(): Array<VideoCodec>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProbeOptions {
|
|
||||||
countFrames: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface VideoInterfaces {
|
|
||||||
dri: string[];
|
|
||||||
mali: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface IMediaRepository {
|
|
||||||
// image
|
|
||||||
extract(input: string, output: string): Promise<boolean>;
|
|
||||||
decodeImage(input: string, options: DecodeToBufferOptions): Promise<ImageBuffer>;
|
|
||||||
generateThumbnail(input: string, options: GenerateThumbnailOptions, outputFile: string): Promise<void>;
|
|
||||||
generateThumbnail(input: Buffer, options: GenerateThumbnailFromBufferOptions, outputFile: string): Promise<void>;
|
|
||||||
generateThumbhash(input: string, options: GenerateThumbhashOptions): Promise<Buffer>;
|
|
||||||
generateThumbhash(input: Buffer, options: GenerateThumbhashFromBufferOptions): Promise<Buffer>;
|
|
||||||
getImageDimensions(input: string): Promise<ImageDimensions>;
|
|
||||||
|
|
||||||
// video
|
|
||||||
probe(input: string, options?: ProbeOptions): Promise<VideoInfo>;
|
|
||||||
transcode(input: string, output: string | Writable, command: TranscodeCommand): Promise<void>;
|
|
||||||
}
|
|
@ -10,7 +10,6 @@ import { ILibraryRepository } from 'src/interfaces/library.interface';
|
|||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
|
||||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||||
@ -77,6 +76,7 @@ export const repositories = [
|
|||||||
AuditRepository,
|
AuditRepository,
|
||||||
ApiKeyRepository,
|
ApiKeyRepository,
|
||||||
ConfigRepository,
|
ConfigRepository,
|
||||||
|
MediaRepository,
|
||||||
MemoryRepository,
|
MemoryRepository,
|
||||||
ViewRepository,
|
ViewRepository,
|
||||||
];
|
];
|
||||||
@ -94,7 +94,6 @@ export const providers = [
|
|||||||
{ provide: ILoggerRepository, useClass: LoggerRepository },
|
{ provide: ILoggerRepository, useClass: LoggerRepository },
|
||||||
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository },
|
{ provide: IMachineLearningRepository, useClass: MachineLearningRepository },
|
||||||
{ provide: IMapRepository, useClass: MapRepository },
|
{ provide: IMapRepository, useClass: MapRepository },
|
||||||
{ provide: IMediaRepository, useClass: MediaRepository },
|
|
||||||
{ provide: IMetadataRepository, useClass: MetadataRepository },
|
{ provide: IMetadataRepository, useClass: MetadataRepository },
|
||||||
{ provide: IMoveRepository, useClass: MoveRepository },
|
{ provide: IMoveRepository, useClass: MoveRepository },
|
||||||
{ provide: INotificationRepository, useClass: NotificationRepository },
|
{ provide: INotificationRepository, useClass: NotificationRepository },
|
||||||
|
@ -12,12 +12,11 @@ import {
|
|||||||
DecodeToBufferOptions,
|
DecodeToBufferOptions,
|
||||||
GenerateThumbhashOptions,
|
GenerateThumbhashOptions,
|
||||||
GenerateThumbnailOptions,
|
GenerateThumbnailOptions,
|
||||||
IMediaRepository,
|
|
||||||
ImageDimensions,
|
ImageDimensions,
|
||||||
ProbeOptions,
|
ProbeOptions,
|
||||||
TranscodeCommand,
|
TranscodeCommand,
|
||||||
VideoInfo,
|
VideoInfo,
|
||||||
} from 'src/interfaces/media.interface';
|
} from 'src/types';
|
||||||
import { handlePromiseError } from 'src/utils/misc';
|
import { handlePromiseError } from 'src/utils/misc';
|
||||||
|
|
||||||
const probe = (input: string, options: string[]): Promise<FfprobeData> =>
|
const probe = (input: string, options: string[]): Promise<FfprobeData> =>
|
||||||
@ -37,7 +36,7 @@ type ProgressEvent = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MediaRepository implements IMediaRepository {
|
export class MediaRepository {
|
||||||
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) {
|
constructor(@Inject(ILoggerRepository) private logger: ILoggerRepository) {
|
||||||
this.logger.setContext(MediaRepository.name);
|
this.logger.setContext(MediaRepository.name);
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,6 @@ import { ILibraryRepository } from 'src/interfaces/library.interface';
|
|||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
import { IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
|
||||||
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
import { IMetadataRepository } from 'src/interfaces/metadata.interface';
|
||||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||||
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
import { INotificationRepository } from 'src/interfaces/notification.interface';
|
||||||
@ -43,6 +42,7 @@ import { ActivityRepository } from 'src/repositories/activity.repository';
|
|||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
|
import { MediaRepository } from 'src/repositories/media.repository';
|
||||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||||
import { ViewRepository } from 'src/repositories/view-repository';
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
import { AccessRequest, checkAccess, requireAccess } from 'src/utils/access';
|
||||||
@ -69,7 +69,7 @@ export class BaseService {
|
|||||||
@Inject(ILibraryRepository) protected libraryRepository: ILibraryRepository,
|
@Inject(ILibraryRepository) protected libraryRepository: ILibraryRepository,
|
||||||
@Inject(IMachineLearningRepository) protected machineLearningRepository: IMachineLearningRepository,
|
@Inject(IMachineLearningRepository) protected machineLearningRepository: IMachineLearningRepository,
|
||||||
@Inject(IMapRepository) protected mapRepository: IMapRepository,
|
@Inject(IMapRepository) protected mapRepository: IMapRepository,
|
||||||
@Inject(IMediaRepository) protected mediaRepository: IMediaRepository,
|
protected mediaRepository: MediaRepository,
|
||||||
protected memoryRepository: MemoryRepository,
|
protected memoryRepository: MemoryRepository,
|
||||||
@Inject(IMetadataRepository) protected metadataRepository: IMetadataRepository,
|
@Inject(IMetadataRepository) protected metadataRepository: IMetadataRepository,
|
||||||
@Inject(IMoveRepository) protected moveRepository: IMoveRepository,
|
@Inject(IMoveRepository) protected moveRepository: IMoveRepository,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { OutputInfo } from 'sharp';
|
||||||
import { SystemConfig } from 'src/config';
|
import { SystemConfig } from 'src/config';
|
||||||
import { AssetEntity } from 'src/entities/asset.entity';
|
import { AssetEntity } from 'src/entities/asset.entity';
|
||||||
import { ExifEntity } from 'src/entities/exif.entity';
|
import { ExifEntity } from 'src/entities/exif.entity';
|
||||||
@ -15,12 +16,12 @@ import {
|
|||||||
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interface';
|
||||||
import { IJobRepository, JobCounts, JobName, JobStatus } from 'src/interfaces/job.interface';
|
import { IJobRepository, JobCounts, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||||
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
import { ILoggerRepository } from 'src/interfaces/logger.interface';
|
||||||
import { IMediaRepository, RawImageInfo } from 'src/interfaces/media.interface';
|
|
||||||
import { IMoveRepository } from 'src/interfaces/move.interface';
|
import { IMoveRepository } from 'src/interfaces/move.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
import { MediaService } from 'src/services/media.service';
|
import { MediaService } from 'src/services/media.service';
|
||||||
|
import { IMediaRepository, RawImageInfo } from 'src/types';
|
||||||
import { assetStub } from 'test/fixtures/asset.stub';
|
import { assetStub } from 'test/fixtures/asset.stub';
|
||||||
import { faceStub } from 'test/fixtures/face.stub';
|
import { faceStub } from 'test/fixtures/face.stub';
|
||||||
import { probeStub } from 'test/fixtures/media.stub';
|
import { probeStub } from 'test/fixtures/media.stub';
|
||||||
@ -257,7 +258,7 @@ describe(MediaService.name, () => {
|
|||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
rawBuffer = Buffer.from('image data');
|
rawBuffer = Buffer.from('image data');
|
||||||
rawInfo = { width: 100, height: 100, channels: 3 };
|
rawInfo = { width: 100, height: 100, channels: 3 };
|
||||||
mediaMock.decodeImage.mockResolvedValue({ data: rawBuffer, info: rawInfo });
|
mediaMock.decodeImage.mockResolvedValue({ data: rawBuffer, info: rawInfo as OutputInfo });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should skip thumbnail generation if asset not found', async () => {
|
it('should skip thumbnail generation if asset not found', async () => {
|
||||||
|
@ -27,8 +27,8 @@ import {
|
|||||||
JobStatus,
|
JobStatus,
|
||||||
QueueName,
|
QueueName,
|
||||||
} from 'src/interfaces/job.interface';
|
} from 'src/interfaces/job.interface';
|
||||||
import { AudioStreamInfo, VideoFormat, VideoInterfaces, VideoStreamInfo } from 'src/interfaces/media.interface';
|
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
|
import { AudioStreamInfo, VideoFormat, VideoInterfaces, VideoStreamInfo } from 'src/types';
|
||||||
import { getAssetFiles } from 'src/utils/asset.util';
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { BaseConfig, ThumbnailConfig } from 'src/utils/media';
|
import { BaseConfig, ThumbnailConfig } from 'src/utils/media';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
|
@ -11,7 +11,6 @@ import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
|||||||
import { IEventRepository } from 'src/interfaces/event.interface';
|
import { IEventRepository } from 'src/interfaces/event.interface';
|
||||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||||
import { IMapRepository } from 'src/interfaces/map.interface';
|
import { IMapRepository } from 'src/interfaces/map.interface';
|
||||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
|
||||||
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
|
import { IMetadataRepository, ImmichTags } from 'src/interfaces/metadata.interface';
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
@ -19,7 +18,7 @@ import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interf
|
|||||||
import { ITagRepository } from 'src/interfaces/tag.interface';
|
import { ITagRepository } from 'src/interfaces/tag.interface';
|
||||||
import { IUserRepository } from 'src/interfaces/user.interface';
|
import { IUserRepository } from 'src/interfaces/user.interface';
|
||||||
import { MetadataService } from 'src/services/metadata.service';
|
import { MetadataService } from 'src/services/metadata.service';
|
||||||
import { IConfigRepository } from 'src/types';
|
import { IConfigRepository, IMediaRepository } from 'src/types';
|
||||||
import { assetStub } from 'test/fixtures/asset.stub';
|
import { assetStub } from 'test/fixtures/asset.stub';
|
||||||
import { fileStub } from 'test/fixtures/file.stub';
|
import { fileStub } from 'test/fixtures/file.stub';
|
||||||
import { probeStub } from 'test/fixtures/media.stub';
|
import { probeStub } from 'test/fixtures/media.stub';
|
||||||
|
@ -7,12 +7,12 @@ import { IAssetRepository, WithoutProperty } from 'src/interfaces/asset.interfac
|
|||||||
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
import { ICryptoRepository } from 'src/interfaces/crypto.interface';
|
||||||
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
import { IJobRepository, JobName, JobStatus } from 'src/interfaces/job.interface';
|
||||||
import { DetectedFaces, IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
import { DetectedFaces, IMachineLearningRepository } from 'src/interfaces/machine-learning.interface';
|
||||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
|
||||||
import { IPersonRepository } from 'src/interfaces/person.interface';
|
import { IPersonRepository } from 'src/interfaces/person.interface';
|
||||||
import { FaceSearchResult, ISearchRepository } from 'src/interfaces/search.interface';
|
import { FaceSearchResult, ISearchRepository } from 'src/interfaces/search.interface';
|
||||||
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
import { IStorageRepository } from 'src/interfaces/storage.interface';
|
||||||
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
import { ISystemMetadataRepository } from 'src/interfaces/system-metadata.interface';
|
||||||
import { PersonService } from 'src/services/person.service';
|
import { PersonService } from 'src/services/person.service';
|
||||||
|
import { IMediaRepository } from 'src/types';
|
||||||
import { ImmichFileResponse } from 'src/utils/file';
|
import { ImmichFileResponse } from 'src/utils/file';
|
||||||
import { assetStub } from 'test/fixtures/asset.stub';
|
import { assetStub } from 'test/fixtures/asset.stub';
|
||||||
import { authStub } from 'test/fixtures/auth.stub';
|
import { authStub } from 'test/fixtures/auth.stub';
|
||||||
|
@ -42,9 +42,9 @@ import {
|
|||||||
QueueName,
|
QueueName,
|
||||||
} from 'src/interfaces/job.interface';
|
} from 'src/interfaces/job.interface';
|
||||||
import { BoundingBox } from 'src/interfaces/machine-learning.interface';
|
import { BoundingBox } from 'src/interfaces/machine-learning.interface';
|
||||||
import { CropOptions, ImageDimensions, InputDimensions } from 'src/interfaces/media.interface';
|
|
||||||
import { UpdateFacesData } from 'src/interfaces/person.interface';
|
import { UpdateFacesData } from 'src/interfaces/person.interface';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
|
import { CropOptions, ImageDimensions, InputDimensions } from 'src/types';
|
||||||
import { getAssetFiles } from 'src/utils/asset.util';
|
import { getAssetFiles } from 'src/utils/asset.util';
|
||||||
import { ImmichFileResponse } from 'src/utils/file';
|
import { ImmichFileResponse } from 'src/utils/file';
|
||||||
import { mimeTypes } from 'src/utils/mime-types';
|
import { mimeTypes } from 'src/utils/mime-types';
|
||||||
|
@ -1,10 +1,11 @@
|
|||||||
import { UserEntity } from 'src/entities/user.entity';
|
import { UserEntity } from 'src/entities/user.entity';
|
||||||
import { Permission } from 'src/enum';
|
import { ExifOrientation, ImageFormat, Permission, TranscodeTarget, VideoCodec } from 'src/enum';
|
||||||
import { AccessRepository } from 'src/repositories/access.repository';
|
import { AccessRepository } from 'src/repositories/access.repository';
|
||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
import { ConfigRepository } from 'src/repositories/config.repository';
|
import { ConfigRepository } from 'src/repositories/config.repository';
|
||||||
|
import { MediaRepository } from 'src/repositories/media.repository';
|
||||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||||
import { ViewRepository } from 'src/repositories/view-repository';
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
|
|
||||||
@ -24,6 +25,7 @@ export type IAccessRepository = { [K in keyof AccessRepository]: RepositoryInter
|
|||||||
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
export type IApiKeyRepository = RepositoryInterface<ApiKeyRepository>;
|
||||||
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
export type IAuditRepository = RepositoryInterface<AuditRepository>;
|
||||||
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
export type IConfigRepository = RepositoryInterface<ConfigRepository>;
|
||||||
|
export type IMediaRepository = RepositoryInterface<MediaRepository>;
|
||||||
export type IMemoryRepository = RepositoryInterface<MemoryRepository>;
|
export type IMemoryRepository = RepositoryInterface<MemoryRepository>;
|
||||||
export type IViewRepository = RepositoryInterface<ViewRepository>;
|
export type IViewRepository = RepositoryInterface<ViewRepository>;
|
||||||
|
|
||||||
@ -39,3 +41,135 @@ export type ApiKeyItem =
|
|||||||
export type MemoryItem =
|
export type MemoryItem =
|
||||||
| Awaited<ReturnType<IMemoryRepository['create']>>
|
| Awaited<ReturnType<IMemoryRepository['create']>>
|
||||||
| Awaited<ReturnType<IMemoryRepository['search']>>[0];
|
| Awaited<ReturnType<IMemoryRepository['search']>>[0];
|
||||||
|
|
||||||
|
export interface CropOptions {
|
||||||
|
top: number;
|
||||||
|
left: number;
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageOptions {
|
||||||
|
format: ImageFormat;
|
||||||
|
quality: number;
|
||||||
|
size: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface RawImageInfo {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
channels: 1 | 2 | 3 | 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface DecodeImageOptions {
|
||||||
|
colorspace: string;
|
||||||
|
crop?: CropOptions;
|
||||||
|
processInvalidImages: boolean;
|
||||||
|
raw?: RawImageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DecodeToBufferOptions extends DecodeImageOptions {
|
||||||
|
size: number;
|
||||||
|
orientation?: ExifOrientation;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type GenerateThumbnailOptions = ImageOptions & DecodeImageOptions;
|
||||||
|
|
||||||
|
export type GenerateThumbnailFromBufferOptions = GenerateThumbnailOptions & { raw: RawImageInfo };
|
||||||
|
|
||||||
|
export type GenerateThumbhashOptions = DecodeImageOptions;
|
||||||
|
|
||||||
|
export type GenerateThumbhashFromBufferOptions = GenerateThumbhashOptions & { raw: RawImageInfo };
|
||||||
|
|
||||||
|
export interface GenerateThumbnailsOptions {
|
||||||
|
colorspace: string;
|
||||||
|
crop?: CropOptions;
|
||||||
|
preview?: ImageOptions;
|
||||||
|
processInvalidImages: boolean;
|
||||||
|
thumbhash?: boolean;
|
||||||
|
thumbnail?: ImageOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoStreamInfo {
|
||||||
|
index: number;
|
||||||
|
height: number;
|
||||||
|
width: number;
|
||||||
|
rotation: number;
|
||||||
|
codecName?: string;
|
||||||
|
frameCount: number;
|
||||||
|
isHDR: boolean;
|
||||||
|
bitrate: number;
|
||||||
|
pixelFormat: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface AudioStreamInfo {
|
||||||
|
index: number;
|
||||||
|
codecName?: string;
|
||||||
|
frameCount: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoFormat {
|
||||||
|
formatName?: string;
|
||||||
|
formatLongName?: string;
|
||||||
|
duration: number;
|
||||||
|
bitrate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageDimensions {
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InputDimensions extends ImageDimensions {
|
||||||
|
inputPath: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoInfo {
|
||||||
|
format: VideoFormat;
|
||||||
|
videoStreams: VideoStreamInfo[];
|
||||||
|
audioStreams: AudioStreamInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface TranscodeCommand {
|
||||||
|
inputOptions: string[];
|
||||||
|
outputOptions: string[];
|
||||||
|
twoPass: boolean;
|
||||||
|
progress: {
|
||||||
|
frameCount: number;
|
||||||
|
percentInterval: number;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface BitrateDistribution {
|
||||||
|
max: number;
|
||||||
|
target: number;
|
||||||
|
min: number;
|
||||||
|
unit: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ImageBuffer {
|
||||||
|
data: Buffer;
|
||||||
|
info: RawImageInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoCodecSWConfig {
|
||||||
|
getCommand(
|
||||||
|
target: TranscodeTarget,
|
||||||
|
videoStream: VideoStreamInfo,
|
||||||
|
audioStream: AudioStreamInfo,
|
||||||
|
format?: VideoFormat,
|
||||||
|
): TranscodeCommand;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoCodecHWConfig extends VideoCodecSWConfig {
|
||||||
|
getSupportedCodecs(): Array<VideoCodec>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProbeOptions {
|
||||||
|
countFrames: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface VideoInterfaces {
|
||||||
|
dri: string[];
|
||||||
|
mali: boolean;
|
||||||
|
}
|
||||||
|
@ -9,7 +9,7 @@ import {
|
|||||||
VideoFormat,
|
VideoFormat,
|
||||||
VideoInterfaces,
|
VideoInterfaces,
|
||||||
VideoStreamInfo,
|
VideoStreamInfo,
|
||||||
} from 'src/interfaces/media.interface';
|
} from 'src/types';
|
||||||
|
|
||||||
export class BaseConfig implements VideoCodecSWConfig {
|
export class BaseConfig implements VideoCodecSWConfig {
|
||||||
readonly presets = ['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast'];
|
readonly presets = ['veryslow', 'slower', 'slow', 'medium', 'fast', 'faster', 'veryfast', 'superfast', 'ultrafast'];
|
||||||
|
2
server/test/fixtures/media.stub.ts
vendored
2
server/test/fixtures/media.stub.ts
vendored
@ -1,4 +1,4 @@
|
|||||||
import { AudioStreamInfo, VideoFormat, VideoInfo, VideoStreamInfo } from 'src/interfaces/media.interface';
|
import { AudioStreamInfo, VideoFormat, VideoInfo, VideoStreamInfo } from 'src/types';
|
||||||
|
|
||||||
const probeStubDefaultFormat: VideoFormat = {
|
const probeStubDefaultFormat: VideoFormat = {
|
||||||
formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
|
formatName: 'mov,mp4,m4a,3gp,3g2,mj2',
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IMediaRepository } from 'src/interfaces/media.interface';
|
import { IMediaRepository } from 'src/types';
|
||||||
import { Mocked, vitest } from 'vitest';
|
import { Mocked, vitest } from 'vitest';
|
||||||
|
|
||||||
export const newMediaRepositoryMock = (): Mocked<IMediaRepository> => {
|
export const newMediaRepositoryMock = (): Mocked<IMediaRepository> => {
|
||||||
|
@ -7,6 +7,7 @@ import { AccessRepository } from 'src/repositories/access.repository';
|
|||||||
import { ActivityRepository } from 'src/repositories/activity.repository';
|
import { ActivityRepository } from 'src/repositories/activity.repository';
|
||||||
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
import { ApiKeyRepository } from 'src/repositories/api-key.repository';
|
||||||
import { AuditRepository } from 'src/repositories/audit.repository';
|
import { AuditRepository } from 'src/repositories/audit.repository';
|
||||||
|
import { MediaRepository } from 'src/repositories/media.repository';
|
||||||
import { MemoryRepository } from 'src/repositories/memory.repository';
|
import { MemoryRepository } from 'src/repositories/memory.repository';
|
||||||
import { ViewRepository } from 'src/repositories/view-repository';
|
import { ViewRepository } from 'src/repositories/view-repository';
|
||||||
import { BaseService } from 'src/services/base.service';
|
import { BaseService } from 'src/services/base.service';
|
||||||
@ -15,6 +16,7 @@ import {
|
|||||||
IActivityRepository,
|
IActivityRepository,
|
||||||
IApiKeyRepository,
|
IApiKeyRepository,
|
||||||
IAuditRepository,
|
IAuditRepository,
|
||||||
|
IMediaRepository,
|
||||||
IMemoryRepository,
|
IMemoryRepository,
|
||||||
IViewRepository,
|
IViewRepository,
|
||||||
} from 'src/types';
|
} from 'src/types';
|
||||||
@ -133,7 +135,7 @@ export const newTestService = <T extends BaseService>(
|
|||||||
libraryMock,
|
libraryMock,
|
||||||
machineLearningMock,
|
machineLearningMock,
|
||||||
mapMock,
|
mapMock,
|
||||||
mediaMock,
|
mediaMock as IMediaRepository as MediaRepository,
|
||||||
memoryMock as IMemoryRepository as MemoryRepository,
|
memoryMock as IMemoryRepository as MemoryRepository,
|
||||||
metadataMock,
|
metadataMock,
|
||||||
moveMock,
|
moveMock,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user