1
0
mirror of https://github.com/immich-app/immich.git synced 2025-06-15 03:30:33 +02:00

refactor: asset media endpoints (#9831)

* refactor: asset media endpoints

* refactor: mobile upload livePhoto as separate request

* refactor: change mobile backup flow to use new asset upload endpoints

* chore: format and analyze dart code

* feat: mark motion as hidden when linked

* feat: upload video portion of live photo before image portion

* fix: incorrect assetApi calls in mobile code

* fix: download asset

---------

Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
Co-authored-by: Zack Pollard <zackpollard@ymail.com>
This commit is contained in:
Jason Rasmussen
2024-05-31 13:44:04 -04:00
committed by GitHub
parent 66fced40e7
commit 69d2fcb43e
91 changed files with 1932 additions and 2456 deletions

View File

@ -264,6 +264,24 @@ export type AssetBulkDeleteDto = {
force?: boolean;
ids: string[];
};
export type AssetMediaCreateDto = {
assetData: Blob;
deviceAssetId: string;
deviceId: string;
duration?: string;
fileCreatedAt: string;
fileModifiedAt: string;
isArchived?: boolean;
isFavorite?: boolean;
isOffline?: boolean;
isVisible?: boolean;
livePhotoVideoId?: string;
sidecarData?: Blob;
};
export type AssetMediaResponseDto = {
id: string;
status: AssetMediaStatus;
};
export type AssetBulkUpdateDto = {
dateTimeOriginal?: string;
duplicateId?: string | null;
@ -316,24 +334,6 @@ export type AssetStatsResponseDto = {
total: number;
videos: number;
};
export type CreateAssetDto = {
assetData: Blob;
deviceAssetId: string;
deviceId: string;
duration?: string;
fileCreatedAt: string;
fileModifiedAt: string;
isArchived?: boolean;
isFavorite?: boolean;
isOffline?: boolean;
isVisible?: boolean;
livePhotoData?: Blob;
sidecarData?: Blob;
};
export type AssetFileUploadResponseDto = {
duplicate: boolean;
id: string;
};
export type UpdateAssetDto = {
dateTimeOriginal?: string;
description?: string;
@ -350,10 +350,6 @@ export type AssetMediaReplaceDto = {
fileCreatedAt: string;
fileModifiedAt: string;
};
export type AssetMediaResponseDto = {
id: string;
status: AssetMediaStatus;
};
export type AuditDeletesResponseDto = {
ids: string[];
needsFullSync: boolean;
@ -1434,16 +1430,35 @@ export function updateApiKey({ id, apiKeyUpdateDto }: {
export function deleteAssets({ assetBulkDeleteDto }: {
assetBulkDeleteDto: AssetBulkDeleteDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/asset", oazapfts.json({
return oazapfts.ok(oazapfts.fetchText("/assets", oazapfts.json({
...opts,
method: "DELETE",
body: assetBulkDeleteDto
})));
}
export function uploadAsset({ key, xImmichChecksum, assetMediaCreateDto }: {
key?: string;
xImmichChecksum?: string;
assetMediaCreateDto: AssetMediaCreateDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 201;
data: AssetMediaResponseDto;
}>(`/assets${QS.query(QS.explode({
key
}))}`, oazapfts.multipart({
...opts,
method: "POST",
body: assetMediaCreateDto,
headers: oazapfts.mergeHeaders(opts?.headers, {
"x-immich-checksum": xImmichChecksum
})
})));
}
export function updateAssets({ assetBulkUpdateDto }: {
assetBulkUpdateDto: AssetBulkUpdateDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/asset", oazapfts.json({
return oazapfts.ok(oazapfts.fetchText("/assets", oazapfts.json({
...opts,
method: "PUT",
body: assetBulkUpdateDto
@ -1458,7 +1473,7 @@ export function checkBulkUpload({ assetBulkUploadCheckDto }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetBulkUploadCheckResponseDto;
}>("/asset/bulk-upload-check", oazapfts.json({
}>("/assets/bulk-upload-check", oazapfts.json({
...opts,
method: "POST",
body: assetBulkUploadCheckDto
@ -1473,7 +1488,7 @@ export function getAllUserAssetsByDeviceId({ deviceId }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: string[];
}>(`/asset/device/${encodeURIComponent(deviceId)}`, {
}>(`/assets/device/${encodeURIComponent(deviceId)}`, {
...opts
}));
}
@ -1486,33 +1501,16 @@ export function checkExistingAssets({ checkExistingAssetsDto }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: CheckExistingAssetsResponseDto;
}>("/asset/exist", oazapfts.json({
}>("/assets/exist", oazapfts.json({
...opts,
method: "POST",
body: checkExistingAssetsDto
})));
}
export function serveFile({ id, isThumb, isWeb, key }: {
id: string;
isThumb?: boolean;
isWeb?: boolean;
key?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/asset/file/${encodeURIComponent(id)}${QS.query(QS.explode({
isThumb,
isWeb,
key
}))}`, {
...opts
}));
}
export function runAssetJobs({ assetJobsDto }: {
assetJobsDto: AssetJobsDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/asset/jobs", oazapfts.json({
return oazapfts.ok(oazapfts.fetchText("/assets/jobs", oazapfts.json({
...opts,
method: "POST",
body: assetJobsDto
@ -1525,7 +1523,7 @@ export function getMemoryLane({ day, month }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: MemoryLaneResponseDto[];
}>(`/asset/memory-lane${QS.query(QS.explode({
}>(`/assets/memory-lane${QS.query(QS.explode({
day,
month
}))}`, {
@ -1538,7 +1536,7 @@ export function getRandom({ count }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetResponseDto[];
}>(`/asset/random${QS.query(QS.explode({
}>(`/assets/random${QS.query(QS.explode({
count
}))}`, {
...opts
@ -1547,7 +1545,7 @@ export function getRandom({ count }: {
export function updateStackParent({ updateStackParentDto }: {
updateStackParentDto: UpdateStackParentDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchText("/asset/stack/parent", oazapfts.json({
return oazapfts.ok(oazapfts.fetchText("/assets/stack/parent", oazapfts.json({
...opts,
method: "PUT",
body: updateStackParentDto
@ -1561,7 +1559,7 @@ export function getAssetStatistics({ isArchived, isFavorite, isTrashed }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetStatsResponseDto;
}>(`/asset/statistics${QS.query(QS.explode({
}>(`/assets/statistics${QS.query(QS.explode({
isArchived,
isFavorite,
isTrashed
@ -1569,40 +1567,6 @@ export function getAssetStatistics({ isArchived, isFavorite, isTrashed }: {
...opts
}));
}
export function getAssetThumbnail({ format, id, key }: {
format?: ThumbnailFormat;
id: string;
key?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/asset/thumbnail/${encodeURIComponent(id)}${QS.query(QS.explode({
format,
key
}))}`, {
...opts
}));
}
export function uploadFile({ key, xImmichChecksum, createAssetDto }: {
key?: string;
xImmichChecksum?: string;
createAssetDto: CreateAssetDto;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchJson<{
status: 201;
data: AssetFileUploadResponseDto;
}>(`/asset/upload${QS.query(QS.explode({
key
}))}`, oazapfts.multipart({
...opts,
method: "POST",
body: createAssetDto,
headers: oazapfts.mergeHeaders(opts?.headers, {
"x-immich-checksum": xImmichChecksum
})
})));
}
export function getAssetInfo({ id, key }: {
id: string;
key?: string;
@ -1610,7 +1574,7 @@ export function getAssetInfo({ id, key }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetResponseDto;
}>(`/asset/${encodeURIComponent(id)}${QS.query(QS.explode({
}>(`/assets/${encodeURIComponent(id)}${QS.query(QS.explode({
key
}))}`, {
...opts
@ -1623,12 +1587,25 @@ export function updateAsset({ id, updateAssetDto }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetResponseDto;
}>(`/asset/${encodeURIComponent(id)}`, oazapfts.json({
}>(`/assets/${encodeURIComponent(id)}`, oazapfts.json({
...opts,
method: "PUT",
body: updateAssetDto
})));
}
export function downloadAsset({ id, key }: {
id: string;
key?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/assets/${encodeURIComponent(id)}/original${QS.query(QS.explode({
key
}))}`, {
...opts
}));
}
/**
* Replace the asset with new file, without changing its id
*/
@ -1640,7 +1617,7 @@ export function replaceAsset({ id, key, assetMediaReplaceDto }: {
return oazapfts.ok(oazapfts.fetchJson<{
status: 200;
data: AssetMediaResponseDto;
}>(`/asset/${encodeURIComponent(id)}/file${QS.query(QS.explode({
}>(`/assets/${encodeURIComponent(id)}/original${QS.query(QS.explode({
key
}))}`, oazapfts.multipart({
...opts,
@ -1648,6 +1625,34 @@ export function replaceAsset({ id, key, assetMediaReplaceDto }: {
body: assetMediaReplaceDto
})));
}
export function viewAsset({ id, key, size }: {
id: string;
key?: string;
size?: AssetMediaSize;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/assets/${encodeURIComponent(id)}/thumbnail${QS.query(QS.explode({
key,
size
}))}`, {
...opts
}));
}
export function playAssetVideo({ id, key }: {
id: string;
key?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/assets/${encodeURIComponent(id)}/video/playback${QS.query(QS.explode({
key
}))}`, {
...opts
}));
}
export function getAuditDeletes({ after, entityType, userId }: {
after: string;
entityType: EntityType;
@ -1733,20 +1738,6 @@ export function downloadArchive({ key, assetIdsDto }: {
body: assetIdsDto
})));
}
export function downloadFile({ id, key }: {
id: string;
key?: string;
}, opts?: Oazapfts.RequestOpts) {
return oazapfts.ok(oazapfts.fetchBlob<{
status: 200;
data: Blob;
}>(`/download/asset/${encodeURIComponent(id)}${QS.query(QS.explode({
key
}))}`, {
...opts,
method: "POST"
}));
}
export function getDownloadInfo({ key, downloadInfoDto }: {
key?: string;
downloadInfoDto: DownloadInfoDto;
@ -2929,6 +2920,11 @@ export enum Error {
NotFound = "not_found",
Unknown = "unknown"
}
export enum AssetMediaStatus {
Created = "created",
Replaced = "replaced",
Duplicate = "duplicate"
}
export enum Action {
Accept = "accept",
Reject = "reject"
@ -2942,13 +2938,9 @@ export enum AssetJobName {
RefreshMetadata = "refresh-metadata",
TranscodeVideo = "transcode-video"
}
export enum ThumbnailFormat {
Jpeg = "JPEG",
Webp = "WEBP"
}
export enum AssetMediaStatus {
Replaced = "replaced",
Duplicate = "duplicate"
export enum AssetMediaSize {
Preview = "preview",
Thumbnail = "thumbnail"
}
export enum EntityType {
Asset = "ASSET",

View File

@ -24,9 +24,12 @@ export const setApiKey = (apiKey: string) => {
defaults.headers['x-api-key'] = apiKey;
};
export const getAssetOriginalPath = (id: string) => `/asset/file/${id}`;
export const getAssetOriginalPath = (id: string) => `/assets/${id}/original`;
export const getAssetThumbnailPath = (id: string) => `/asset/thumbnail/${id}`;
export const getAssetThumbnailPath = (id: string) => `/assets/${id}/thumbnail`;
export const getAssetPlaybackPath = (id: string) =>
`/assets/${id}/video/playback`;
export const getUserProfileImagePath = (userId: string) =>
`/users/${userId}/profile-image`;