This commit is contained in:
mertalev
2025-10-06 23:32:20 -04:00
parent de117ebe7a
commit e3e8da168f
15 changed files with 317 additions and 468 deletions
+54 -60
View File
@@ -76,16 +76,8 @@ class UploadApi {
}
}
/// This endpoint requires the `asset.upload` permission.
///
/// Note: This method returns the HTTP [Response].
///
/// Parameters:
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> getUploadOptionsWithHttpInfo({ String? key, String? slug, }) async {
/// Performs an HTTP 'OPTIONS /upload' operation and returns the [Response].
Future<Response> getUploadOptionsWithHttpInfo() async {
// ignore: prefer_const_declarations
final apiPath = r'/upload';
@@ -96,13 +88,6 @@ class UploadApi {
final headerParams = <String, String>{};
final formParams = <String, String>{};
if (key != null) {
queryParams.addAll(_queryParams('', 'key', key));
}
if (slug != null) {
queryParams.addAll(_queryParams('', 'slug', slug));
}
const contentTypes = <String>[];
@@ -117,15 +102,8 @@ class UploadApi {
);
}
/// This endpoint requires the `asset.upload` permission.
///
/// Parameters:
///
/// * [String] key:
///
/// * [String] slug:
Future<void> getUploadOptions({ String? key, String? slug, }) async {
final response = await getUploadOptionsWithHttpInfo( key: key, slug: slug, );
Future<void> getUploadOptions() async {
final response = await getUploadOptionsWithHttpInfo();
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -137,15 +115,15 @@ class UploadApi {
///
/// Parameters:
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] id (required):
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> getUploadStatusWithHttpInfo(String draftUploadInteropVersion, String id, { String? key, String? slug, }) async {
Future<Response> getUploadStatusWithHttpInfo(String id, String uploadDraftInteropVersion, { String? key, String? slug, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/upload/{id}'
.replaceAll('{id}', id);
@@ -164,7 +142,7 @@ class UploadApi {
queryParams.addAll(_queryParams('', 'slug', slug));
}
headerParams[r'draft-upload-interop-version'] = parameterToString(draftUploadInteropVersion);
headerParams[r'upload-draft-interop-version'] = parameterToString(uploadDraftInteropVersion);
const contentTypes = <String>[];
@@ -184,16 +162,16 @@ class UploadApi {
///
/// Parameters:
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] id (required):
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] key:
///
/// * [String] slug:
Future<void> getUploadStatus(String draftUploadInteropVersion, String id, { String? key, String? slug, }) async {
final response = await getUploadStatusWithHttpInfo(draftUploadInteropVersion, id, key: key, slug: slug, );
Future<void> getUploadStatus(String id, String uploadDraftInteropVersion, { String? key, String? slug, }) async {
final response = await getUploadStatusWithHttpInfo(id, uploadDraftInteropVersion, key: key, slug: slug, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
@@ -208,21 +186,21 @@ class UploadApi {
/// * [String] contentLength (required):
/// Non-negative size of the request body in bytes.
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] id (required):
///
/// * [String] uploadComplete (required):
/// Structured boolean indicating whether this request completes the file. Use Upload-Incomplete instead for version <= 3.
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] uploadOffset (required):
/// Non-negative byte offset indicating the starting position of the data in the request body within the entire file.
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> resumeUploadWithHttpInfo(String contentLength, String draftUploadInteropVersion, String id, String uploadComplete, String uploadOffset, { String? key, String? slug, }) async {
Future<Response> resumeUploadWithHttpInfo(String contentLength, String id, String uploadComplete, String uploadDraftInteropVersion, String uploadOffset, { String? key, String? slug, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/upload/{id}'
.replaceAll('{id}', id);
@@ -242,8 +220,8 @@ class UploadApi {
}
headerParams[r'content-length'] = parameterToString(contentLength);
headerParams[r'draft-upload-interop-version'] = parameterToString(draftUploadInteropVersion);
headerParams[r'upload-complete'] = parameterToString(uploadComplete);
headerParams[r'upload-draft-interop-version'] = parameterToString(uploadDraftInteropVersion);
headerParams[r'upload-offset'] = parameterToString(uploadOffset);
const contentTypes = <String>[];
@@ -267,25 +245,33 @@ class UploadApi {
/// * [String] contentLength (required):
/// Non-negative size of the request body in bytes.
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] id (required):
///
/// * [String] uploadComplete (required):
/// Structured boolean indicating whether this request completes the file. Use Upload-Incomplete instead for version <= 3.
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] uploadOffset (required):
/// Non-negative byte offset indicating the starting position of the data in the request body within the entire file.
///
/// * [String] key:
///
/// * [String] slug:
Future<void> resumeUpload(String contentLength, String draftUploadInteropVersion, String id, String uploadComplete, String uploadOffset, { String? key, String? slug, }) async {
final response = await resumeUploadWithHttpInfo(contentLength, draftUploadInteropVersion, id, uploadComplete, uploadOffset, key: key, slug: slug, );
Future<Object?> resumeUpload(String contentLength, String id, String uploadComplete, String uploadDraftInteropVersion, String uploadOffset, { String? key, String? slug, }) async {
final response = await resumeUploadWithHttpInfo(contentLength, id, uploadComplete, uploadDraftInteropVersion, uploadOffset, key: key, slug: slug, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Object',) as Object;
}
return null;
}
/// This endpoint requires the `asset.upload` permission.
@@ -297,22 +283,22 @@ class UploadApi {
/// * [String] contentLength (required):
/// Non-negative size of the request body in bytes.
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] reprDigest (required):
/// Structured dictionary containing an SHA-1 checksum used to detect duplicate files and validate data integrity.
/// RFC 9651 structured dictionary containing an `sha` (bytesequence) checksum used to detect duplicate files and validate data integrity.
///
/// * [String] uploadComplete (required):
/// Structured boolean indicating whether this request completes the file. Use Upload-Incomplete instead for version <= 3.
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] xImmichAssetData (required):
/// Base64-encoded JSON of asset metadata. The expected content is the same as AssetMediaCreateDto, except that `filename` is required and `sidecarData` is ignored.
/// RFC 9651 structured dictionary containing asset metadata with the following keys: - device-asset-id (string, required): Unique device asset identifier - device-id (string, required): Device identifier - file-created-at (string/date, required): ISO 8601 date string or Unix timestamp - file-modified-at (string/date, required): ISO 8601 date string or Unix timestamp - filename (string, required): Original filename - is-favorite (boolean, optional): Favorite status - icloud-id (string, optional): iCloud identifier for assets from iOS devices
///
/// * [String] key:
///
/// * [String] slug:
Future<Response> startUploadWithHttpInfo(String contentLength, String draftUploadInteropVersion, String reprDigest, String uploadComplete, String xImmichAssetData, { String? key, String? slug, }) async {
Future<Response> startUploadWithHttpInfo(String contentLength, String reprDigest, String uploadComplete, String uploadDraftInteropVersion, String xImmichAssetData, { String? key, String? slug, }) async {
// ignore: prefer_const_declarations
final apiPath = r'/upload';
@@ -331,9 +317,9 @@ class UploadApi {
}
headerParams[r'content-length'] = parameterToString(contentLength);
headerParams[r'draft-upload-interop-version'] = parameterToString(draftUploadInteropVersion);
headerParams[r'repr-digest'] = parameterToString(reprDigest);
headerParams[r'upload-complete'] = parameterToString(uploadComplete);
headerParams[r'upload-draft-interop-version'] = parameterToString(uploadDraftInteropVersion);
headerParams[r'x-immich-asset-data'] = parameterToString(xImmichAssetData);
const contentTypes = <String>[];
@@ -357,25 +343,33 @@ class UploadApi {
/// * [String] contentLength (required):
/// Non-negative size of the request body in bytes.
///
/// * [String] draftUploadInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] reprDigest (required):
/// Structured dictionary containing an SHA-1 checksum used to detect duplicate files and validate data integrity.
/// RFC 9651 structured dictionary containing an `sha` (bytesequence) checksum used to detect duplicate files and validate data integrity.
///
/// * [String] uploadComplete (required):
/// Structured boolean indicating whether this request completes the file. Use Upload-Incomplete instead for version <= 3.
///
/// * [String] uploadDraftInteropVersion (required):
/// Indicates the version of the RUFH protocol supported by the client.
///
/// * [String] xImmichAssetData (required):
/// Base64-encoded JSON of asset metadata. The expected content is the same as AssetMediaCreateDto, except that `filename` is required and `sidecarData` is ignored.
/// RFC 9651 structured dictionary containing asset metadata with the following keys: - device-asset-id (string, required): Unique device asset identifier - device-id (string, required): Device identifier - file-created-at (string/date, required): ISO 8601 date string or Unix timestamp - file-modified-at (string/date, required): ISO 8601 date string or Unix timestamp - filename (string, required): Original filename - is-favorite (boolean, optional): Favorite status - icloud-id (string, optional): iCloud identifier for assets from iOS devices
///
/// * [String] key:
///
/// * [String] slug:
Future<void> startUpload(String contentLength, String draftUploadInteropVersion, String reprDigest, String uploadComplete, String xImmichAssetData, { String? key, String? slug, }) async {
final response = await startUploadWithHttpInfo(contentLength, draftUploadInteropVersion, reprDigest, uploadComplete, xImmichAssetData, key: key, slug: slug, );
Future<Object?> startUpload(String contentLength, String reprDigest, String uploadComplete, String uploadDraftInteropVersion, String xImmichAssetData, { String? key, String? slug, }) async {
final response = await startUploadWithHttpInfo(contentLength, reprDigest, uploadComplete, uploadDraftInteropVersion, xImmichAssetData, key: key, slug: slug, );
if (response.statusCode >= HttpStatus.badRequest) {
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
}
// When a remote server returns no body with a status of 204, we shall not decode it.
// At the time of writing this, `dart:convert` will throw an "Unexpected end of input"
// FormatException when trying to decode an empty string.
if (response.body.isNotEmpty && response.statusCode != HttpStatus.noContent) {
return await apiClient.deserializeAsync(await _decodeBodyBytes(response), 'Object',) as Object;
}
return null;
}
}
-207
View File
@@ -1,207 +0,0 @@
enum BackupSelection {
// Used to sort albums based on the backupSelection
// selected -> none -> excluded
// Do not change the order of these values
selected,
none,
excluded,
}
class LocalAlbum {
final String id;
final String name;
final DateTime updatedAt;
final bool isIosSharedAlbum;
final int assetCount;
final BackupSelection backupSelection;
final String? linkedRemoteAlbumId;
const LocalAlbum({
required this.id,
required this.name,
required this.updatedAt,
this.assetCount = 0,
this.backupSelection = BackupSelection.none,
this.isIosSharedAlbum = false,
this.linkedRemoteAlbumId,
});
LocalAlbum copyWith({
String? id,
String? name,
DateTime? updatedAt,
int? assetCount,
BackupSelection? backupSelection,
bool? isIosSharedAlbum,
String? linkedRemoteAlbumId,
}) {
return LocalAlbum(
id: id ?? this.id,
name: name ?? this.name,
updatedAt: updatedAt ?? this.updatedAt,
assetCount: assetCount ?? this.assetCount,
backupSelection: backupSelection ?? this.backupSelection,
isIosSharedAlbum: isIosSharedAlbum ?? this.isIosSharedAlbum,
linkedRemoteAlbumId: linkedRemoteAlbumId ?? this.linkedRemoteAlbumId,
);
}
@override
bool operator ==(Object other) {
if (other is! LocalAlbum) return false;
if (identical(this, other)) return true;
return other.id == id &&
other.name == name &&
other.updatedAt == updatedAt &&
other.assetCount == assetCount &&
other.backupSelection == backupSelection &&
other.isIosSharedAlbum == isIosSharedAlbum &&
other.linkedRemoteAlbumId == linkedRemoteAlbumId;
}
@override
int get hashCode {
return id.hashCode ^
name.hashCode ^
updatedAt.hashCode ^
assetCount.hashCode ^
backupSelection.hashCode ^
isIosSharedAlbum.hashCode ^
linkedRemoteAlbumId.hashCode;
}
@override
String toString() {
return '''LocalAlbum: {
id: $id,
name: $name,
updatedAt: $updatedAt,
assetCount: $assetCount,
backupSelection: $backupSelection,
isIosSharedAlbum: $isIosSharedAlbum
linkedRemoteAlbumId: $linkedRemoteAlbumId,
}''';
}
}
int square(int num) {
return num * num;
}
@pragma('vm:never-inline')
List<LocalAlbum> getAlbums() {
final updatedAt = DateTime.now();
final selection = BackupSelection.values;
return List.generate(100000, (i) {
return LocalAlbum(id: i.toString(), name: '', updatedAt: updatedAt, backupSelection: selection[i % 3]);
});
}
@pragma('vm:never-inline')
List<LocalAlbum> setAlbum1(List<LocalAlbum> albums, LocalAlbum album) {
final newAlbums = List.filled(albums.length, LocalAlbum(id: '', name: '', updatedAt: DateTime.now()));
newAlbums.setAll(0, albums);
for (int i = 0; i < newAlbums.length; i++) {
final currentAlbum = newAlbums[i];
if (currentAlbum.id == album.id) {
newAlbums[i] = currentAlbum.copyWith(backupSelection: BackupSelection.selected);
break;
}
}
return newAlbums;
}
@pragma('vm:never-inline')
List<LocalAlbum> setAlbum2(List<LocalAlbum> albums, LocalAlbum album) {
final newAlbums = List.filled(albums.length, LocalAlbum(id: '', name: '', updatedAt: DateTime.now()));
for (int i = 0; i < newAlbums.length; i++) {
final currentAlbum = newAlbums[i];
newAlbums[i] = currentAlbum.id == album.id ? currentAlbum.copyWith(backupSelection: BackupSelection.selected) : currentAlbum;
}
return newAlbums;
}
@pragma('vm:never-inline')
List<LocalAlbum> setAlbum3(List<LocalAlbum> albums, LocalAlbum album) {
final newAlbums = albums.toList(growable: false);
for (int i = 0; i < newAlbums.length; i++) {
final currentAlbum = newAlbums[i];
if (currentAlbum.id == album.id) {
newAlbums[i] = currentAlbum.copyWith(backupSelection: BackupSelection.selected);
break;
}
}
return newAlbums;
}
@pragma('vm:never-inline')
Set<String> toSet1(List<LocalAlbum> albums) {
return albums.map((album) => album.id).toSet();
}
@pragma('vm:never-inline')
Set<String> toSet2(List<LocalAlbum> albums) {
final ids = <String>{};
for (final album in albums) {
ids.add(album.id);
}
return ids;
}
@pragma('vm:never-inline')
Set<String> toSet3(List<LocalAlbum> albums) {
return Set.unmodifiable(albums.map((album) => album.id));
}
@pragma('vm:never-inline')
Set<String> toSet4(List<LocalAlbum> albums) {
final ids = <String>{};
for (int i = 0; i < albums.length; i++) {
final id = albums[i].id;
ids.add(id);
}
return ids;
}
@pragma('vm:never-inline')
List<LocalAlbum> toFiltered1(List<LocalAlbum> albums, BackupSelection selection) {
return albums.where((album) => album.backupSelection == selection).toList(growable: false);
}
@pragma('vm:never-inline')
List<LocalAlbum> toFiltered2(List<LocalAlbum> albums, BackupSelection selection) {
final filtered = <LocalAlbum>[];
for (final album in albums) {
if (album.backupSelection == selection) {
filtered.add(album);
}
}
return filtered;
}
@pragma('vm:never-inline')
List<LocalAlbum> toFiltered3(List<LocalAlbum> albums, BackupSelection selection) {
final filtered = <LocalAlbum>[];
for (int i = 0; i < albums.length; i++) {
final album = albums[i];
if (album.backupSelection == selection) {
filtered.add(album);
}
}
return filtered;
}
late Set<String> ids;
late List<LocalAlbum> localAlbums;
void main(List<String> args) {
final albums = getAlbums();
// final album = LocalAlbum(id: '50000', name: '', updatedAt: DateTime.now());
final stopwatch = Stopwatch()..start();
// localAlbums = setAlbum3(albums, album);
// ids = toSet1(albums);
localAlbums = toFiltered2(albums, BackupSelection.selected);
stopwatch.stop();
print('Elapsed time: ${(stopwatch.elapsedMicroseconds / 1000).toStringAsFixed(2)}ms');
}