2024-03-20 16:02:51 -05:00
|
|
|
import { AssetJobStatusEntity } from 'src/entities/asset-job-status.entity';
|
2024-08-15 06:57:01 -04:00
|
|
|
import { AssetEntity } from 'src/entities/asset.entity';
|
2024-03-20 16:02:51 -05:00
|
|
|
import { ExifEntity } from 'src/entities/exif.entity';
|
2024-12-08 22:56:11 +01:00
|
|
|
import { LibraryEntity } from 'src/entities/library.entity';
|
2024-09-18 09:57:52 -04:00
|
|
|
import { AssetFileType, AssetOrder, AssetStatus, AssetType } from 'src/enum';
|
2024-03-21 12:59:49 +01:00
|
|
|
import { AssetSearchOptions, SearchExploreItem } from 'src/interfaces/search.interface';
|
2024-03-20 22:15:09 -05:00
|
|
|
import { Paginated, PaginationOptions } from 'src/utils/pagination';
|
2024-12-08 22:56:11 +01:00
|
|
|
import { FindOptionsOrder, FindOptionsRelations, FindOptionsSelect, UpdateResult } from 'typeorm';
|
2023-02-25 09:12:03 -05:00
|
|
|
|
2023-07-14 09:30:17 -04:00
|
|
|
export type AssetStats = Record<AssetType, number>;
|
|
|
|
|
|
|
|
export interface AssetStatsOptions {
|
|
|
|
isFavorite?: boolean;
|
|
|
|
isArchived?: boolean;
|
2023-10-06 07:01:14 +00:00
|
|
|
isTrashed?: boolean;
|
2023-07-14 09:30:17 -04:00
|
|
|
}
|
|
|
|
|
2023-04-04 00:48:05 -04:00
|
|
|
export interface LivePhotoSearchOptions {
|
|
|
|
ownerId: string;
|
2024-08-20 21:23:50 -04:00
|
|
|
libraryId?: string | null;
|
2023-04-04 00:48:05 -04:00
|
|
|
livePhotoCID: string;
|
|
|
|
otherAssetId: string;
|
|
|
|
type: AssetType;
|
|
|
|
}
|
|
|
|
|
2023-03-20 11:55:28 -04:00
|
|
|
export enum WithoutProperty {
|
|
|
|
THUMBNAIL = 'thumbnail',
|
|
|
|
ENCODED_VIDEO = 'encoded-video',
|
|
|
|
EXIF = 'exif',
|
2024-01-29 09:51:22 -05:00
|
|
|
SMART_SEARCH = 'smart-search',
|
2024-05-16 13:08:37 -04:00
|
|
|
DUPLICATE = 'duplicate',
|
2023-05-17 13:07:17 -04:00
|
|
|
FACES = 'faces',
|
feat(server): xmp sidecar metadata (#2466)
* initial commit for XMP sidecar support
* Added support for 'missing' metadata files to include those without sidecar files, now detects sidecar files in the filesystem for media already ingested but the sidecar was created afterwards
* didn't mean to commit default log level during testing
* new sidecar logic for video metadata as well
* Added xml mimetype for sidecars only
* don't need capture group for this regex
* wrong default value reverted
* simplified the move here - keep it in the same try catch since the outcome is to move the media back anyway
* simplified setter logic
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
* simplified logic per suggestions
* sidecar is now its own queue with a discover and sync, updated UI for the new job queueing
* queue a sidecar job for every asset based on discovery or sync, though the logic is almost identical aside from linking the sidecar
* now queue sidecar jobs for each assset, though logic is mostly the same between discovery and sync
* simplified logic of filename extraction and asset instantiation
* not sure how that got deleted..
* updated code per suggestions and comments in the PR
* stat was not being used, removed the variable set
* better type checking, using in-scope variables for exif getter instead of passing in every time
* removed commented out test
* ran and resolved all lints, formats, checks, and tests
* resolved suggested change in PR
* made getExifProperty more dynamic with multiple possible args for fallbacks, fixed typo, used generic in function for better type checking
* better error handling and moving files back to positions on move or save failure
* regenerated api
* format fixes
* Added XMP documentation
* documentation typo
* Merged in main
* missed merge conflict
* more changes due to a merge
* Resolving conflicts
* added icon for sidecar jobs
---------
Co-authored-by: Jason Rasmussen <jrasm91@gmail.com>
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
2023-05-24 21:59:30 -04:00
|
|
|
SIDECAR = 'sidecar',
|
|
|
|
}
|
|
|
|
|
|
|
|
export enum WithProperty {
|
|
|
|
SIDECAR = 'sidecar',
|
2023-03-02 21:47:08 -05:00
|
|
|
}
|
|
|
|
|
2023-08-04 17:07:15 -04:00
|
|
|
export enum TimeBucketSize {
|
|
|
|
DAY = 'DAY',
|
|
|
|
MONTH = 'MONTH',
|
|
|
|
}
|
|
|
|
|
2023-12-08 11:15:46 -05:00
|
|
|
export interface AssetBuilderOptions {
|
2023-08-04 17:07:15 -04:00
|
|
|
isArchived?: boolean;
|
|
|
|
isFavorite?: boolean;
|
2023-10-06 07:01:14 +00:00
|
|
|
isTrashed?: boolean;
|
2024-05-16 13:08:37 -04:00
|
|
|
isDuplicate?: boolean;
|
2023-08-04 17:07:15 -04:00
|
|
|
albumId?: string;
|
2024-08-29 12:14:03 -04:00
|
|
|
tagId?: string;
|
2023-08-05 09:58:52 -04:00
|
|
|
personId?: string;
|
2023-11-11 15:06:19 -06:00
|
|
|
userIds?: string[];
|
2023-10-27 15:34:01 -05:00
|
|
|
withStacked?: boolean;
|
2023-12-08 11:15:46 -05:00
|
|
|
exifInfo?: boolean;
|
2024-09-18 09:57:52 -04:00
|
|
|
status?: AssetStatus;
|
2023-12-08 11:15:46 -05:00
|
|
|
assetType?: AssetType;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface TimeBucketOptions extends AssetBuilderOptions {
|
|
|
|
size: TimeBucketSize;
|
2024-03-14 17:45:03 +01:00
|
|
|
order?: AssetOrder;
|
2023-08-04 17:07:15 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
export interface TimeBucketItem {
|
|
|
|
timeBucket: string;
|
|
|
|
count: number;
|
|
|
|
}
|
|
|
|
|
2023-10-04 18:11:11 -04:00
|
|
|
export type AssetCreate = Pick<
|
|
|
|
AssetEntity,
|
|
|
|
| 'deviceAssetId'
|
|
|
|
| 'ownerId'
|
|
|
|
| 'libraryId'
|
|
|
|
| 'deviceId'
|
|
|
|
| 'type'
|
|
|
|
| 'originalPath'
|
|
|
|
| 'fileCreatedAt'
|
|
|
|
| 'localDateTime'
|
|
|
|
| 'fileModifiedAt'
|
|
|
|
| 'checksum'
|
|
|
|
| 'originalFileName'
|
|
|
|
> &
|
|
|
|
Partial<AssetEntity>;
|
|
|
|
|
2024-03-19 22:42:10 -04:00
|
|
|
export type AssetWithoutRelations = Omit<
|
|
|
|
AssetEntity,
|
|
|
|
| 'livePhotoVideo'
|
|
|
|
| 'stack'
|
|
|
|
| 'albums'
|
|
|
|
| 'faces'
|
|
|
|
| 'owner'
|
|
|
|
| 'library'
|
|
|
|
| 'exifInfo'
|
|
|
|
| 'sharedLinks'
|
|
|
|
| 'smartSearch'
|
|
|
|
| 'tags'
|
|
|
|
>;
|
|
|
|
|
2024-05-23 20:26:22 -04:00
|
|
|
type AssetUpdateWithoutRelations = Pick<AssetWithoutRelations, 'id'> & Partial<AssetWithoutRelations>;
|
|
|
|
type AssetUpdateWithLivePhotoRelation = Pick<AssetWithoutRelations, 'id'> & Pick<AssetEntity, 'livePhotoVideo'>;
|
|
|
|
|
|
|
|
export type AssetUpdateOptions = AssetUpdateWithoutRelations | AssetUpdateWithLivePhotoRelation;
|
2024-03-19 22:42:10 -04:00
|
|
|
|
|
|
|
export type AssetUpdateAllOptions = Omit<Partial<AssetWithoutRelations>, 'id'>;
|
|
|
|
|
2023-10-04 18:11:11 -04:00
|
|
|
export interface MonthDay {
|
|
|
|
day: number;
|
|
|
|
month: number;
|
|
|
|
}
|
|
|
|
|
2023-12-08 11:15:46 -05:00
|
|
|
export interface AssetExploreFieldOptions {
|
|
|
|
maxFields: number;
|
|
|
|
minAssetsPerField: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface AssetExploreOptions extends AssetExploreFieldOptions {
|
|
|
|
relation: keyof AssetEntity;
|
|
|
|
relatedField: string;
|
|
|
|
unnest?: boolean;
|
|
|
|
}
|
|
|
|
|
2024-04-16 07:26:37 +02:00
|
|
|
export interface AssetFullSyncOptions {
|
|
|
|
ownerId: string;
|
|
|
|
lastId?: string;
|
|
|
|
updatedUntil: Date;
|
|
|
|
limit: number;
|
|
|
|
}
|
|
|
|
|
|
|
|
export interface AssetDeltaSyncOptions {
|
|
|
|
userIds: string[];
|
|
|
|
updatedAfter: Date;
|
|
|
|
limit: number;
|
|
|
|
}
|
|
|
|
|
2024-05-16 13:08:37 -04:00
|
|
|
export interface AssetUpdateDuplicateOptions {
|
|
|
|
targetDuplicateId: string | null;
|
|
|
|
assetIds: string[];
|
|
|
|
duplicateIds: string[];
|
|
|
|
}
|
|
|
|
|
2024-09-28 13:47:24 -04:00
|
|
|
export interface UpsertFileOptions {
|
|
|
|
assetId: string;
|
|
|
|
type: AssetFileType;
|
|
|
|
path: string;
|
|
|
|
}
|
|
|
|
|
2024-03-10 22:30:57 -04:00
|
|
|
export type AssetPathEntity = Pick<AssetEntity, 'id' | 'originalPath' | 'isOffline'>;
|
|
|
|
|
2024-12-10 16:22:47 -05:00
|
|
|
export interface DayOfYearAssets {
|
|
|
|
yearsAgo: number;
|
|
|
|
assets: AssetEntity[];
|
|
|
|
}
|
|
|
|
|
2023-02-25 09:12:03 -05:00
|
|
|
export const IAssetRepository = 'IAssetRepository';
|
|
|
|
|
|
|
|
export interface IAssetRepository {
|
2023-10-04 18:11:11 -04:00
|
|
|
create(asset: AssetCreate): Promise<AssetEntity>;
|
2024-12-10 15:39:30 +01:00
|
|
|
createAll(assets: AssetCreate[]): Promise<AssetEntity[]>;
|
2024-01-18 00:08:48 -05:00
|
|
|
getByIds(
|
|
|
|
ids: string[],
|
|
|
|
relations?: FindOptionsRelations<AssetEntity>,
|
|
|
|
select?: FindOptionsSelect<AssetEntity>,
|
|
|
|
): Promise<AssetEntity[]>;
|
2024-03-14 01:58:09 -04:00
|
|
|
getByIdsWithAllRelations(ids: string[]): Promise<AssetEntity[]>;
|
2024-12-10 16:22:47 -05:00
|
|
|
getByDayOfYear(ownerIds: string[], monthDay: MonthDay): Promise<DayOfYearAssets[]>;
|
2024-05-31 13:44:04 -04:00
|
|
|
getByChecksum(options: { ownerId: string; checksum: Buffer; libraryId?: string }): Promise<AssetEntity | null>;
|
2024-05-24 21:02:22 -04:00
|
|
|
getByChecksums(userId: string, checksums: Buffer[]): Promise<AssetEntity[]>;
|
2024-05-02 15:42:26 -04:00
|
|
|
getUploadAssetIdByChecksum(ownerId: string, checksum: Buffer): Promise<string | undefined>;
|
2023-06-30 12:24:28 -04:00
|
|
|
getByAlbumId(pagination: PaginationOptions, albumId: string): Paginated<AssetEntity>;
|
2024-06-12 15:48:44 +02:00
|
|
|
getByDeviceIds(ownerId: string, deviceId: string, deviceAssetIds: string[]): Promise<string[]>;
|
2023-10-06 07:01:14 +00:00
|
|
|
getByUserId(pagination: PaginationOptions, userId: string, options?: AssetSearchOptions): Paginated<AssetEntity>;
|
2024-05-05 20:16:44 +02:00
|
|
|
getById(
|
|
|
|
id: string,
|
|
|
|
relations?: FindOptionsRelations<AssetEntity>,
|
|
|
|
order?: FindOptionsOrder<AssetEntity>,
|
|
|
|
): Promise<AssetEntity | null>;
|
2023-05-22 20:05:06 +02:00
|
|
|
getWithout(pagination: PaginationOptions, property: WithoutProperty): Paginated<AssetEntity>;
|
2024-09-12 13:56:38 -04:00
|
|
|
getRandom(userIds: string[], count: number): Promise<AssetEntity[]>;
|
2023-06-21 04:00:59 +03:00
|
|
|
getLastUpdatedAssetForAlbumId(albumId: string): Promise<AssetEntity | null>;
|
2023-09-20 13:16:33 +02:00
|
|
|
getByLibraryIdAndOriginalPath(libraryId: string, originalPath: string): Promise<AssetEntity | null>;
|
2023-02-25 09:12:03 -05:00
|
|
|
deleteAll(ownerId: string): Promise<void>;
|
2023-05-22 20:05:06 +02:00
|
|
|
getAll(pagination: PaginationOptions, options?: AssetSearchOptions): Paginated<AssetEntity>;
|
2023-11-25 15:46:20 +00:00
|
|
|
getAllByDeviceId(userId: string, deviceId: string): Promise<string[]>;
|
2024-06-27 15:41:49 -04:00
|
|
|
getLivePhotoCount(motionId: string): Promise<number>;
|
2024-03-19 22:42:10 -04:00
|
|
|
updateAll(ids: string[], options: Partial<AssetUpdateAllOptions>): Promise<void>;
|
2024-05-16 13:08:37 -04:00
|
|
|
updateDuplicates(options: AssetUpdateDuplicateOptions): Promise<void>;
|
2024-03-19 22:42:10 -04:00
|
|
|
update(asset: AssetUpdateOptions): Promise<void>;
|
2023-10-06 07:01:14 +00:00
|
|
|
remove(asset: AssetEntity): Promise<void>;
|
2023-04-04 00:48:05 -04:00
|
|
|
findLivePhotoMatch(options: LivePhotoSearchOptions): Promise<AssetEntity | null>;
|
2023-07-14 09:30:17 -04:00
|
|
|
getStatistics(ownerId: string, options: AssetStatsOptions): Promise<AssetStats>;
|
2023-08-11 12:00:51 -04:00
|
|
|
getTimeBuckets(options: TimeBucketOptions): Promise<TimeBucketItem[]>;
|
2023-11-03 21:33:15 -04:00
|
|
|
getTimeBucket(timeBucket: string, options: TimeBucketOptions): Promise<AssetEntity[]>;
|
2023-09-04 22:25:31 -04:00
|
|
|
upsertExif(exif: Partial<ExifEntity>): Promise<void>;
|
2024-05-16 13:08:37 -04:00
|
|
|
upsertJobStatus(...jobStatus: Partial<AssetJobStatusEntity>[]): Promise<void>;
|
2023-12-08 11:15:46 -05:00
|
|
|
getAssetIdByCity(userId: string, options: AssetExploreFieldOptions): Promise<SearchExploreItem<string>>;
|
2024-05-16 13:08:37 -04:00
|
|
|
getDuplicates(options: AssetBuilderOptions): Promise<AssetEntity[]>;
|
2024-04-16 07:26:37 +02:00
|
|
|
getAllForUserFullSync(options: AssetFullSyncOptions): Promise<AssetEntity[]>;
|
|
|
|
getChangedDeltaSync(options: AssetDeltaSyncOptions): Promise<AssetEntity[]>;
|
2024-09-28 13:47:24 -04:00
|
|
|
upsertFile(file: UpsertFileOptions): Promise<void>;
|
|
|
|
upsertFiles(files: UpsertFileOptions[]): Promise<void>;
|
2024-12-10 15:39:30 +01:00
|
|
|
updateOffline(library: LibraryEntity): Promise<UpdateResult>;
|
|
|
|
getNewPaths(libraryId: string, paths: string[]): Promise<string[]>;
|
2023-02-25 09:12:03 -05:00
|
|
|
}
|