mirror of
https://github.com/immich-app/immich.git
synced 2025-03-01 15:11:21 +01:00
refactor(server): calculate asset type server side (#3200)
* refactor(server): calculate asset type server-side
* chore: open api
* chore: remove comments
* fix: linting
* update
* Revert "update"
This reverts commit dc58702923
.
* fix: upload LivePhotos
* chore: remove unused request fields for upload
* remove unused method
* mobile-fix: livePhoto filename
* fix: revert check for livephotos filename and extension
---------
Co-authored-by: Alex Tran <alex.tran1502@gmail.com>
This commit is contained in:
parent
93462aafbc
commit
b71d7e33bb
24 changed files with 97 additions and 580 deletions
|
@ -1375,12 +1375,6 @@ export interface GetAssetCountByTimeBucketDto {
|
||||||
* @interface ImportAssetDto
|
* @interface ImportAssetDto
|
||||||
*/
|
*/
|
||||||
export interface ImportAssetDto {
|
export interface ImportAssetDto {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {AssetTypeEnum}
|
|
||||||
* @memberof ImportAssetDto
|
|
||||||
*/
|
|
||||||
'assetType': AssetTypeEnum;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -1448,8 +1442,6 @@ export interface ImportAssetDto {
|
||||||
*/
|
*/
|
||||||
'duration'?: string;
|
'duration'?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
|
@ -5690,9 +5682,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetTypeEnum} assetType
|
|
||||||
* @param {File} assetData
|
* @param {File} assetData
|
||||||
* @param {string} fileExtension
|
|
||||||
* @param {string} deviceAssetId
|
* @param {string} deviceAssetId
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {string} fileCreatedAt
|
* @param {string} fileCreatedAt
|
||||||
|
@ -5708,13 +5698,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
uploadFile: async (assetType: AssetTypeEnum, assetData: File, fileExtension: string, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
uploadFile: async (assetData: File, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'assetType' is not null or undefined
|
|
||||||
assertParamExists('uploadFile', 'assetType', assetType)
|
|
||||||
// verify required parameter 'assetData' is not null or undefined
|
// verify required parameter 'assetData' is not null or undefined
|
||||||
assertParamExists('uploadFile', 'assetData', assetData)
|
assertParamExists('uploadFile', 'assetData', assetData)
|
||||||
// verify required parameter 'fileExtension' is not null or undefined
|
|
||||||
assertParamExists('uploadFile', 'fileExtension', fileExtension)
|
|
||||||
// verify required parameter 'deviceAssetId' is not null or undefined
|
// verify required parameter 'deviceAssetId' is not null or undefined
|
||||||
assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId)
|
assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId)
|
||||||
// verify required parameter 'deviceId' is not null or undefined
|
// verify required parameter 'deviceId' is not null or undefined
|
||||||
|
@ -5752,10 +5738,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (assetType !== undefined) {
|
|
||||||
localVarFormParams.append('assetType', new Blob([JSON.stringify(assetType)], { type: "application/json", }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assetData !== undefined) {
|
if (assetData !== undefined) {
|
||||||
localVarFormParams.append('assetData', assetData as any);
|
localVarFormParams.append('assetData', assetData as any);
|
||||||
}
|
}
|
||||||
|
@ -5772,10 +5754,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
localVarFormParams.append('isReadOnly', isReadOnly as any);
|
localVarFormParams.append('isReadOnly', isReadOnly as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileExtension !== undefined) {
|
|
||||||
localVarFormParams.append('fileExtension', fileExtension as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceAssetId !== undefined) {
|
if (deviceAssetId !== undefined) {
|
||||||
localVarFormParams.append('deviceAssetId', deviceAssetId as any);
|
localVarFormParams.append('deviceAssetId', deviceAssetId as any);
|
||||||
}
|
}
|
||||||
|
@ -6089,9 +6067,7 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetTypeEnum} assetType
|
|
||||||
* @param {File} assetData
|
* @param {File} assetData
|
||||||
* @param {string} fileExtension
|
|
||||||
* @param {string} deviceAssetId
|
* @param {string} deviceAssetId
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {string} fileCreatedAt
|
* @param {string} fileCreatedAt
|
||||||
|
@ -6107,8 +6083,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async uploadFile(assetType: AssetTypeEnum, assetData: File, fileExtension: string, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
|
async uploadFile(assetData: File, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -6339,7 +6315,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig): AxiosPromise<AssetFileUploadResponseDto> {
|
uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig): AxiosPromise<AssetFileUploadResponseDto> {
|
||||||
return localVarFp.uploadFile(requestParameters.assetType, requestParameters.assetData, requestParameters.fileExtension, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(axios, basePath));
|
return localVarFp.uploadFile(requestParameters.assetData, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -6763,13 +6739,6 @@ export interface AssetApiUpdateAssetRequest {
|
||||||
* @interface AssetApiUploadFileRequest
|
* @interface AssetApiUploadFileRequest
|
||||||
*/
|
*/
|
||||||
export interface AssetApiUploadFileRequest {
|
export interface AssetApiUploadFileRequest {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {AssetTypeEnum}
|
|
||||||
* @memberof AssetApiUploadFile
|
|
||||||
*/
|
|
||||||
readonly assetType: AssetTypeEnum
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {File}
|
* @type {File}
|
||||||
|
@ -6777,13 +6746,6 @@ export interface AssetApiUploadFileRequest {
|
||||||
*/
|
*/
|
||||||
readonly assetData: File
|
readonly assetData: File
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AssetApiUploadFile
|
|
||||||
*/
|
|
||||||
readonly fileExtension: string
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
@ -7143,7 +7105,7 @@ export class AssetApi extends BaseAPI {
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig) {
|
public uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).uploadFile(requestParameters.assetType, requestParameters.assetData, requestParameters.fileExtension, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).uploadFile(requestParameters.assetData, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -71,7 +71,6 @@ export default class Upload extends BaseCommand {
|
||||||
const importData = {
|
const importData = {
|
||||||
assetPath: asset.path,
|
assetPath: asset.path,
|
||||||
deviceAssetId: asset.deviceAssetId,
|
deviceAssetId: asset.deviceAssetId,
|
||||||
assetType: asset.assetType,
|
|
||||||
deviceId: this.deviceId,
|
deviceId: this.deviceId,
|
||||||
fileCreatedAt: asset.fileCreatedAt,
|
fileCreatedAt: asset.fileCreatedAt,
|
||||||
fileModifiedAt: asset.fileModifiedAt,
|
fileModifiedAt: asset.fileModifiedAt,
|
||||||
|
@ -157,8 +156,6 @@ export default class Upload extends BaseCommand {
|
||||||
uploadFormData.append('fileCreatedAt', asset.fileCreatedAt);
|
uploadFormData.append('fileCreatedAt', asset.fileCreatedAt);
|
||||||
uploadFormData.append('fileModifiedAt', asset.fileModifiedAt);
|
uploadFormData.append('fileModifiedAt', asset.fileModifiedAt);
|
||||||
uploadFormData.append('isFavorite', String(false));
|
uploadFormData.append('isFavorite', String(false));
|
||||||
uploadFormData.append('fileExtension', asset.fileExtension);
|
|
||||||
uploadFormData.append('assetType', asset.assetType);
|
|
||||||
uploadFormData.append('assetData', asset.assetData, { filename: asset.path });
|
uploadFormData.append('assetData', asset.assetData, { filename: asset.path });
|
||||||
|
|
||||||
if (asset.sidecarData) {
|
if (asset.sidecarData) {
|
||||||
|
|
|
@ -1,19 +1,14 @@
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as mime from 'mime-types';
|
|
||||||
import { basename } from 'node:path';
|
import { basename } from 'node:path';
|
||||||
import * as path from 'path';
|
|
||||||
import crypto from 'crypto';
|
import crypto from 'crypto';
|
||||||
import { AssetTypeEnum } from 'src/api/open-api';
|
|
||||||
|
|
||||||
export class CrawledAsset {
|
export class CrawledAsset {
|
||||||
public path: string;
|
public path: string;
|
||||||
|
|
||||||
public assetType?: AssetTypeEnum;
|
|
||||||
public assetData?: fs.ReadStream;
|
public assetData?: fs.ReadStream;
|
||||||
public deviceAssetId?: string;
|
public deviceAssetId?: string;
|
||||||
public fileCreatedAt?: string;
|
public fileCreatedAt?: string;
|
||||||
public fileModifiedAt?: string;
|
public fileModifiedAt?: string;
|
||||||
public fileExtension?: string;
|
|
||||||
public sidecarData?: Buffer;
|
public sidecarData?: Buffer;
|
||||||
public sidecarPath?: string;
|
public sidecarPath?: string;
|
||||||
public fileSize!: number;
|
public fileSize!: number;
|
||||||
|
@ -30,16 +25,8 @@ export class CrawledAsset {
|
||||||
async process() {
|
async process() {
|
||||||
const stats = await fs.promises.stat(this.path);
|
const stats = await fs.promises.stat(this.path);
|
||||||
this.deviceAssetId = `${basename(this.path)}-${stats.size}`.replace(/\s+/g, '');
|
this.deviceAssetId = `${basename(this.path)}-${stats.size}`.replace(/\s+/g, '');
|
||||||
|
|
||||||
// TODO: Determine file type from extension only
|
|
||||||
const mimeType = mime.lookup(this.path);
|
|
||||||
if (!mimeType) {
|
|
||||||
throw Error('Cannot determine mime type of asset: ' + this.path);
|
|
||||||
}
|
|
||||||
this.assetType = mimeType.split('/')[0].toUpperCase() as AssetTypeEnum;
|
|
||||||
this.fileCreatedAt = stats.ctime.toISOString();
|
this.fileCreatedAt = stats.ctime.toISOString();
|
||||||
this.fileModifiedAt = stats.mtime.toISOString();
|
this.fileModifiedAt = stats.mtime.toISOString();
|
||||||
this.fileExtension = path.extname(this.path);
|
|
||||||
this.fileSize = stats.size;
|
this.fileSize = stats.size;
|
||||||
|
|
||||||
// TODO: doesn't xmp replace the file extension? Will need investigation
|
// TODO: doesn't xmp replace the file extension? Will need investigation
|
||||||
|
|
|
@ -21,7 +21,6 @@ describe('UploadService', () => {
|
||||||
|
|
||||||
it('should upload a single file', async () => {
|
it('should upload a single file', async () => {
|
||||||
const data = new FormData();
|
const data = new FormData();
|
||||||
data.append('assetType', 'image');
|
|
||||||
|
|
||||||
uploadService.upload(data);
|
uploadService.upload(data);
|
||||||
|
|
||||||
|
|
|
@ -14,15 +14,13 @@ import 'package:immich_mobile/shared/models/store.dart';
|
||||||
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
import 'package:immich_mobile/shared/providers/api.provider.dart';
|
||||||
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||||
import 'package:immich_mobile/utils/files_helper.dart';
|
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
import 'package:photo_manager/photo_manager.dart';
|
import 'package:photo_manager/photo_manager.dart';
|
||||||
import 'package:http_parser/http_parser.dart';
|
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
import 'package:cancellation_token_http/http.dart' as http;
|
import 'package:cancellation_token_http/http.dart' as http;
|
||||||
|
import 'package:path/path.dart' as p;
|
||||||
|
|
||||||
final backupServiceProvider = Provider(
|
final backupServiceProvider = Provider(
|
||||||
(ref) => BackupService(
|
(ref) => BackupService(
|
||||||
|
@ -230,18 +228,12 @@ class BackupService {
|
||||||
|
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
String originalFileName = await entity.titleAsync;
|
String originalFileName = await entity.titleAsync;
|
||||||
var fileExtension = p.extension(file.path);
|
|
||||||
var mimeType = FileHelper.getMimeType(file.path);
|
|
||||||
var fileStream = file.openRead();
|
var fileStream = file.openRead();
|
||||||
var assetRawUploadData = http.MultipartFile(
|
var assetRawUploadData = http.MultipartFile(
|
||||||
"assetData",
|
"assetData",
|
||||||
fileStream,
|
fileStream,
|
||||||
file.lengthSync(),
|
file.lengthSync(),
|
||||||
filename: originalFileName,
|
filename: originalFileName,
|
||||||
contentType: MediaType(
|
|
||||||
mimeType["type"],
|
|
||||||
mimeType["subType"],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
var req = MultipartRequest(
|
var req = MultipartRequest(
|
||||||
|
@ -256,12 +248,10 @@ class BackupService {
|
||||||
|
|
||||||
req.fields['deviceAssetId'] = entity.id;
|
req.fields['deviceAssetId'] = entity.id;
|
||||||
req.fields['deviceId'] = deviceId;
|
req.fields['deviceId'] = deviceId;
|
||||||
req.fields['assetType'] = _getAssetType(entity.type);
|
|
||||||
req.fields['fileCreatedAt'] = entity.createDateTime.toIso8601String();
|
req.fields['fileCreatedAt'] = entity.createDateTime.toIso8601String();
|
||||||
req.fields['fileModifiedAt'] =
|
req.fields['fileModifiedAt'] =
|
||||||
entity.modifiedDateTime.toIso8601String();
|
entity.modifiedDateTime.toIso8601String();
|
||||||
req.fields['isFavorite'] = entity.isFavorite.toString();
|
req.fields['isFavorite'] = entity.isFavorite.toString();
|
||||||
req.fields['fileExtension'] = fileExtension;
|
|
||||||
req.fields['duration'] = entity.videoDuration.toString();
|
req.fields['duration'] = entity.videoDuration.toString();
|
||||||
|
|
||||||
req.files.add(assetRawUploadData);
|
req.files.add(assetRawUploadData);
|
||||||
|
@ -342,18 +332,12 @@ class BackupService {
|
||||||
var validPath = motionFilePath.replaceAll('file://', '');
|
var validPath = motionFilePath.replaceAll('file://', '');
|
||||||
var motionFile = File(validPath);
|
var motionFile = File(validPath);
|
||||||
var fileStream = motionFile.openRead();
|
var fileStream = motionFile.openRead();
|
||||||
String originalFileName = await entity.titleAsync;
|
String fileName = p.basename(motionFile.path);
|
||||||
var mimeType = FileHelper.getMimeType(validPath);
|
|
||||||
|
|
||||||
return http.MultipartFile(
|
return http.MultipartFile(
|
||||||
"livePhotoData",
|
"livePhotoData",
|
||||||
fileStream,
|
fileStream,
|
||||||
motionFile.lengthSync(),
|
motionFile.lengthSync(),
|
||||||
filename: originalFileName,
|
filename: fileName,
|
||||||
contentType: MediaType(
|
|
||||||
mimeType["type"],
|
|
||||||
mimeType["subType"],
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:http/http.dart';
|
import 'package:http/http.dart';
|
||||||
import 'package:http_parser/http_parser.dart';
|
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
import 'package:immich_mobile/modules/partner/services/partner.service.dart';
|
import 'package:immich_mobile/modules/partner/services/partner.service.dart';
|
||||||
import 'package:immich_mobile/shared/models/store.dart';
|
import 'package:immich_mobile/shared/models/store.dart';
|
||||||
|
@ -11,7 +10,6 @@ import 'package:immich_mobile/shared/providers/db.provider.dart';
|
||||||
import 'package:immich_mobile/shared/services/api.service.dart';
|
import 'package:immich_mobile/shared/services/api.service.dart';
|
||||||
import 'package:immich_mobile/shared/services/sync.service.dart';
|
import 'package:immich_mobile/shared/services/sync.service.dart';
|
||||||
import 'package:immich_mobile/utils/diff.dart';
|
import 'package:immich_mobile/utils/diff.dart';
|
||||||
import 'package:immich_mobile/utils/files_helper.dart';
|
|
||||||
import 'package:isar/isar.dart';
|
import 'package:isar/isar.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:openapi/api.dart';
|
import 'package:openapi/api.dart';
|
||||||
|
@ -59,17 +57,11 @@ class UserService {
|
||||||
|
|
||||||
Future<CreateProfileImageResponseDto?> uploadProfileImage(XFile image) async {
|
Future<CreateProfileImageResponseDto?> uploadProfileImage(XFile image) async {
|
||||||
try {
|
try {
|
||||||
var mimeType = FileHelper.getMimeType(image.path);
|
|
||||||
|
|
||||||
return await _apiService.userApi.createProfileImage(
|
return await _apiService.userApi.createProfileImage(
|
||||||
MultipartFile.fromBytes(
|
MultipartFile.fromBytes(
|
||||||
'file',
|
'file',
|
||||||
await image.readAsBytes(),
|
await image.readAsBytes(),
|
||||||
filename: image.name,
|
filename: image.name,
|
||||||
contentType: MediaType(
|
|
||||||
mimeType["type"],
|
|
||||||
mimeType["subType"],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|
|
@ -1,150 +0,0 @@
|
||||||
import 'package:path/path.dart' as p;
|
|
||||||
|
|
||||||
class FileHelper {
|
|
||||||
static getMimeType(String filePath) {
|
|
||||||
var fileExtension = p.extension(filePath).split(".")[1];
|
|
||||||
|
|
||||||
switch (fileExtension.toLowerCase()) {
|
|
||||||
case 'gif':
|
|
||||||
return {"type": "image", "subType": "gif"};
|
|
||||||
|
|
||||||
case 'jpeg':
|
|
||||||
return {"type": "image", "subType": "jpeg"};
|
|
||||||
|
|
||||||
case 'jpg':
|
|
||||||
return {"type": "image", "subType": "jpeg"};
|
|
||||||
|
|
||||||
case 'png':
|
|
||||||
return {"type": "image", "subType": "png"};
|
|
||||||
|
|
||||||
case 'tif':
|
|
||||||
return {"type": "image", "subType": "tiff"};
|
|
||||||
|
|
||||||
case 'mov':
|
|
||||||
return {"type": "video", "subType": "quicktime"};
|
|
||||||
|
|
||||||
case 'mp4':
|
|
||||||
return {"type": "video", "subType": "mp4"};
|
|
||||||
|
|
||||||
case 'avi':
|
|
||||||
return {"type": "video", "subType": "x-msvideo"};
|
|
||||||
|
|
||||||
case 'heic':
|
|
||||||
return {"type": "image", "subType": "heic"};
|
|
||||||
|
|
||||||
case 'heif':
|
|
||||||
return {"type": "image", "subType": "heif"};
|
|
||||||
|
|
||||||
case 'dng':
|
|
||||||
return {"type": "image", "subType": "dng"};
|
|
||||||
|
|
||||||
case 'webp':
|
|
||||||
return {"type": "image", "subType": "webp"};
|
|
||||||
|
|
||||||
case '3gp':
|
|
||||||
return {"type": "video", "subType": "3gpp"};
|
|
||||||
|
|
||||||
case 'webm':
|
|
||||||
return {"type": "video", "subType": "webm"};
|
|
||||||
|
|
||||||
case 'avif':
|
|
||||||
return {"type": "image", "subType": "avif"};
|
|
||||||
|
|
||||||
case 'insp':
|
|
||||||
return {"type": "image", "subType": "jpeg"};
|
|
||||||
|
|
||||||
case 'insv':
|
|
||||||
return {"type": "video", "subType": "mp4"};
|
|
||||||
|
|
||||||
case 'arw':
|
|
||||||
return {"type": "image", "subType": "x-sony-arw"};
|
|
||||||
|
|
||||||
case 'raf':
|
|
||||||
return {"type": "image", "subType": "x-fuji-raf"};
|
|
||||||
|
|
||||||
case 'nef':
|
|
||||||
return {"type": "image", "subType": "x-nikon-nef"};
|
|
||||||
|
|
||||||
case 'srw':
|
|
||||||
return {"type": "image", "subType": "x-samsung-srw"};
|
|
||||||
|
|
||||||
case 'crw':
|
|
||||||
return {"type": "image", "subType": "x-canon-crw"};
|
|
||||||
|
|
||||||
case 'cr2':
|
|
||||||
return {"type": "image", "subType": "x-canon-cr2"};
|
|
||||||
|
|
||||||
case 'cr3':
|
|
||||||
return {"type": "image", "subType": "x-canon-cr3"};
|
|
||||||
|
|
||||||
case 'erf':
|
|
||||||
return {"type": "image", "subType": "x-epson-erf"};
|
|
||||||
|
|
||||||
case 'dcr':
|
|
||||||
return {"type": "image", "subType": "x-kodak-dcr"};
|
|
||||||
|
|
||||||
case 'k25':
|
|
||||||
return {"type": "image", "subType": "x-kodak-k25"};
|
|
||||||
|
|
||||||
case 'kdc':
|
|
||||||
return {"type": "image", "subType": "x-kodak-kdc"};
|
|
||||||
|
|
||||||
case 'mrw':
|
|
||||||
return {"type": "image", "subType": "x-minolta-mrw"};
|
|
||||||
|
|
||||||
case 'orf':
|
|
||||||
return {"type": "image", "subType": "x-olympus-orf"};
|
|
||||||
|
|
||||||
case 'raw':
|
|
||||||
return {"type": "image", "subType": "x-panasonic-raw"};
|
|
||||||
|
|
||||||
case 'pef':
|
|
||||||
return {"type": "image", "subType": "x-panasonic-pef"};
|
|
||||||
|
|
||||||
case 'x3f':
|
|
||||||
return {"type": "image", "subType": "x-sigma-x3f"};
|
|
||||||
|
|
||||||
case 'srf':
|
|
||||||
return {"type": "image", "subType": "x-sony-srf"};
|
|
||||||
|
|
||||||
case 'sr2':
|
|
||||||
return {"type": "image", "subType": "x-sony-sr2"};
|
|
||||||
|
|
||||||
case '3fr':
|
|
||||||
return {"type": "image", "subType": "x-hasselblad-3fr"};
|
|
||||||
|
|
||||||
case 'fff':
|
|
||||||
return {"type": "image", "subType": "x-hasselblad-fff"};
|
|
||||||
|
|
||||||
case 'rwl':
|
|
||||||
return {"type": "image", "subType": "x-leica-rwl"};
|
|
||||||
|
|
||||||
case 'ori':
|
|
||||||
return {"type": "image", "subType": "x-olympus-ori"};
|
|
||||||
|
|
||||||
case 'iiq':
|
|
||||||
return {"type": "image", "subType": "x-phaseone-iiq"};
|
|
||||||
|
|
||||||
case 'ari':
|
|
||||||
return {"type": "image", "subType": "x-arriflex-ari"};
|
|
||||||
|
|
||||||
case 'cap':
|
|
||||||
return {"type": "image", "subType": "x-phaseone-cap"};
|
|
||||||
|
|
||||||
case 'cin':
|
|
||||||
return {"type": "image", "subType": "x-phantom-cin"};
|
|
||||||
|
|
||||||
case 'jxl':
|
|
||||||
return {"type": "image", "subType": "jxl"};
|
|
||||||
|
|
||||||
case 'mts':
|
|
||||||
return {"type": "video", "subType": "mp2t"};
|
|
||||||
|
|
||||||
case 'm2ts':
|
|
||||||
return {"type": "video", "subType": "mp2t"};
|
|
||||||
|
|
||||||
default:
|
|
||||||
return {"type": "unsupport", "subType": "unsupport"};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
8
mobile/openapi/doc/AssetApi.md
generated
8
mobile/openapi/doc/AssetApi.md
generated
|
@ -1393,7 +1393,7 @@ Name | Type | Description | Notes
|
||||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||||
|
|
||||||
# **uploadFile**
|
# **uploadFile**
|
||||||
> AssetFileUploadResponseDto uploadFile(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration)
|
> AssetFileUploadResponseDto uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1416,9 +1416,7 @@ import 'package:openapi/api.dart';
|
||||||
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
//defaultApiClient.getAuthentication<HttpBearerAuth>('bearer').setAccessToken(yourTokenGeneratorFunction);
|
||||||
|
|
||||||
final api_instance = AssetApi();
|
final api_instance = AssetApi();
|
||||||
final assetType = ; // AssetTypeEnum |
|
|
||||||
final assetData = BINARY_DATA_HERE; // MultipartFile |
|
final assetData = BINARY_DATA_HERE; // MultipartFile |
|
||||||
final fileExtension = fileExtension_example; // String |
|
|
||||||
final deviceAssetId = deviceAssetId_example; // String |
|
final deviceAssetId = deviceAssetId_example; // String |
|
||||||
final deviceId = deviceId_example; // String |
|
final deviceId = deviceId_example; // String |
|
||||||
final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime |
|
final fileCreatedAt = 2013-10-20T19:20:30+01:00; // DateTime |
|
||||||
|
@ -1433,7 +1431,7 @@ final isVisible = true; // bool |
|
||||||
final duration = duration_example; // String |
|
final duration = duration_example; // String |
|
||||||
|
|
||||||
try {
|
try {
|
||||||
final result = api_instance.uploadFile(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration);
|
final result = api_instance.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration);
|
||||||
print(result);
|
print(result);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
print('Exception when calling AssetApi->uploadFile: $e\n');
|
print('Exception when calling AssetApi->uploadFile: $e\n');
|
||||||
|
@ -1444,9 +1442,7 @@ try {
|
||||||
|
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------- | ------------- | ------------- | -------------
|
------------- | ------------- | ------------- | -------------
|
||||||
**assetType** | [**AssetTypeEnum**](AssetTypeEnum.md)| |
|
|
||||||
**assetData** | **MultipartFile**| |
|
**assetData** | **MultipartFile**| |
|
||||||
**fileExtension** | **String**| |
|
|
||||||
**deviceAssetId** | **String**| |
|
**deviceAssetId** | **String**| |
|
||||||
**deviceId** | **String**| |
|
**deviceId** | **String**| |
|
||||||
**fileCreatedAt** | **DateTime**| |
|
**fileCreatedAt** | **DateTime**| |
|
||||||
|
|
1
mobile/openapi/doc/ImportAssetDto.md
generated
1
mobile/openapi/doc/ImportAssetDto.md
generated
|
@ -8,7 +8,6 @@ import 'package:openapi/api.dart';
|
||||||
## Properties
|
## Properties
|
||||||
Name | Type | Description | Notes
|
Name | Type | Description | Notes
|
||||||
------------ | ------------- | ------------- | -------------
|
------------ | ------------- | ------------- | -------------
|
||||||
**assetType** | [**AssetTypeEnum**](AssetTypeEnum.md) | |
|
|
||||||
**isReadOnly** | **bool** | | [optional] [default to true]
|
**isReadOnly** | **bool** | | [optional] [default to true]
|
||||||
**assetPath** | **String** | |
|
**assetPath** | **String** | |
|
||||||
**sidecarPath** | **String** | | [optional]
|
**sidecarPath** | **String** | | [optional]
|
||||||
|
|
22
mobile/openapi/lib/api/asset_api.dart
generated
22
mobile/openapi/lib/api/asset_api.dart
generated
|
@ -1359,12 +1359,8 @@ class AssetApi {
|
||||||
/// Performs an HTTP 'POST /asset/upload' operation and returns the [Response].
|
/// Performs an HTTP 'POST /asset/upload' operation and returns the [Response].
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
///
|
///
|
||||||
/// * [AssetTypeEnum] assetType (required):
|
|
||||||
///
|
|
||||||
/// * [MultipartFile] assetData (required):
|
/// * [MultipartFile] assetData (required):
|
||||||
///
|
///
|
||||||
/// * [String] fileExtension (required):
|
|
||||||
///
|
|
||||||
/// * [String] deviceAssetId (required):
|
/// * [String] deviceAssetId (required):
|
||||||
///
|
///
|
||||||
/// * [String] deviceId (required):
|
/// * [String] deviceId (required):
|
||||||
|
@ -1388,7 +1384,7 @@ class AssetApi {
|
||||||
/// * [bool] isVisible:
|
/// * [bool] isVisible:
|
||||||
///
|
///
|
||||||
/// * [String] duration:
|
/// * [String] duration:
|
||||||
Future<Response> uploadFileWithHttpInfo(AssetTypeEnum assetType, MultipartFile assetData, String fileExtension, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, MultipartFile? livePhotoData, MultipartFile? sidecarData, bool? isReadOnly, bool? isArchived, bool? isVisible, String? duration, }) async {
|
Future<Response> uploadFileWithHttpInfo(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, MultipartFile? livePhotoData, MultipartFile? sidecarData, bool? isReadOnly, bool? isArchived, bool? isVisible, String? duration, }) async {
|
||||||
// ignore: prefer_const_declarations
|
// ignore: prefer_const_declarations
|
||||||
final path = r'/asset/upload';
|
final path = r'/asset/upload';
|
||||||
|
|
||||||
|
@ -1407,10 +1403,6 @@ class AssetApi {
|
||||||
|
|
||||||
bool hasFields = false;
|
bool hasFields = false;
|
||||||
final mp = MultipartRequest('POST', Uri.parse(path));
|
final mp = MultipartRequest('POST', Uri.parse(path));
|
||||||
if (assetType != null) {
|
|
||||||
hasFields = true;
|
|
||||||
mp.fields[r'assetType'] = parameterToString(assetType);
|
|
||||||
}
|
|
||||||
if (assetData != null) {
|
if (assetData != null) {
|
||||||
hasFields = true;
|
hasFields = true;
|
||||||
mp.fields[r'assetData'] = assetData.field;
|
mp.fields[r'assetData'] = assetData.field;
|
||||||
|
@ -1430,10 +1422,6 @@ class AssetApi {
|
||||||
hasFields = true;
|
hasFields = true;
|
||||||
mp.fields[r'isReadOnly'] = parameterToString(isReadOnly);
|
mp.fields[r'isReadOnly'] = parameterToString(isReadOnly);
|
||||||
}
|
}
|
||||||
if (fileExtension != null) {
|
|
||||||
hasFields = true;
|
|
||||||
mp.fields[r'fileExtension'] = parameterToString(fileExtension);
|
|
||||||
}
|
|
||||||
if (deviceAssetId != null) {
|
if (deviceAssetId != null) {
|
||||||
hasFields = true;
|
hasFields = true;
|
||||||
mp.fields[r'deviceAssetId'] = parameterToString(deviceAssetId);
|
mp.fields[r'deviceAssetId'] = parameterToString(deviceAssetId);
|
||||||
|
@ -1483,12 +1471,8 @@ class AssetApi {
|
||||||
|
|
||||||
/// Parameters:
|
/// Parameters:
|
||||||
///
|
///
|
||||||
/// * [AssetTypeEnum] assetType (required):
|
|
||||||
///
|
|
||||||
/// * [MultipartFile] assetData (required):
|
/// * [MultipartFile] assetData (required):
|
||||||
///
|
///
|
||||||
/// * [String] fileExtension (required):
|
|
||||||
///
|
|
||||||
/// * [String] deviceAssetId (required):
|
/// * [String] deviceAssetId (required):
|
||||||
///
|
///
|
||||||
/// * [String] deviceId (required):
|
/// * [String] deviceId (required):
|
||||||
|
@ -1512,8 +1496,8 @@ class AssetApi {
|
||||||
/// * [bool] isVisible:
|
/// * [bool] isVisible:
|
||||||
///
|
///
|
||||||
/// * [String] duration:
|
/// * [String] duration:
|
||||||
Future<AssetFileUploadResponseDto?> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String fileExtension, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, MultipartFile? livePhotoData, MultipartFile? sidecarData, bool? isReadOnly, bool? isArchived, bool? isVisible, String? duration, }) async {
|
Future<AssetFileUploadResponseDto?> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String? key, MultipartFile? livePhotoData, MultipartFile? sidecarData, bool? isReadOnly, bool? isArchived, bool? isVisible, String? duration, }) async {
|
||||||
final response = await uploadFileWithHttpInfo(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key: key, livePhotoData: livePhotoData, sidecarData: sidecarData, isReadOnly: isReadOnly, isArchived: isArchived, isVisible: isVisible, duration: duration, );
|
final response = await uploadFileWithHttpInfo(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key: key, livePhotoData: livePhotoData, sidecarData: sidecarData, isReadOnly: isReadOnly, isArchived: isArchived, isVisible: isVisible, duration: duration, );
|
||||||
if (response.statusCode >= HttpStatus.badRequest) {
|
if (response.statusCode >= HttpStatus.badRequest) {
|
||||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||||
}
|
}
|
||||||
|
|
10
mobile/openapi/lib/model/import_asset_dto.dart
generated
10
mobile/openapi/lib/model/import_asset_dto.dart
generated
|
@ -13,7 +13,6 @@ part of openapi.api;
|
||||||
class ImportAssetDto {
|
class ImportAssetDto {
|
||||||
/// Returns a new [ImportAssetDto] instance.
|
/// Returns a new [ImportAssetDto] instance.
|
||||||
ImportAssetDto({
|
ImportAssetDto({
|
||||||
required this.assetType,
|
|
||||||
this.isReadOnly = true,
|
this.isReadOnly = true,
|
||||||
required this.assetPath,
|
required this.assetPath,
|
||||||
this.sidecarPath,
|
this.sidecarPath,
|
||||||
|
@ -27,8 +26,6 @@ class ImportAssetDto {
|
||||||
this.duration,
|
this.duration,
|
||||||
});
|
});
|
||||||
|
|
||||||
AssetTypeEnum assetType;
|
|
||||||
|
|
||||||
bool isReadOnly;
|
bool isReadOnly;
|
||||||
|
|
||||||
String assetPath;
|
String assetPath;
|
||||||
|
@ -77,7 +74,6 @@ class ImportAssetDto {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool operator ==(Object other) => identical(this, other) || other is ImportAssetDto &&
|
bool operator ==(Object other) => identical(this, other) || other is ImportAssetDto &&
|
||||||
other.assetType == assetType &&
|
|
||||||
other.isReadOnly == isReadOnly &&
|
other.isReadOnly == isReadOnly &&
|
||||||
other.assetPath == assetPath &&
|
other.assetPath == assetPath &&
|
||||||
other.sidecarPath == sidecarPath &&
|
other.sidecarPath == sidecarPath &&
|
||||||
|
@ -93,7 +89,6 @@ class ImportAssetDto {
|
||||||
@override
|
@override
|
||||||
int get hashCode =>
|
int get hashCode =>
|
||||||
// ignore: unnecessary_parenthesis
|
// ignore: unnecessary_parenthesis
|
||||||
(assetType.hashCode) +
|
|
||||||
(isReadOnly.hashCode) +
|
(isReadOnly.hashCode) +
|
||||||
(assetPath.hashCode) +
|
(assetPath.hashCode) +
|
||||||
(sidecarPath == null ? 0 : sidecarPath!.hashCode) +
|
(sidecarPath == null ? 0 : sidecarPath!.hashCode) +
|
||||||
|
@ -107,11 +102,10 @@ class ImportAssetDto {
|
||||||
(duration == null ? 0 : duration!.hashCode);
|
(duration == null ? 0 : duration!.hashCode);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String toString() => 'ImportAssetDto[assetType=$assetType, isReadOnly=$isReadOnly, assetPath=$assetPath, sidecarPath=$sidecarPath, deviceAssetId=$deviceAssetId, deviceId=$deviceId, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, isFavorite=$isFavorite, isArchived=$isArchived, isVisible=$isVisible, duration=$duration]';
|
String toString() => 'ImportAssetDto[isReadOnly=$isReadOnly, assetPath=$assetPath, sidecarPath=$sidecarPath, deviceAssetId=$deviceAssetId, deviceId=$deviceId, fileCreatedAt=$fileCreatedAt, fileModifiedAt=$fileModifiedAt, isFavorite=$isFavorite, isArchived=$isArchived, isVisible=$isVisible, duration=$duration]';
|
||||||
|
|
||||||
Map<String, dynamic> toJson() {
|
Map<String, dynamic> toJson() {
|
||||||
final json = <String, dynamic>{};
|
final json = <String, dynamic>{};
|
||||||
json[r'assetType'] = this.assetType;
|
|
||||||
json[r'isReadOnly'] = this.isReadOnly;
|
json[r'isReadOnly'] = this.isReadOnly;
|
||||||
json[r'assetPath'] = this.assetPath;
|
json[r'assetPath'] = this.assetPath;
|
||||||
if (this.sidecarPath != null) {
|
if (this.sidecarPath != null) {
|
||||||
|
@ -150,7 +144,6 @@ class ImportAssetDto {
|
||||||
final json = value.cast<String, dynamic>();
|
final json = value.cast<String, dynamic>();
|
||||||
|
|
||||||
return ImportAssetDto(
|
return ImportAssetDto(
|
||||||
assetType: AssetTypeEnum.fromJson(json[r'assetType'])!,
|
|
||||||
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly') ?? true,
|
isReadOnly: mapValueOfType<bool>(json, r'isReadOnly') ?? true,
|
||||||
assetPath: mapValueOfType<String>(json, r'assetPath')!,
|
assetPath: mapValueOfType<String>(json, r'assetPath')!,
|
||||||
sidecarPath: mapValueOfType<String>(json, r'sidecarPath'),
|
sidecarPath: mapValueOfType<String>(json, r'sidecarPath'),
|
||||||
|
@ -209,7 +202,6 @@ class ImportAssetDto {
|
||||||
|
|
||||||
/// The list of required keys that must be present in a JSON.
|
/// The list of required keys that must be present in a JSON.
|
||||||
static const requiredKeys = <String>{
|
static const requiredKeys = <String>{
|
||||||
'assetType',
|
|
||||||
'assetPath',
|
'assetPath',
|
||||||
'deviceAssetId',
|
'deviceAssetId',
|
||||||
'deviceId',
|
'deviceId',
|
||||||
|
|
2
mobile/openapi/test/asset_api_test.dart
generated
2
mobile/openapi/test/asset_api_test.dart
generated
|
@ -151,7 +151,7 @@ void main() {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
||||||
//Future<AssetFileUploadResponseDto> uploadFile(AssetTypeEnum assetType, MultipartFile assetData, String fileExtension, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String key, MultipartFile livePhotoData, MultipartFile sidecarData, bool isReadOnly, bool isArchived, bool isVisible, String duration }) async
|
//Future<AssetFileUploadResponseDto> uploadFile(MultipartFile assetData, String deviceAssetId, String deviceId, DateTime fileCreatedAt, DateTime fileModifiedAt, bool isFavorite, { String key, MultipartFile livePhotoData, MultipartFile sidecarData, bool isReadOnly, bool isArchived, bool isVisible, String duration }) async
|
||||||
test('test uploadFile', () async {
|
test('test uploadFile', () async {
|
||||||
// TODO
|
// TODO
|
||||||
});
|
});
|
||||||
|
|
5
mobile/openapi/test/import_asset_dto_test.dart
generated
5
mobile/openapi/test/import_asset_dto_test.dart
generated
|
@ -16,11 +16,6 @@ void main() {
|
||||||
// final instance = ImportAssetDto();
|
// final instance = ImportAssetDto();
|
||||||
|
|
||||||
group('test ImportAssetDto', () {
|
group('test ImportAssetDto', () {
|
||||||
// AssetTypeEnum assetType
|
|
||||||
test('to test the property `assetType`', () async {
|
|
||||||
// TODO
|
|
||||||
});
|
|
||||||
|
|
||||||
// bool isReadOnly (default value: true)
|
// bool isReadOnly (default value: true)
|
||||||
test('to test the property `isReadOnly`', () async {
|
test('to test the property `isReadOnly`', () async {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
|
@ -5148,9 +5148,6 @@
|
||||||
"CreateAssetDto": {
|
"CreateAssetDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"assetType": {
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
},
|
|
||||||
"assetData": {
|
"assetData": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"format": "binary"
|
"format": "binary"
|
||||||
|
@ -5167,9 +5164,6 @@
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false
|
"default": false
|
||||||
},
|
},
|
||||||
"fileExtension": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"deviceAssetId": {
|
"deviceAssetId": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
@ -5198,9 +5192,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"assetType",
|
|
||||||
"assetData",
|
"assetData",
|
||||||
"fileExtension",
|
|
||||||
"deviceAssetId",
|
"deviceAssetId",
|
||||||
"deviceId",
|
"deviceId",
|
||||||
"fileCreatedAt",
|
"fileCreatedAt",
|
||||||
|
@ -5571,9 +5563,6 @@
|
||||||
"ImportAssetDto": {
|
"ImportAssetDto": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
"assetType": {
|
|
||||||
"$ref": "#/components/schemas/AssetTypeEnum"
|
|
||||||
},
|
|
||||||
"isReadOnly": {
|
"isReadOnly": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": true
|
"default": true
|
||||||
|
@ -5612,7 +5601,6 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
"assetType",
|
|
||||||
"assetPath",
|
"assetPath",
|
||||||
"deviceAssetId",
|
"deviceAssetId",
|
||||||
"deviceId",
|
"deviceId",
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { AssetType } from '@app/infra/entities';
|
||||||
import { BadRequestException } from '@nestjs/common';
|
import { BadRequestException } from '@nestjs/common';
|
||||||
import { extname } from 'node:path';
|
import { extname } from 'node:path';
|
||||||
import pkg from 'src/../../package.json';
|
import pkg from 'src/../../package.json';
|
||||||
|
@ -91,6 +92,8 @@ const sidecar: Record<string, string> = {
|
||||||
|
|
||||||
const isType = (filename: string, lookup: Record<string, string>) => !!lookup[extname(filename).toLowerCase()];
|
const isType = (filename: string, lookup: Record<string, string>) => !!lookup[extname(filename).toLowerCase()];
|
||||||
const getType = (filename: string, lookup: Record<string, string>) => lookup[extname(filename).toLowerCase()];
|
const getType = (filename: string, lookup: Record<string, string>) => lookup[extname(filename).toLowerCase()];
|
||||||
|
const lookup = (filename: string) =>
|
||||||
|
getType(filename, { ...image, ...video, ...sidecar }) || 'application/octet-stream';
|
||||||
|
|
||||||
export const mimeTypes = {
|
export const mimeTypes = {
|
||||||
image,
|
image,
|
||||||
|
@ -102,5 +105,16 @@ export const mimeTypes = {
|
||||||
isProfile: (filename: string) => isType(filename, profile),
|
isProfile: (filename: string) => isType(filename, profile),
|
||||||
isSidecar: (filename: string) => isType(filename, sidecar),
|
isSidecar: (filename: string) => isType(filename, sidecar),
|
||||||
isVideo: (filename: string) => isType(filename, video),
|
isVideo: (filename: string) => isType(filename, video),
|
||||||
lookup: (filename: string) => getType(filename, { ...image, ...video, ...sidecar }) || 'application/octet-stream',
|
lookup,
|
||||||
|
assetType: (filename: string) => {
|
||||||
|
const contentType = lookup(filename).split('/')[0];
|
||||||
|
switch (contentType) {
|
||||||
|
case 'image':
|
||||||
|
return AssetType.IMAGE;
|
||||||
|
case 'video':
|
||||||
|
return AssetType.VIDEO;
|
||||||
|
default:
|
||||||
|
return AssetType.OTHER;
|
||||||
|
}
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { AuthUserDto, IJobRepository, JobName, UploadFile } from '@app/domain';
|
import { AuthUserDto, IJobRepository, JobName, mimeTypes, UploadFile } from '@app/domain';
|
||||||
import { AssetEntity, UserEntity } from '@app/infra/entities';
|
import { AssetEntity, UserEntity } from '@app/infra/entities';
|
||||||
import { parse } from 'node:path';
|
import { parse } from 'node:path';
|
||||||
import { IAssetRepository } from './asset-repository';
|
import { IAssetRepository } from './asset-repository';
|
||||||
|
@ -26,7 +26,7 @@ export class AssetCore {
|
||||||
fileCreatedAt: dto.fileCreatedAt,
|
fileCreatedAt: dto.fileCreatedAt,
|
||||||
fileModifiedAt: dto.fileModifiedAt,
|
fileModifiedAt: dto.fileModifiedAt,
|
||||||
|
|
||||||
type: dto.assetType,
|
type: mimeTypes.assetType(file.originalPath),
|
||||||
isFavorite: dto.isFavorite,
|
isFavorite: dto.isFavorite,
|
||||||
isArchived: dto.isArchived ?? false,
|
isArchived: dto.isArchived ?? false,
|
||||||
duration: dto.duration || null,
|
duration: dto.duration || null,
|
||||||
|
|
|
@ -32,7 +32,6 @@ const _getCreateAssetDto = (): CreateAssetDto => {
|
||||||
const createAssetDto = new CreateAssetDto();
|
const createAssetDto = new CreateAssetDto();
|
||||||
createAssetDto.deviceAssetId = 'deviceAssetId';
|
createAssetDto.deviceAssetId = 'deviceAssetId';
|
||||||
createAssetDto.deviceId = 'deviceId';
|
createAssetDto.deviceId = 'deviceId';
|
||||||
createAssetDto.assetType = AssetType.OTHER;
|
|
||||||
createAssetDto.fileCreatedAt = new Date('2022-06-19T23:41:36.910Z');
|
createAssetDto.fileCreatedAt = new Date('2022-06-19T23:41:36.910Z');
|
||||||
createAssetDto.fileModifiedAt = new Date('2022-06-19T23:41:36.910Z');
|
createAssetDto.fileModifiedAt = new Date('2022-06-19T23:41:36.910Z');
|
||||||
createAssetDto.isFavorite = false;
|
createAssetDto.isFavorite = false;
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
import { toBoolean, toSanitized, UploadFieldName } from '@app/domain';
|
import { toBoolean, toSanitized, UploadFieldName } from '@app/domain';
|
||||||
import { AssetType } from '@app/infra/entities';
|
|
||||||
import { ApiProperty } from '@nestjs/swagger';
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
import { Transform } from 'class-transformer';
|
import { Transform } from 'class-transformer';
|
||||||
import { IsBoolean, IsEnum, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
import { IsBoolean, IsNotEmpty, IsOptional, IsString } from 'class-validator';
|
||||||
|
|
||||||
export class CreateAssetBase {
|
export class CreateAssetBase {
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
|
@ -11,11 +10,6 @@ export class CreateAssetBase {
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
deviceId!: string;
|
deviceId!: string;
|
||||||
|
|
||||||
@IsNotEmpty()
|
|
||||||
@IsEnum(AssetType)
|
|
||||||
@ApiProperty({ enumName: 'AssetTypeEnum', enum: AssetType })
|
|
||||||
assetType!: AssetType;
|
|
||||||
|
|
||||||
@IsNotEmpty()
|
@IsNotEmpty()
|
||||||
fileCreatedAt!: Date;
|
fileCreatedAt!: Date;
|
||||||
|
|
||||||
|
@ -43,9 +37,6 @@ export class CreateAssetDto extends CreateAssetBase {
|
||||||
@Transform(toBoolean)
|
@Transform(toBoolean)
|
||||||
isReadOnly?: boolean = false;
|
isReadOnly?: boolean = false;
|
||||||
|
|
||||||
@IsNotEmpty()
|
|
||||||
fileExtension!: string;
|
|
||||||
|
|
||||||
// The properties below are added to correctly generate the API docs
|
// The properties below are added to correctly generate the API docs
|
||||||
// and client SDKs. Validation should be handled in the controller.
|
// and client SDKs. Validation should be handled in the controller.
|
||||||
@ApiProperty({ type: 'string', format: 'binary' })
|
@ApiProperty({ type: 'string', format: 'binary' })
|
||||||
|
|
52
web/src/api/open-api/api.ts
generated
52
web/src/api/open-api/api.ts
generated
|
@ -1375,12 +1375,6 @@ export interface GetAssetCountByTimeBucketDto {
|
||||||
* @interface ImportAssetDto
|
* @interface ImportAssetDto
|
||||||
*/
|
*/
|
||||||
export interface ImportAssetDto {
|
export interface ImportAssetDto {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {AssetTypeEnum}
|
|
||||||
* @memberof ImportAssetDto
|
|
||||||
*/
|
|
||||||
'assetType': AssetTypeEnum;
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {boolean}
|
* @type {boolean}
|
||||||
|
@ -1448,8 +1442,6 @@ export interface ImportAssetDto {
|
||||||
*/
|
*/
|
||||||
'duration'?: string;
|
'duration'?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @export
|
* @export
|
||||||
|
@ -5699,9 +5691,7 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetTypeEnum} assetType
|
|
||||||
* @param {File} assetData
|
* @param {File} assetData
|
||||||
* @param {string} fileExtension
|
|
||||||
* @param {string} deviceAssetId
|
* @param {string} deviceAssetId
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {string} fileCreatedAt
|
* @param {string} fileCreatedAt
|
||||||
|
@ -5717,13 +5707,9 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
uploadFile: async (assetType: AssetTypeEnum, assetData: File, fileExtension: string, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
uploadFile: async (assetData: File, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options: AxiosRequestConfig = {}): Promise<RequestArgs> => {
|
||||||
// verify required parameter 'assetType' is not null or undefined
|
|
||||||
assertParamExists('uploadFile', 'assetType', assetType)
|
|
||||||
// verify required parameter 'assetData' is not null or undefined
|
// verify required parameter 'assetData' is not null or undefined
|
||||||
assertParamExists('uploadFile', 'assetData', assetData)
|
assertParamExists('uploadFile', 'assetData', assetData)
|
||||||
// verify required parameter 'fileExtension' is not null or undefined
|
|
||||||
assertParamExists('uploadFile', 'fileExtension', fileExtension)
|
|
||||||
// verify required parameter 'deviceAssetId' is not null or undefined
|
// verify required parameter 'deviceAssetId' is not null or undefined
|
||||||
assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId)
|
assertParamExists('uploadFile', 'deviceAssetId', deviceAssetId)
|
||||||
// verify required parameter 'deviceId' is not null or undefined
|
// verify required parameter 'deviceId' is not null or undefined
|
||||||
|
@ -5761,10 +5747,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (assetType !== undefined) {
|
|
||||||
localVarFormParams.append('assetType', new Blob([JSON.stringify(assetType)], { type: "application/json", }));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (assetData !== undefined) {
|
if (assetData !== undefined) {
|
||||||
localVarFormParams.append('assetData', assetData as any);
|
localVarFormParams.append('assetData', assetData as any);
|
||||||
}
|
}
|
||||||
|
@ -5781,10 +5763,6 @@ export const AssetApiAxiosParamCreator = function (configuration?: Configuration
|
||||||
localVarFormParams.append('isReadOnly', isReadOnly as any);
|
localVarFormParams.append('isReadOnly', isReadOnly as any);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileExtension !== undefined) {
|
|
||||||
localVarFormParams.append('fileExtension', fileExtension as any);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (deviceAssetId !== undefined) {
|
if (deviceAssetId !== undefined) {
|
||||||
localVarFormParams.append('deviceAssetId', deviceAssetId as any);
|
localVarFormParams.append('deviceAssetId', deviceAssetId as any);
|
||||||
}
|
}
|
||||||
|
@ -6098,9 +6076,7 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetTypeEnum} assetType
|
|
||||||
* @param {File} assetData
|
* @param {File} assetData
|
||||||
* @param {string} fileExtension
|
|
||||||
* @param {string} deviceAssetId
|
* @param {string} deviceAssetId
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {string} fileCreatedAt
|
* @param {string} fileCreatedAt
|
||||||
|
@ -6116,8 +6092,8 @@ export const AssetApiFp = function(configuration?: Configuration) {
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
async uploadFile(assetType: AssetTypeEnum, assetData: File, fileExtension: string, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
|
async uploadFile(assetData: File, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<AssetFileUploadResponseDto>> {
|
||||||
const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options);
|
const localVarAxiosArgs = await localVarAxiosParamCreator.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options);
|
||||||
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration);
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -6364,9 +6340,7 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {AssetTypeEnum} assetType
|
|
||||||
* @param {File} assetData
|
* @param {File} assetData
|
||||||
* @param {string} fileExtension
|
|
||||||
* @param {string} deviceAssetId
|
* @param {string} deviceAssetId
|
||||||
* @param {string} deviceId
|
* @param {string} deviceId
|
||||||
* @param {string} fileCreatedAt
|
* @param {string} fileCreatedAt
|
||||||
|
@ -6382,8 +6356,8 @@ export const AssetApiFactory = function (configuration?: Configuration, basePath
|
||||||
* @param {*} [options] Override http request option.
|
* @param {*} [options] Override http request option.
|
||||||
* @throws {RequiredError}
|
* @throws {RequiredError}
|
||||||
*/
|
*/
|
||||||
uploadFile(assetType: AssetTypeEnum, assetData: File, fileExtension: string, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: any): AxiosPromise<AssetFileUploadResponseDto> {
|
uploadFile(assetData: File, deviceAssetId: string, deviceId: string, fileCreatedAt: string, fileModifiedAt: string, isFavorite: boolean, key?: string, livePhotoData?: File, sidecarData?: File, isReadOnly?: boolean, isArchived?: boolean, isVisible?: boolean, duration?: string, options?: any): AxiosPromise<AssetFileUploadResponseDto> {
|
||||||
return localVarFp.uploadFile(assetType, assetData, fileExtension, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options).then((request) => request(axios, basePath));
|
return localVarFp.uploadFile(assetData, deviceAssetId, deviceId, fileCreatedAt, fileModifiedAt, isFavorite, key, livePhotoData, sidecarData, isReadOnly, isArchived, isVisible, duration, options).then((request) => request(axios, basePath));
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
@ -6807,13 +6781,6 @@ export interface AssetApiUpdateAssetRequest {
|
||||||
* @interface AssetApiUploadFileRequest
|
* @interface AssetApiUploadFileRequest
|
||||||
*/
|
*/
|
||||||
export interface AssetApiUploadFileRequest {
|
export interface AssetApiUploadFileRequest {
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {AssetTypeEnum}
|
|
||||||
* @memberof AssetApiUploadFile
|
|
||||||
*/
|
|
||||||
readonly assetType: AssetTypeEnum
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {File}
|
* @type {File}
|
||||||
|
@ -6821,13 +6788,6 @@ export interface AssetApiUploadFileRequest {
|
||||||
*/
|
*/
|
||||||
readonly assetData: File
|
readonly assetData: File
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @type {string}
|
|
||||||
* @memberof AssetApiUploadFile
|
|
||||||
*/
|
|
||||||
readonly fileExtension: string
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
|
@ -7187,7 +7147,7 @@ export class AssetApi extends BaseAPI {
|
||||||
* @memberof AssetApi
|
* @memberof AssetApi
|
||||||
*/
|
*/
|
||||||
public uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig) {
|
public uploadFile(requestParameters: AssetApiUploadFileRequest, options?: AxiosRequestConfig) {
|
||||||
return AssetApiFp(this.configuration).uploadFile(requestParameters.assetType, requestParameters.assetData, requestParameters.fileExtension, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(this.axios, this.basePath));
|
return AssetApiFp(this.configuration).uploadFile(requestParameters.assetData, requestParameters.deviceAssetId, requestParameters.deviceId, requestParameters.fileCreatedAt, requestParameters.fileModifiedAt, requestParameters.isFavorite, requestParameters.key, requestParameters.livePhotoData, requestParameters.sidecarData, requestParameters.isReadOnly, requestParameters.isArchived, requestParameters.isVisible, requestParameters.duration, options).then((request) => request(this.axios, this.basePath));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
import { asByteUnitString } from '$lib/utils/byte-units';
|
import { asByteUnitString } from '$lib/utils/byte-units';
|
||||||
import { fade } from 'svelte/transition';
|
import { fade } from 'svelte/transition';
|
||||||
import ImmichLogo from './immich-logo.svelte';
|
import ImmichLogo from './immich-logo.svelte';
|
||||||
|
import { getFilenameExtension } from '../../utils/asset-utils';
|
||||||
|
|
||||||
export let uploadAsset: UploadAsset;
|
export let uploadAsset: UploadAsset;
|
||||||
|
|
||||||
|
@ -42,7 +43,7 @@
|
||||||
<p
|
<p
|
||||||
class="absolute bottom-1 right-1 object-right-bottom text-gray-50/95 font-semibold stroke-immich-primary uppercase"
|
class="absolute bottom-1 right-1 object-right-bottom text-gray-50/95 font-semibold stroke-immich-primary uppercase"
|
||||||
>
|
>
|
||||||
.{uploadAsset.fileExtension}
|
.{getFilenameExtension(uploadAsset.file.name)}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -2,5 +2,4 @@ export type UploadAsset = {
|
||||||
id: string;
|
id: string;
|
||||||
file: File;
|
file: File;
|
||||||
progress: number;
|
progress: number;
|
||||||
fileExtension: string;
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import type { AssetResponseDto } from '@api';
|
import type { AssetResponseDto } from '@api';
|
||||||
import { describe, expect, it } from '@jest/globals';
|
import { describe, expect, it } from '@jest/globals';
|
||||||
import { getAssetFilename, getFileMimeType, getFilenameExtension } from './asset-utils';
|
import { getAssetFilename, getFilenameExtension } from './asset-utils';
|
||||||
|
|
||||||
describe('get file extension from filename', () => {
|
describe('get file extension from filename', () => {
|
||||||
it('returns the extension without including the dot', () => {
|
it('returns the extension without including the dot', () => {
|
||||||
|
@ -57,88 +57,3 @@ describe('get asset filename', () => {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('get file mime type', () => {
|
|
||||||
for (const { mimetype, extension } of [
|
|
||||||
{ mimetype: 'image/avif', extension: 'avif' },
|
|
||||||
{ mimetype: 'image/gif', extension: 'gif' },
|
|
||||||
{ mimetype: 'image/heic', extension: 'heic' },
|
|
||||||
{ mimetype: 'image/heif', extension: 'heif' },
|
|
||||||
{ mimetype: 'image/jpeg', extension: 'jpeg' },
|
|
||||||
{ mimetype: 'image/jpeg', extension: 'jpg' },
|
|
||||||
{ mimetype: 'image/jxl', extension: 'jxl' },
|
|
||||||
{ mimetype: 'image/png', extension: 'png' },
|
|
||||||
{ mimetype: 'image/tiff', extension: 'tiff' },
|
|
||||||
{ mimetype: 'image/webp', extension: 'webp' },
|
|
||||||
{ mimetype: 'image/x-adobe-dng', extension: 'dng' },
|
|
||||||
{ mimetype: 'image/x-arriflex-ari', extension: 'ari' },
|
|
||||||
{ mimetype: 'image/x-canon-cr2', extension: 'cr2' },
|
|
||||||
{ mimetype: 'image/x-canon-cr3', extension: 'cr3' },
|
|
||||||
{ mimetype: 'image/x-canon-crw', extension: 'crw' },
|
|
||||||
{ mimetype: 'image/x-epson-erf', extension: 'erf' },
|
|
||||||
{ mimetype: 'image/x-fuji-raf', extension: 'raf' },
|
|
||||||
{ mimetype: 'image/x-hasselblad-3fr', extension: '3fr' },
|
|
||||||
{ mimetype: 'image/x-hasselblad-fff', extension: 'fff' },
|
|
||||||
{ mimetype: 'image/x-kodak-dcr', extension: 'dcr' },
|
|
||||||
{ mimetype: 'image/x-kodak-k25', extension: 'k25' },
|
|
||||||
{ mimetype: 'image/x-kodak-kdc', extension: 'kdc' },
|
|
||||||
{ mimetype: 'image/x-leica-rwl', extension: 'rwl' },
|
|
||||||
{ mimetype: 'image/x-minolta-mrw', extension: 'mrw' },
|
|
||||||
{ mimetype: 'image/x-nikon-nef', extension: 'nef' },
|
|
||||||
{ mimetype: 'image/x-olympus-orf', extension: 'orf' },
|
|
||||||
{ mimetype: 'image/x-olympus-ori', extension: 'ori' },
|
|
||||||
{ mimetype: 'image/x-panasonic-raw', extension: 'raw' },
|
|
||||||
{ mimetype: 'image/x-pentax-pef', extension: 'pef' },
|
|
||||||
{ mimetype: 'image/x-phantom-cin', extension: 'cin' },
|
|
||||||
{ mimetype: 'image/x-phaseone-cap', extension: 'cap' },
|
|
||||||
{ mimetype: 'image/x-phaseone-iiq', extension: 'iiq' },
|
|
||||||
{ mimetype: 'image/x-samsung-srw', extension: 'srw' },
|
|
||||||
{ mimetype: 'image/x-sigma-x3f', extension: 'x3f' },
|
|
||||||
{ mimetype: 'image/x-sony-arw', extension: 'arw' },
|
|
||||||
{ mimetype: 'image/x-sony-sr2', extension: 'sr2' },
|
|
||||||
{ mimetype: 'image/x-sony-srf', extension: 'srf' },
|
|
||||||
{ mimetype: 'video/3gpp', extension: '3gp' },
|
|
||||||
{ mimetype: 'video/avi', extension: 'avi' },
|
|
||||||
{ mimetype: 'video/mp2t', extension: 'm2ts' },
|
|
||||||
{ mimetype: 'video/mp2t', extension: 'mts' },
|
|
||||||
{ mimetype: 'video/mp4', extension: 'mp4' },
|
|
||||||
{ mimetype: 'video/mpeg', extension: 'mpg' },
|
|
||||||
{ mimetype: 'video/quicktime', extension: 'mov' },
|
|
||||||
{ mimetype: 'video/webm', extension: 'webm' },
|
|
||||||
{ mimetype: 'video/x-flv', extension: 'flv' },
|
|
||||||
{ mimetype: 'video/x-matroska', extension: 'mkv' },
|
|
||||||
{ mimetype: 'video/x-ms-wmv', extension: 'wmv' },
|
|
||||||
]) {
|
|
||||||
it(`returns the mime type for ${extension}`, () => {
|
|
||||||
expect(getFileMimeType({ name: `filename.${extension}` } as File)).toEqual(mimetype);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
it('returns the mime type from the file', () => {
|
|
||||||
[
|
|
||||||
{
|
|
||||||
file: {
|
|
||||||
name: 'filename.jpg',
|
|
||||||
type: 'image/jpeg',
|
|
||||||
},
|
|
||||||
result: 'image/jpeg',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
file: {
|
|
||||||
name: 'filename.txt',
|
|
||||||
type: 'text/plain',
|
|
||||||
},
|
|
||||||
result: 'text/plain',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
file: {
|
|
||||||
name: 'filename.txt',
|
|
||||||
type: '',
|
|
||||||
},
|
|
||||||
result: '',
|
|
||||||
},
|
|
||||||
].forEach(({ file, result }) => {
|
|
||||||
expect(getFileMimeType(file as File)).toEqual(result);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -136,66 +136,6 @@ export function getAssetFilename(asset: AssetResponseDto): string {
|
||||||
return `${asset.originalFileName}.${fileExtension}`;
|
return `${asset.originalFileName}.${fileExtension}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the MIME type of the file and an empty string when not found.
|
|
||||||
*/
|
|
||||||
export function getFileMimeType(file: File): string {
|
|
||||||
const mimeTypes: Record<string, string> = {
|
|
||||||
'3fr': 'image/x-hasselblad-3fr',
|
|
||||||
'3gp': 'video/3gpp',
|
|
||||||
ari: 'image/x-arriflex-ari',
|
|
||||||
arw: 'image/x-sony-arw',
|
|
||||||
avi: 'video/avi',
|
|
||||||
avif: 'image/avif',
|
|
||||||
cap: 'image/x-phaseone-cap',
|
|
||||||
cin: 'image/x-phantom-cin',
|
|
||||||
cr2: 'image/x-canon-cr2',
|
|
||||||
cr3: 'image/x-canon-cr3',
|
|
||||||
crw: 'image/x-canon-crw',
|
|
||||||
dcr: 'image/x-kodak-dcr',
|
|
||||||
dng: 'image/x-adobe-dng',
|
|
||||||
erf: 'image/x-epson-erf',
|
|
||||||
fff: 'image/x-hasselblad-fff',
|
|
||||||
flv: 'video/x-flv',
|
|
||||||
gif: 'image/gif',
|
|
||||||
heic: 'image/heic',
|
|
||||||
heif: 'image/heif',
|
|
||||||
iiq: 'image/x-phaseone-iiq',
|
|
||||||
insp: 'image/jpeg',
|
|
||||||
insv: 'video/mp4',
|
|
||||||
jpeg: 'image/jpeg',
|
|
||||||
jpg: 'image/jpeg',
|
|
||||||
jxl: 'image/jxl',
|
|
||||||
k25: 'image/x-kodak-k25',
|
|
||||||
kdc: 'image/x-kodak-kdc',
|
|
||||||
m2ts: 'video/mp2t',
|
|
||||||
mkv: 'video/x-matroska',
|
|
||||||
mov: 'video/quicktime',
|
|
||||||
mp4: 'video/mp4',
|
|
||||||
mpg: 'video/mpeg',
|
|
||||||
mrw: 'image/x-minolta-mrw',
|
|
||||||
mts: 'video/mp2t',
|
|
||||||
nef: 'image/x-nikon-nef',
|
|
||||||
orf: 'image/x-olympus-orf',
|
|
||||||
ori: 'image/x-olympus-ori',
|
|
||||||
pef: 'image/x-pentax-pef',
|
|
||||||
png: 'image/png',
|
|
||||||
raf: 'image/x-fuji-raf',
|
|
||||||
raw: 'image/x-panasonic-raw',
|
|
||||||
rwl: 'image/x-leica-rwl',
|
|
||||||
sr2: 'image/x-sony-sr2',
|
|
||||||
srf: 'image/x-sony-srf',
|
|
||||||
srw: 'image/x-samsung-srw',
|
|
||||||
tiff: 'image/tiff',
|
|
||||||
webm: 'video/webm',
|
|
||||||
webp: 'image/webp',
|
|
||||||
wmv: 'video/x-ms-wmv',
|
|
||||||
x3f: 'image/x-sigma-x3f',
|
|
||||||
};
|
|
||||||
// Return the MIME type determined by the browser or the MIME type based on the file extension.
|
|
||||||
return file.type || (mimeTypes[getFilenameExtension(file.name)] ?? '');
|
|
||||||
}
|
|
||||||
|
|
||||||
function isRotated90CW(orientation: number) {
|
function isRotated90CW(orientation: number) {
|
||||||
return orientation == 6 || orientation == 90;
|
return orientation == 6 || orientation == 90;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,59 @@
|
||||||
import { uploadAssetsStore } from '$lib/stores/upload';
|
import { uploadAssetsStore } from '$lib/stores/upload';
|
||||||
import { addAssetsToAlbum, getFileMimeType, getFilenameExtension } from '$lib/utils/asset-utils';
|
import { addAssetsToAlbum, getFilenameExtension } from '$lib/utils/asset-utils';
|
||||||
import type { AssetFileUploadResponseDto } from '@api';
|
import type { AssetFileUploadResponseDto } from '@api';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
import { combineLatestAll, filter, firstValueFrom, from, mergeMap, of } from 'rxjs';
|
import { combineLatestAll, filter, firstValueFrom, from, mergeMap, of } from 'rxjs';
|
||||||
import type { UploadAsset } from '../models/upload-asset';
|
|
||||||
import { notificationController, NotificationType } from './../components/shared-components/notification/notification';
|
import { notificationController, NotificationType } from './../components/shared-components/notification/notification';
|
||||||
|
|
||||||
|
const extensions = [
|
||||||
|
'.3fr',
|
||||||
|
'.3gp',
|
||||||
|
'.ari',
|
||||||
|
'.arw',
|
||||||
|
'.avi',
|
||||||
|
'.avif',
|
||||||
|
'.cap',
|
||||||
|
'.cin',
|
||||||
|
'.cr2',
|
||||||
|
'.cr3',
|
||||||
|
'.crw',
|
||||||
|
'.dcr',
|
||||||
|
'.dng',
|
||||||
|
'.erf',
|
||||||
|
'.fff',
|
||||||
|
'.flv',
|
||||||
|
'.gif',
|
||||||
|
'.heic',
|
||||||
|
'.heif',
|
||||||
|
'.iiq',
|
||||||
|
'.jpeg',
|
||||||
|
'.jpg',
|
||||||
|
'.k25',
|
||||||
|
'.kdc',
|
||||||
|
'.mkv',
|
||||||
|
'.mov',
|
||||||
|
'.mp2t',
|
||||||
|
'.mp4',
|
||||||
|
'.mpeg',
|
||||||
|
'.mrw',
|
||||||
|
'.nef',
|
||||||
|
'.orf',
|
||||||
|
'.ori',
|
||||||
|
'.pef',
|
||||||
|
'.png',
|
||||||
|
'.raf',
|
||||||
|
'.raw',
|
||||||
|
'.rwl',
|
||||||
|
'.sr2',
|
||||||
|
'.srf',
|
||||||
|
'.srw',
|
||||||
|
'.tiff',
|
||||||
|
'.webm',
|
||||||
|
'.webp',
|
||||||
|
'.wmv',
|
||||||
|
'.x3f',
|
||||||
|
];
|
||||||
|
|
||||||
export const openFileUploadDialog = async (
|
export const openFileUploadDialog = async (
|
||||||
albumId: string | undefined = undefined,
|
albumId: string | undefined = undefined,
|
||||||
sharedKey: string | undefined = undefined,
|
sharedKey: string | undefined = undefined,
|
||||||
|
@ -16,52 +64,7 @@ export const openFileUploadDialog = async (
|
||||||
|
|
||||||
fileSelector.type = 'file';
|
fileSelector.type = 'file';
|
||||||
fileSelector.multiple = true;
|
fileSelector.multiple = true;
|
||||||
|
fileSelector.accept = extensions.join(',');
|
||||||
// When adding a content type that is unsupported by browsers, make sure
|
|
||||||
// to also add it to getFileMimeType() otherwise the upload will fail.
|
|
||||||
fileSelector.accept = [
|
|
||||||
'image/*',
|
|
||||||
'video/*',
|
|
||||||
'.3fr',
|
|
||||||
'.3gp',
|
|
||||||
'.ari',
|
|
||||||
'.arw',
|
|
||||||
'.avif',
|
|
||||||
'.cap',
|
|
||||||
'.cin',
|
|
||||||
'.cr2',
|
|
||||||
'.cr3',
|
|
||||||
'.crw',
|
|
||||||
'.dcr',
|
|
||||||
'.dng',
|
|
||||||
'.erf',
|
|
||||||
'.fff',
|
|
||||||
'.heic',
|
|
||||||
'.heif',
|
|
||||||
'.iiq',
|
|
||||||
'.insp',
|
|
||||||
'.insv',
|
|
||||||
'.jxl',
|
|
||||||
'.k25',
|
|
||||||
'.kdc',
|
|
||||||
'.m2ts',
|
|
||||||
'.mov',
|
|
||||||
'.mrw',
|
|
||||||
'.mts',
|
|
||||||
'.nef',
|
|
||||||
'.orf',
|
|
||||||
'.ori',
|
|
||||||
'.pef',
|
|
||||||
'.raf',
|
|
||||||
'.raf',
|
|
||||||
'.raw',
|
|
||||||
'.rwl',
|
|
||||||
'.sr2',
|
|
||||||
'.srf',
|
|
||||||
'.srw',
|
|
||||||
'.x3f',
|
|
||||||
].join(',');
|
|
||||||
|
|
||||||
fileSelector.onchange = async (e: Event) => {
|
fileSelector.onchange = async (e: Event) => {
|
||||||
const target = e.target as HTMLInputElement;
|
const target = e.target as HTMLInputElement;
|
||||||
if (!target.files) {
|
if (!target.files) {
|
||||||
|
@ -87,10 +90,7 @@ export const fileUploadHandler = async (
|
||||||
) => {
|
) => {
|
||||||
return firstValueFrom(
|
return firstValueFrom(
|
||||||
from(files).pipe(
|
from(files).pipe(
|
||||||
filter((file) => {
|
filter((file) => extensions.includes('.' + getFilenameExtension(file.name))),
|
||||||
const assetType = getFileMimeType(file).split('/')[0];
|
|
||||||
return assetType === 'video' || assetType === 'image';
|
|
||||||
}),
|
|
||||||
mergeMap(async (file) => of(await fileUploader(file, albumId, sharedKey)), 2),
|
mergeMap(async (file) => of(await fileUploader(file, albumId, sharedKey)), 2),
|
||||||
combineLatestAll(),
|
combineLatestAll(),
|
||||||
),
|
),
|
||||||
|
@ -103,51 +103,24 @@ async function fileUploader(
|
||||||
albumId: string | undefined = undefined,
|
albumId: string | undefined = undefined,
|
||||||
sharedKey: string | undefined = undefined,
|
sharedKey: string | undefined = undefined,
|
||||||
): Promise<string | undefined> {
|
): Promise<string | undefined> {
|
||||||
const mimeType = getFileMimeType(asset);
|
|
||||||
const assetType = mimeType.split('/')[0].toUpperCase();
|
|
||||||
const fileExtension = getFilenameExtension(asset.name);
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
const fileCreatedAt = new Date(asset.lastModified).toISOString();
|
const fileCreatedAt = new Date(asset.lastModified).toISOString();
|
||||||
const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified;
|
const deviceAssetId = 'web' + '-' + asset.name + '-' + asset.lastModified;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Create and add pseudo-unique ID of asset on the device
|
|
||||||
formData.append('deviceAssetId', deviceAssetId);
|
formData.append('deviceAssetId', deviceAssetId);
|
||||||
|
|
||||||
// Get device id - for web -> use WEB
|
|
||||||
formData.append('deviceId', 'WEB');
|
formData.append('deviceId', 'WEB');
|
||||||
|
|
||||||
// Get asset type
|
|
||||||
formData.append('assetType', assetType);
|
|
||||||
|
|
||||||
// Get Asset Created Date
|
|
||||||
formData.append('fileCreatedAt', fileCreatedAt);
|
formData.append('fileCreatedAt', fileCreatedAt);
|
||||||
|
|
||||||
// Get Asset Modified At
|
|
||||||
formData.append('fileModifiedAt', new Date(asset.lastModified).toISOString());
|
formData.append('fileModifiedAt', new Date(asset.lastModified).toISOString());
|
||||||
|
|
||||||
// Set Asset is Favorite to false
|
|
||||||
formData.append('isFavorite', 'false');
|
formData.append('isFavorite', 'false');
|
||||||
|
|
||||||
// Get asset duration
|
|
||||||
formData.append('duration', '0:00:00.000000');
|
formData.append('duration', '0:00:00.000000');
|
||||||
|
formData.append('assetData', new File([asset], asset.name));
|
||||||
|
|
||||||
// Get asset file extension
|
uploadAssetsStore.addNewUploadAsset({
|
||||||
formData.append('fileExtension', '.' + fileExtension);
|
|
||||||
|
|
||||||
// Get asset binary data with a custom MIME type, because browsers will
|
|
||||||
// use application/octet-stream for unsupported MIME types, leading to
|
|
||||||
// failed uploads.
|
|
||||||
formData.append('assetData', new File([asset], asset.name, { type: mimeType }));
|
|
||||||
|
|
||||||
const newUploadAsset: UploadAsset = {
|
|
||||||
id: deviceAssetId,
|
id: deviceAssetId,
|
||||||
file: asset,
|
file: asset,
|
||||||
progress: 0,
|
progress: 0,
|
||||||
fileExtension: fileExtension,
|
});
|
||||||
};
|
|
||||||
|
|
||||||
uploadAssetsStore.addNewUploadAsset(newUploadAsset);
|
|
||||||
|
|
||||||
const response = await axios.post(`/api/asset/upload`, formData, {
|
const response = await axios.post(`/api/asset/upload`, formData, {
|
||||||
params: {
|
params: {
|
||||||
|
|
Loading…
Add table
Reference in a new issue