Merge 517beaf2e6 into 2afde23a5d
commit
b15be5b5b0
10
i18n/en.json
10
i18n/en.json
|
|
@ -565,6 +565,9 @@
|
|||
"are_these_the_same_person": "Are these the same person?",
|
||||
"are_you_sure_to_do_this": "Are you sure you want to do this?",
|
||||
"array_field_not_fully_supported": "Array fields require manual JSON editing",
|
||||
"aspect_ratio": "Aspect ratio",
|
||||
"aspect_ratio_height": "Aspect ratio height",
|
||||
"aspect_ratio_width": "Aspect ratio width",
|
||||
"asset_action_delete_err_read_only": "Cannot delete read only asset(s), skipping",
|
||||
"asset_action_share_err_offline": "Cannot fetch offline asset(s), skipping",
|
||||
"asset_added_to_album": "Added to album",
|
||||
|
|
@ -1334,6 +1337,7 @@
|
|||
"image_alt_text_date_place_2_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1} and {person2} on {date}",
|
||||
"image_alt_text_date_place_3_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1}, {person2}, and {person3} on {date}",
|
||||
"image_alt_text_date_place_4_or_more_people": "{isVideo, select, true {Video} other {Image}} taken in {city}, {country} with {person1}, {person2}, and {additionalCount, number} others on {date}",
|
||||
"image_properties": "Image properties",
|
||||
"image_saved_successfully": "Image saved",
|
||||
"image_viewer_page_state_provider_download_started": "Download Started",
|
||||
"image_viewer_page_state_provider_download_success": "Download Success",
|
||||
|
|
@ -1592,7 +1596,13 @@
|
|||
"merge_people_prompt": "Do you want to merge these people? This action is irreversible.",
|
||||
"merge_people_successfully": "Merge people successfully",
|
||||
"merged_people_count": "Merged {count, plural, one {# person} other {# people}}",
|
||||
"max_aspect_ratio": "Max aspect ratio",
|
||||
"max_height": "Max height",
|
||||
"max_width": "Max width",
|
||||
"minimize": "Minimize",
|
||||
"min_aspect_ratio": "Min aspect ratio",
|
||||
"min_height": "Min height",
|
||||
"min_width": "Min width",
|
||||
"minute": "Minute",
|
||||
"minutes": "Minutes",
|
||||
"mirror_horizontal": "Horizontal",
|
||||
|
|
|
|||
|
|
@ -397,9 +397,27 @@ class SearchApi {
|
|||
/// * [String] make:
|
||||
/// Filter by camera make
|
||||
///
|
||||
/// * [num] maxAspectRatio:
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// * [int] maxHeight:
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// * [int] maxWidth:
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// * [num] minAspectRatio:
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// * [int] minFileSize:
|
||||
/// Minimum file size in bytes
|
||||
///
|
||||
/// * [int] minHeight:
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// * [int] minWidth:
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// * [String] model:
|
||||
/// Filter by camera model
|
||||
///
|
||||
|
|
@ -448,7 +466,7 @@ class SearchApi {
|
|||
///
|
||||
/// * [bool] withExif:
|
||||
/// Include EXIF data in response
|
||||
Future<Response> searchLargeAssetsWithHttpInfo({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, String? ocr, List<String>? personIds, int? rating, int? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, Future<void>? abortTrigger, }) async {
|
||||
Future<Response> searchLargeAssetsWithHttpInfo({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, num? maxAspectRatio, int? maxHeight, int? maxWidth, num? minAspectRatio, int? minFileSize, int? minHeight, int? minWidth, String? model, String? ocr, List<String>? personIds, int? rating, int? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, Future<void>? abortTrigger, }) async {
|
||||
// ignore: prefer_const_declarations
|
||||
final apiPath = r'/search/large-assets';
|
||||
|
||||
|
|
@ -498,9 +516,27 @@ class SearchApi {
|
|||
if (make != null) {
|
||||
queryParams.addAll(_queryParams('', 'make', make));
|
||||
}
|
||||
if (maxAspectRatio != null) {
|
||||
queryParams.addAll(_queryParams('', 'maxAspectRatio', maxAspectRatio));
|
||||
}
|
||||
if (maxHeight != null) {
|
||||
queryParams.addAll(_queryParams('', 'maxHeight', maxHeight));
|
||||
}
|
||||
if (maxWidth != null) {
|
||||
queryParams.addAll(_queryParams('', 'maxWidth', maxWidth));
|
||||
}
|
||||
if (minAspectRatio != null) {
|
||||
queryParams.addAll(_queryParams('', 'minAspectRatio', minAspectRatio));
|
||||
}
|
||||
if (minFileSize != null) {
|
||||
queryParams.addAll(_queryParams('', 'minFileSize', minFileSize));
|
||||
}
|
||||
if (minHeight != null) {
|
||||
queryParams.addAll(_queryParams('', 'minHeight', minHeight));
|
||||
}
|
||||
if (minWidth != null) {
|
||||
queryParams.addAll(_queryParams('', 'minWidth', minWidth));
|
||||
}
|
||||
if (model != null) {
|
||||
queryParams.addAll(_queryParams('', 'model', model));
|
||||
}
|
||||
|
|
@ -613,9 +649,27 @@ class SearchApi {
|
|||
/// * [String] make:
|
||||
/// Filter by camera make
|
||||
///
|
||||
/// * [num] maxAspectRatio:
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// * [int] maxHeight:
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// * [int] maxWidth:
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// * [num] minAspectRatio:
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// * [int] minFileSize:
|
||||
/// Minimum file size in bytes
|
||||
///
|
||||
/// * [int] minHeight:
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// * [int] minWidth:
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// * [String] model:
|
||||
/// Filter by camera model
|
||||
///
|
||||
|
|
@ -664,8 +718,8 @@ class SearchApi {
|
|||
///
|
||||
/// * [bool] withExif:
|
||||
/// Include EXIF data in response
|
||||
Future<List<AssetResponseDto>?> searchLargeAssets({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, int? minFileSize, String? model, String? ocr, List<String>? personIds, int? rating, int? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, Future<void>? abortTrigger, }) async {
|
||||
final response = await searchLargeAssetsWithHttpInfo(albumIds: albumIds, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, isEncoded: isEncoded, isFavorite: isFavorite, isMotion: isMotion, isNotInAlbum: isNotInAlbum, isOffline: isOffline, lensModel: lensModel, libraryId: libraryId, make: make, minFileSize: minFileSize, model: model, ocr: ocr, personIds: personIds, rating: rating, size: size, state: state, tagIds: tagIds, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, visibility: visibility, withDeleted: withDeleted, withExif: withExif, abortTrigger: abortTrigger,);
|
||||
Future<List<AssetResponseDto>?> searchLargeAssets({ List<String>? albumIds, String? city, String? country, DateTime? createdAfter, DateTime? createdBefore, bool? isEncoded, bool? isFavorite, bool? isMotion, bool? isNotInAlbum, bool? isOffline, String? lensModel, String? libraryId, String? make, num? maxAspectRatio, int? maxHeight, int? maxWidth, num? minAspectRatio, int? minFileSize, int? minHeight, int? minWidth, String? model, String? ocr, List<String>? personIds, int? rating, int? size, String? state, List<String>? tagIds, DateTime? takenAfter, DateTime? takenBefore, DateTime? trashedAfter, DateTime? trashedBefore, AssetTypeEnum? type, DateTime? updatedAfter, DateTime? updatedBefore, AssetVisibility? visibility, bool? withDeleted, bool? withExif, Future<void>? abortTrigger, }) async {
|
||||
final response = await searchLargeAssetsWithHttpInfo(albumIds: albumIds, city: city, country: country, createdAfter: createdAfter, createdBefore: createdBefore, isEncoded: isEncoded, isFavorite: isFavorite, isMotion: isMotion, isNotInAlbum: isNotInAlbum, isOffline: isOffline, lensModel: lensModel, libraryId: libraryId, make: make, maxAspectRatio: maxAspectRatio, maxHeight: maxHeight, maxWidth: maxWidth, minAspectRatio: minAspectRatio, minFileSize: minFileSize, minHeight: minHeight, minWidth: minWidth, model: model, ocr: ocr, personIds: personIds, rating: rating, size: size, state: state, tagIds: tagIds, takenAfter: takenAfter, takenBefore: takenBefore, trashedAfter: trashedAfter, trashedBefore: trashedBefore, type: type, updatedAfter: updatedAfter, updatedBefore: updatedBefore, visibility: visibility, withDeleted: withDeleted, withExif: withExif, abortTrigger: abortTrigger,);
|
||||
if (response.statusCode >= HttpStatus.badRequest) {
|
||||
throw ApiException(response.statusCode, await _decodeBodyBytes(response));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,12 @@ class MetadataSearchDto {
|
|||
this.lensModel,
|
||||
this.libraryId,
|
||||
this.make,
|
||||
this.maxAspectRatio,
|
||||
this.maxHeight,
|
||||
this.maxWidth,
|
||||
this.minAspectRatio,
|
||||
this.minHeight,
|
||||
this.minWidth,
|
||||
this.model,
|
||||
this.ocr,
|
||||
this.order,
|
||||
|
|
@ -174,6 +180,76 @@ class MetadataSearchDto {
|
|||
/// Filter by camera make
|
||||
String? make;
|
||||
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? maxAspectRatio;
|
||||
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxHeight;
|
||||
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxWidth;
|
||||
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? minAspectRatio;
|
||||
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minHeight;
|
||||
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minWidth;
|
||||
|
||||
/// Filter by camera model
|
||||
String? model;
|
||||
|
||||
|
|
@ -394,6 +470,12 @@ class MetadataSearchDto {
|
|||
other.lensModel == lensModel &&
|
||||
other.libraryId == libraryId &&
|
||||
other.make == make &&
|
||||
other.maxAspectRatio == maxAspectRatio &&
|
||||
other.maxHeight == maxHeight &&
|
||||
other.maxWidth == maxWidth &&
|
||||
other.minAspectRatio == minAspectRatio &&
|
||||
other.minHeight == minHeight &&
|
||||
other.minWidth == minWidth &&
|
||||
other.model == model &&
|
||||
other.ocr == ocr &&
|
||||
other.order == order &&
|
||||
|
|
@ -440,6 +522,12 @@ class MetadataSearchDto {
|
|||
(lensModel == null ? 0 : lensModel!.hashCode) +
|
||||
(libraryId == null ? 0 : libraryId!.hashCode) +
|
||||
(make == null ? 0 : make!.hashCode) +
|
||||
(maxAspectRatio == null ? 0 : maxAspectRatio!.hashCode) +
|
||||
(maxHeight == null ? 0 : maxHeight!.hashCode) +
|
||||
(maxWidth == null ? 0 : maxWidth!.hashCode) +
|
||||
(minAspectRatio == null ? 0 : minAspectRatio!.hashCode) +
|
||||
(minHeight == null ? 0 : minHeight!.hashCode) +
|
||||
(minWidth == null ? 0 : minWidth!.hashCode) +
|
||||
(model == null ? 0 : model!.hashCode) +
|
||||
(ocr == null ? 0 : ocr!.hashCode) +
|
||||
(order == null ? 0 : order!.hashCode) +
|
||||
|
|
@ -467,7 +555,7 @@ class MetadataSearchDto {
|
|||
(withStacked == null ? 0 : withStacked!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'MetadataSearchDto[albumIds=$albumIds, checksum=$checksum, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, description=$description, encodedVideoPath=$encodedVideoPath, id=$id, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, ocr=$ocr, order=$order, originalFileName=$originalFileName, originalPath=$originalPath, page=$page, personIds=$personIds, previewPath=$previewPath, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, thumbnailPath=$thumbnailPath, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
|
||||
String toString() => 'MetadataSearchDto[albumIds=$albumIds, checksum=$checksum, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, description=$description, encodedVideoPath=$encodedVideoPath, id=$id, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, maxAspectRatio=$maxAspectRatio, maxHeight=$maxHeight, maxWidth=$maxWidth, minAspectRatio=$minAspectRatio, minHeight=$minHeight, minWidth=$minWidth, model=$model, ocr=$ocr, order=$order, originalFileName=$originalFileName, originalPath=$originalPath, page=$page, personIds=$personIds, previewPath=$previewPath, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, thumbnailPath=$thumbnailPath, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
|
@ -556,6 +644,36 @@ class MetadataSearchDto {
|
|||
} else {
|
||||
// json[r'make'] = null;
|
||||
}
|
||||
if (this.maxAspectRatio != null) {
|
||||
json[r'maxAspectRatio'] = this.maxAspectRatio;
|
||||
} else {
|
||||
// json[r'maxAspectRatio'] = null;
|
||||
}
|
||||
if (this.maxHeight != null) {
|
||||
json[r'maxHeight'] = this.maxHeight;
|
||||
} else {
|
||||
// json[r'maxHeight'] = null;
|
||||
}
|
||||
if (this.maxWidth != null) {
|
||||
json[r'maxWidth'] = this.maxWidth;
|
||||
} else {
|
||||
// json[r'maxWidth'] = null;
|
||||
}
|
||||
if (this.minAspectRatio != null) {
|
||||
json[r'minAspectRatio'] = this.minAspectRatio;
|
||||
} else {
|
||||
// json[r'minAspectRatio'] = null;
|
||||
}
|
||||
if (this.minHeight != null) {
|
||||
json[r'minHeight'] = this.minHeight;
|
||||
} else {
|
||||
// json[r'minHeight'] = null;
|
||||
}
|
||||
if (this.minWidth != null) {
|
||||
json[r'minWidth'] = this.minWidth;
|
||||
} else {
|
||||
// json[r'minWidth'] = null;
|
||||
}
|
||||
if (this.model != null) {
|
||||
json[r'model'] = this.model;
|
||||
} else {
|
||||
|
|
@ -720,6 +838,12 @@ class MetadataSearchDto {
|
|||
lensModel: mapValueOfType<String>(json, r'lensModel'),
|
||||
libraryId: mapValueOfType<String>(json, r'libraryId'),
|
||||
make: mapValueOfType<String>(json, r'make'),
|
||||
maxAspectRatio: num.parse('${json[r'maxAspectRatio']}'),
|
||||
maxHeight: mapValueOfType<int>(json, r'maxHeight'),
|
||||
maxWidth: mapValueOfType<int>(json, r'maxWidth'),
|
||||
minAspectRatio: num.parse('${json[r'minAspectRatio']}'),
|
||||
minHeight: mapValueOfType<int>(json, r'minHeight'),
|
||||
minWidth: mapValueOfType<int>(json, r'minWidth'),
|
||||
model: mapValueOfType<String>(json, r'model'),
|
||||
ocr: mapValueOfType<String>(json, r'ocr'),
|
||||
order: AssetOrder.fromJson(json[r'order']),
|
||||
|
|
|
|||
|
|
@ -26,6 +26,12 @@ class RandomSearchDto {
|
|||
this.lensModel,
|
||||
this.libraryId,
|
||||
this.make,
|
||||
this.maxAspectRatio,
|
||||
this.maxHeight,
|
||||
this.maxWidth,
|
||||
this.minAspectRatio,
|
||||
this.minHeight,
|
||||
this.minWidth,
|
||||
this.model,
|
||||
this.ocr,
|
||||
this.personIds = const [],
|
||||
|
|
@ -128,6 +134,76 @@ class RandomSearchDto {
|
|||
/// Filter by camera make
|
||||
String? make;
|
||||
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? maxAspectRatio;
|
||||
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxHeight;
|
||||
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxWidth;
|
||||
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? minAspectRatio;
|
||||
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minHeight;
|
||||
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minWidth;
|
||||
|
||||
/// Filter by camera model
|
||||
String? model;
|
||||
|
||||
|
|
@ -288,6 +364,12 @@ class RandomSearchDto {
|
|||
other.lensModel == lensModel &&
|
||||
other.libraryId == libraryId &&
|
||||
other.make == make &&
|
||||
other.maxAspectRatio == maxAspectRatio &&
|
||||
other.maxHeight == maxHeight &&
|
||||
other.maxWidth == maxWidth &&
|
||||
other.minAspectRatio == minAspectRatio &&
|
||||
other.minHeight == minHeight &&
|
||||
other.minWidth == minWidth &&
|
||||
other.model == model &&
|
||||
other.ocr == ocr &&
|
||||
_deepEquality.equals(other.personIds, personIds) &&
|
||||
|
|
@ -324,6 +406,12 @@ class RandomSearchDto {
|
|||
(lensModel == null ? 0 : lensModel!.hashCode) +
|
||||
(libraryId == null ? 0 : libraryId!.hashCode) +
|
||||
(make == null ? 0 : make!.hashCode) +
|
||||
(maxAspectRatio == null ? 0 : maxAspectRatio!.hashCode) +
|
||||
(maxHeight == null ? 0 : maxHeight!.hashCode) +
|
||||
(maxWidth == null ? 0 : maxWidth!.hashCode) +
|
||||
(minAspectRatio == null ? 0 : minAspectRatio!.hashCode) +
|
||||
(minHeight == null ? 0 : minHeight!.hashCode) +
|
||||
(minWidth == null ? 0 : minWidth!.hashCode) +
|
||||
(model == null ? 0 : model!.hashCode) +
|
||||
(ocr == null ? 0 : ocr!.hashCode) +
|
||||
(personIds.hashCode) +
|
||||
|
|
@ -345,7 +433,7 @@ class RandomSearchDto {
|
|||
(withStacked == null ? 0 : withStacked!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'RandomSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, ocr=$ocr, personIds=$personIds, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
|
||||
String toString() => 'RandomSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, maxAspectRatio=$maxAspectRatio, maxHeight=$maxHeight, maxWidth=$maxWidth, minAspectRatio=$minAspectRatio, minHeight=$minHeight, minWidth=$minWidth, model=$model, ocr=$ocr, personIds=$personIds, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif, withPeople=$withPeople, withStacked=$withStacked]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
|
@ -414,6 +502,36 @@ class RandomSearchDto {
|
|||
} else {
|
||||
// json[r'make'] = null;
|
||||
}
|
||||
if (this.maxAspectRatio != null) {
|
||||
json[r'maxAspectRatio'] = this.maxAspectRatio;
|
||||
} else {
|
||||
// json[r'maxAspectRatio'] = null;
|
||||
}
|
||||
if (this.maxHeight != null) {
|
||||
json[r'maxHeight'] = this.maxHeight;
|
||||
} else {
|
||||
// json[r'maxHeight'] = null;
|
||||
}
|
||||
if (this.maxWidth != null) {
|
||||
json[r'maxWidth'] = this.maxWidth;
|
||||
} else {
|
||||
// json[r'maxWidth'] = null;
|
||||
}
|
||||
if (this.minAspectRatio != null) {
|
||||
json[r'minAspectRatio'] = this.minAspectRatio;
|
||||
} else {
|
||||
// json[r'minAspectRatio'] = null;
|
||||
}
|
||||
if (this.minHeight != null) {
|
||||
json[r'minHeight'] = this.minHeight;
|
||||
} else {
|
||||
// json[r'minHeight'] = null;
|
||||
}
|
||||
if (this.minWidth != null) {
|
||||
json[r'minWidth'] = this.minWidth;
|
||||
} else {
|
||||
// json[r'minWidth'] = null;
|
||||
}
|
||||
if (this.model != null) {
|
||||
json[r'model'] = this.model;
|
||||
} else {
|
||||
|
|
@ -544,6 +662,12 @@ class RandomSearchDto {
|
|||
lensModel: mapValueOfType<String>(json, r'lensModel'),
|
||||
libraryId: mapValueOfType<String>(json, r'libraryId'),
|
||||
make: mapValueOfType<String>(json, r'make'),
|
||||
maxAspectRatio: num.parse('${json[r'maxAspectRatio']}'),
|
||||
maxHeight: mapValueOfType<int>(json, r'maxHeight'),
|
||||
maxWidth: mapValueOfType<int>(json, r'maxWidth'),
|
||||
minAspectRatio: num.parse('${json[r'minAspectRatio']}'),
|
||||
minHeight: mapValueOfType<int>(json, r'minHeight'),
|
||||
minWidth: mapValueOfType<int>(json, r'minWidth'),
|
||||
model: mapValueOfType<String>(json, r'model'),
|
||||
ocr: mapValueOfType<String>(json, r'ocr'),
|
||||
personIds: json[r'personIds'] is Iterable
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ class SmartSearchDto {
|
|||
this.lensModel,
|
||||
this.libraryId,
|
||||
this.make,
|
||||
this.maxAspectRatio,
|
||||
this.maxHeight,
|
||||
this.maxWidth,
|
||||
this.minAspectRatio,
|
||||
this.minHeight,
|
||||
this.minWidth,
|
||||
this.model,
|
||||
this.ocr,
|
||||
this.page,
|
||||
|
|
@ -139,6 +145,76 @@ class SmartSearchDto {
|
|||
/// Filter by camera make
|
||||
String? make;
|
||||
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? maxAspectRatio;
|
||||
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxHeight;
|
||||
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxWidth;
|
||||
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? minAspectRatio;
|
||||
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minHeight;
|
||||
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minWidth;
|
||||
|
||||
/// Filter by camera model
|
||||
String? model;
|
||||
|
||||
|
|
@ -312,6 +388,12 @@ class SmartSearchDto {
|
|||
other.lensModel == lensModel &&
|
||||
other.libraryId == libraryId &&
|
||||
other.make == make &&
|
||||
other.maxAspectRatio == maxAspectRatio &&
|
||||
other.maxHeight == maxHeight &&
|
||||
other.maxWidth == maxWidth &&
|
||||
other.minAspectRatio == minAspectRatio &&
|
||||
other.minHeight == minHeight &&
|
||||
other.minWidth == minWidth &&
|
||||
other.model == model &&
|
||||
other.ocr == ocr &&
|
||||
other.page == page &&
|
||||
|
|
@ -350,6 +432,12 @@ class SmartSearchDto {
|
|||
(lensModel == null ? 0 : lensModel!.hashCode) +
|
||||
(libraryId == null ? 0 : libraryId!.hashCode) +
|
||||
(make == null ? 0 : make!.hashCode) +
|
||||
(maxAspectRatio == null ? 0 : maxAspectRatio!.hashCode) +
|
||||
(maxHeight == null ? 0 : maxHeight!.hashCode) +
|
||||
(maxWidth == null ? 0 : maxWidth!.hashCode) +
|
||||
(minAspectRatio == null ? 0 : minAspectRatio!.hashCode) +
|
||||
(minHeight == null ? 0 : minHeight!.hashCode) +
|
||||
(minWidth == null ? 0 : minWidth!.hashCode) +
|
||||
(model == null ? 0 : model!.hashCode) +
|
||||
(ocr == null ? 0 : ocr!.hashCode) +
|
||||
(page == null ? 0 : page!.hashCode) +
|
||||
|
|
@ -372,7 +460,7 @@ class SmartSearchDto {
|
|||
(withExif == null ? 0 : withExif!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'SmartSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, language=$language, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, ocr=$ocr, page=$page, personIds=$personIds, query=$query, queryAssetId=$queryAssetId, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif]';
|
||||
String toString() => 'SmartSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, language=$language, lensModel=$lensModel, libraryId=$libraryId, make=$make, maxAspectRatio=$maxAspectRatio, maxHeight=$maxHeight, maxWidth=$maxWidth, minAspectRatio=$minAspectRatio, minHeight=$minHeight, minWidth=$minWidth, model=$model, ocr=$ocr, page=$page, personIds=$personIds, query=$query, queryAssetId=$queryAssetId, rating=$rating, size=$size, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility, withDeleted=$withDeleted, withExif=$withExif]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
|
@ -446,6 +534,36 @@ class SmartSearchDto {
|
|||
} else {
|
||||
// json[r'make'] = null;
|
||||
}
|
||||
if (this.maxAspectRatio != null) {
|
||||
json[r'maxAspectRatio'] = this.maxAspectRatio;
|
||||
} else {
|
||||
// json[r'maxAspectRatio'] = null;
|
||||
}
|
||||
if (this.maxHeight != null) {
|
||||
json[r'maxHeight'] = this.maxHeight;
|
||||
} else {
|
||||
// json[r'maxHeight'] = null;
|
||||
}
|
||||
if (this.maxWidth != null) {
|
||||
json[r'maxWidth'] = this.maxWidth;
|
||||
} else {
|
||||
// json[r'maxWidth'] = null;
|
||||
}
|
||||
if (this.minAspectRatio != null) {
|
||||
json[r'minAspectRatio'] = this.minAspectRatio;
|
||||
} else {
|
||||
// json[r'minAspectRatio'] = null;
|
||||
}
|
||||
if (this.minHeight != null) {
|
||||
json[r'minHeight'] = this.minHeight;
|
||||
} else {
|
||||
// json[r'minHeight'] = null;
|
||||
}
|
||||
if (this.minWidth != null) {
|
||||
json[r'minWidth'] = this.minWidth;
|
||||
} else {
|
||||
// json[r'minWidth'] = null;
|
||||
}
|
||||
if (this.model != null) {
|
||||
json[r'model'] = this.model;
|
||||
} else {
|
||||
|
|
@ -582,6 +700,12 @@ class SmartSearchDto {
|
|||
lensModel: mapValueOfType<String>(json, r'lensModel'),
|
||||
libraryId: mapValueOfType<String>(json, r'libraryId'),
|
||||
make: mapValueOfType<String>(json, r'make'),
|
||||
maxAspectRatio: num.parse('${json[r'maxAspectRatio']}'),
|
||||
maxHeight: mapValueOfType<int>(json, r'maxHeight'),
|
||||
maxWidth: mapValueOfType<int>(json, r'maxWidth'),
|
||||
minAspectRatio: num.parse('${json[r'minAspectRatio']}'),
|
||||
minHeight: mapValueOfType<int>(json, r'minHeight'),
|
||||
minWidth: mapValueOfType<int>(json, r'minWidth'),
|
||||
model: mapValueOfType<String>(json, r'model'),
|
||||
ocr: mapValueOfType<String>(json, r'ocr'),
|
||||
page: mapValueOfType<int>(json, r'page'),
|
||||
|
|
|
|||
|
|
@ -27,6 +27,12 @@ class StatisticsSearchDto {
|
|||
this.lensModel,
|
||||
this.libraryId,
|
||||
this.make,
|
||||
this.maxAspectRatio,
|
||||
this.maxHeight,
|
||||
this.maxWidth,
|
||||
this.minAspectRatio,
|
||||
this.minHeight,
|
||||
this.minWidth,
|
||||
this.model,
|
||||
this.ocr,
|
||||
this.personIds = const [],
|
||||
|
|
@ -133,6 +139,76 @@ class StatisticsSearchDto {
|
|||
/// Filter by camera make
|
||||
String? make;
|
||||
|
||||
/// Filter by maximum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? maxAspectRatio;
|
||||
|
||||
/// Filter by maximum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxHeight;
|
||||
|
||||
/// Filter by maximum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? maxWidth;
|
||||
|
||||
/// Filter by minimum aspect ratio (width/height)
|
||||
///
|
||||
/// Minimum value: 0
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
num? minAspectRatio;
|
||||
|
||||
/// Filter by minimum image height
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minHeight;
|
||||
|
||||
/// Filter by minimum image width
|
||||
///
|
||||
/// Minimum value: 1
|
||||
/// Maximum value: 9007199254740991
|
||||
///
|
||||
/// Please note: This property should have been non-nullable! Since the specification file
|
||||
/// does not include a default value (using the "default:" property), however, the generated
|
||||
/// source code must fall back to having a nullable type.
|
||||
/// Consider adding a "default:" property in the specification file to hide this note.
|
||||
///
|
||||
int? minWidth;
|
||||
|
||||
/// Filter by camera model
|
||||
String? model;
|
||||
|
||||
|
|
@ -246,6 +322,12 @@ class StatisticsSearchDto {
|
|||
other.lensModel == lensModel &&
|
||||
other.libraryId == libraryId &&
|
||||
other.make == make &&
|
||||
other.maxAspectRatio == maxAspectRatio &&
|
||||
other.maxHeight == maxHeight &&
|
||||
other.maxWidth == maxWidth &&
|
||||
other.minAspectRatio == minAspectRatio &&
|
||||
other.minHeight == minHeight &&
|
||||
other.minWidth == minWidth &&
|
||||
other.model == model &&
|
||||
other.ocr == ocr &&
|
||||
_deepEquality.equals(other.personIds, personIds) &&
|
||||
|
|
@ -278,6 +360,12 @@ class StatisticsSearchDto {
|
|||
(lensModel == null ? 0 : lensModel!.hashCode) +
|
||||
(libraryId == null ? 0 : libraryId!.hashCode) +
|
||||
(make == null ? 0 : make!.hashCode) +
|
||||
(maxAspectRatio == null ? 0 : maxAspectRatio!.hashCode) +
|
||||
(maxHeight == null ? 0 : maxHeight!.hashCode) +
|
||||
(maxWidth == null ? 0 : maxWidth!.hashCode) +
|
||||
(minAspectRatio == null ? 0 : minAspectRatio!.hashCode) +
|
||||
(minHeight == null ? 0 : minHeight!.hashCode) +
|
||||
(minWidth == null ? 0 : minWidth!.hashCode) +
|
||||
(model == null ? 0 : model!.hashCode) +
|
||||
(ocr == null ? 0 : ocr!.hashCode) +
|
||||
(personIds.hashCode) +
|
||||
|
|
@ -294,7 +382,7 @@ class StatisticsSearchDto {
|
|||
(visibility == null ? 0 : visibility!.hashCode);
|
||||
|
||||
@override
|
||||
String toString() => 'StatisticsSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, description=$description, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, model=$model, ocr=$ocr, personIds=$personIds, rating=$rating, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility]';
|
||||
String toString() => 'StatisticsSearchDto[albumIds=$albumIds, city=$city, country=$country, createdAfter=$createdAfter, createdBefore=$createdBefore, description=$description, isEncoded=$isEncoded, isFavorite=$isFavorite, isMotion=$isMotion, isNotInAlbum=$isNotInAlbum, isOffline=$isOffline, lensModel=$lensModel, libraryId=$libraryId, make=$make, maxAspectRatio=$maxAspectRatio, maxHeight=$maxHeight, maxWidth=$maxWidth, minAspectRatio=$minAspectRatio, minHeight=$minHeight, minWidth=$minWidth, model=$model, ocr=$ocr, personIds=$personIds, rating=$rating, state=$state, tagIds=$tagIds, takenAfter=$takenAfter, takenBefore=$takenBefore, trashedAfter=$trashedAfter, trashedBefore=$trashedBefore, type=$type, updatedAfter=$updatedAfter, updatedBefore=$updatedBefore, visibility=$visibility]';
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
final json = <String, dynamic>{};
|
||||
|
|
@ -368,6 +456,36 @@ class StatisticsSearchDto {
|
|||
} else {
|
||||
// json[r'make'] = null;
|
||||
}
|
||||
if (this.maxAspectRatio != null) {
|
||||
json[r'maxAspectRatio'] = this.maxAspectRatio;
|
||||
} else {
|
||||
// json[r'maxAspectRatio'] = null;
|
||||
}
|
||||
if (this.maxHeight != null) {
|
||||
json[r'maxHeight'] = this.maxHeight;
|
||||
} else {
|
||||
// json[r'maxHeight'] = null;
|
||||
}
|
||||
if (this.maxWidth != null) {
|
||||
json[r'maxWidth'] = this.maxWidth;
|
||||
} else {
|
||||
// json[r'maxWidth'] = null;
|
||||
}
|
||||
if (this.minAspectRatio != null) {
|
||||
json[r'minAspectRatio'] = this.minAspectRatio;
|
||||
} else {
|
||||
// json[r'minAspectRatio'] = null;
|
||||
}
|
||||
if (this.minHeight != null) {
|
||||
json[r'minHeight'] = this.minHeight;
|
||||
} else {
|
||||
// json[r'minHeight'] = null;
|
||||
}
|
||||
if (this.minWidth != null) {
|
||||
json[r'minWidth'] = this.minWidth;
|
||||
} else {
|
||||
// json[r'minWidth'] = null;
|
||||
}
|
||||
if (this.model != null) {
|
||||
json[r'model'] = this.model;
|
||||
} else {
|
||||
|
|
@ -474,6 +592,12 @@ class StatisticsSearchDto {
|
|||
lensModel: mapValueOfType<String>(json, r'lensModel'),
|
||||
libraryId: mapValueOfType<String>(json, r'libraryId'),
|
||||
make: mapValueOfType<String>(json, r'make'),
|
||||
maxAspectRatio: num.parse('${json[r'maxAspectRatio']}'),
|
||||
maxHeight: mapValueOfType<int>(json, r'maxHeight'),
|
||||
maxWidth: mapValueOfType<int>(json, r'maxWidth'),
|
||||
minAspectRatio: num.parse('${json[r'minAspectRatio']}'),
|
||||
minHeight: mapValueOfType<int>(json, r'minHeight'),
|
||||
minWidth: mapValueOfType<int>(json, r'minWidth'),
|
||||
model: mapValueOfType<String>(json, r'model'),
|
||||
ocr: mapValueOfType<String>(json, r'ocr'),
|
||||
personIds: json[r'personIds'] is Iterable
|
||||
|
|
|
|||
|
|
@ -9823,6 +9823,50 @@
|
|||
"nullable": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maxAspectRatio",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by maximum aspect ratio (width/height)",
|
||||
"schema": {
|
||||
"exclusiveMinimum": true,
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maxHeight",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by maximum image height",
|
||||
"schema": {
|
||||
"minimum": 1,
|
||||
"maximum": 9007199254740991,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "maxWidth",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by maximum image width",
|
||||
"schema": {
|
||||
"minimum": 1,
|
||||
"maximum": 9007199254740991,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minAspectRatio",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by minimum aspect ratio (width/height)",
|
||||
"schema": {
|
||||
"exclusiveMinimum": true,
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minFileSize",
|
||||
"required": false,
|
||||
|
|
@ -9834,6 +9878,28 @@
|
|||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minHeight",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by minimum image height",
|
||||
"schema": {
|
||||
"minimum": 1,
|
||||
"maximum": 9007199254740991,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "minWidth",
|
||||
"required": false,
|
||||
"in": "query",
|
||||
"description": "Filter by minimum image width",
|
||||
"schema": {
|
||||
"minimum": 1,
|
||||
"maximum": 9007199254740991,
|
||||
"type": "integer"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "model",
|
||||
"required": false,
|
||||
|
|
@ -19324,6 +19390,42 @@
|
|||
"nullable": true,
|
||||
"type": "string"
|
||||
},
|
||||
"maxAspectRatio": {
|
||||
"description": "Filter by maximum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"maxHeight": {
|
||||
"description": "Filter by maximum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"maxWidth": {
|
||||
"description": "Filter by maximum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minAspectRatio": {
|
||||
"description": "Filter by minimum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"minHeight": {
|
||||
"description": "Filter by minimum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minWidth": {
|
||||
"description": "Filter by minimum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"description": "Filter by camera model",
|
||||
"nullable": true,
|
||||
|
|
@ -21008,6 +21110,42 @@
|
|||
"nullable": true,
|
||||
"type": "string"
|
||||
},
|
||||
"maxAspectRatio": {
|
||||
"description": "Filter by maximum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"maxHeight": {
|
||||
"description": "Filter by maximum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"maxWidth": {
|
||||
"description": "Filter by maximum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minAspectRatio": {
|
||||
"description": "Filter by minimum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"minHeight": {
|
||||
"description": "Filter by minimum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minWidth": {
|
||||
"description": "Filter by minimum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"description": "Filter by camera model",
|
||||
"nullable": true,
|
||||
|
|
@ -22453,6 +22591,42 @@
|
|||
"nullable": true,
|
||||
"type": "string"
|
||||
},
|
||||
"maxAspectRatio": {
|
||||
"description": "Filter by maximum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"maxHeight": {
|
||||
"description": "Filter by maximum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"maxWidth": {
|
||||
"description": "Filter by maximum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minAspectRatio": {
|
||||
"description": "Filter by minimum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"minHeight": {
|
||||
"description": "Filter by minimum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minWidth": {
|
||||
"description": "Filter by minimum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"description": "Filter by camera model",
|
||||
"nullable": true,
|
||||
|
|
@ -22729,6 +22903,42 @@
|
|||
"nullable": true,
|
||||
"type": "string"
|
||||
},
|
||||
"maxAspectRatio": {
|
||||
"description": "Filter by maximum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"maxHeight": {
|
||||
"description": "Filter by maximum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"maxWidth": {
|
||||
"description": "Filter by maximum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minAspectRatio": {
|
||||
"description": "Filter by minimum aspect ratio (width/height)",
|
||||
"exclusiveMinimum": true,
|
||||
"minimum": 0,
|
||||
"type": "number"
|
||||
},
|
||||
"minHeight": {
|
||||
"description": "Filter by minimum image height",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"minWidth": {
|
||||
"description": "Filter by minimum image width",
|
||||
"maximum": 9007199254740991,
|
||||
"minimum": 1,
|
||||
"type": "integer"
|
||||
},
|
||||
"model": {
|
||||
"description": "Filter by camera model",
|
||||
"nullable": true,
|
||||
|
|
|
|||
|
|
@ -1608,6 +1608,18 @@ export type MetadataSearchDto = {
|
|||
libraryId?: string | null;
|
||||
/** Filter by camera make */
|
||||
make?: string | null;
|
||||
/** Filter by maximum aspect ratio (width/height) */
|
||||
maxAspectRatio?: number;
|
||||
/** Filter by maximum image height */
|
||||
maxHeight?: number;
|
||||
/** Filter by maximum image width */
|
||||
maxWidth?: number;
|
||||
/** Filter by minimum aspect ratio (width/height) */
|
||||
minAspectRatio?: number;
|
||||
/** Filter by minimum image height */
|
||||
minHeight?: number;
|
||||
/** Filter by minimum image width */
|
||||
minWidth?: number;
|
||||
/** Filter by camera model */
|
||||
model?: string | null;
|
||||
/** Filter by OCR text content */
|
||||
|
|
@ -1729,6 +1741,18 @@ export type RandomSearchDto = {
|
|||
libraryId?: string | null;
|
||||
/** Filter by camera make */
|
||||
make?: string | null;
|
||||
/** Filter by maximum aspect ratio (width/height) */
|
||||
maxAspectRatio?: number;
|
||||
/** Filter by maximum image height */
|
||||
maxHeight?: number;
|
||||
/** Filter by maximum image width */
|
||||
maxWidth?: number;
|
||||
/** Filter by minimum aspect ratio (width/height) */
|
||||
minAspectRatio?: number;
|
||||
/** Filter by minimum image height */
|
||||
minHeight?: number;
|
||||
/** Filter by minimum image width */
|
||||
minWidth?: number;
|
||||
/** Filter by camera model */
|
||||
model?: string | null;
|
||||
/** Filter by OCR text content */
|
||||
|
|
@ -1795,6 +1819,18 @@ export type SmartSearchDto = {
|
|||
libraryId?: string | null;
|
||||
/** Filter by camera make */
|
||||
make?: string | null;
|
||||
/** Filter by maximum aspect ratio (width/height) */
|
||||
maxAspectRatio?: number;
|
||||
/** Filter by maximum image height */
|
||||
maxHeight?: number;
|
||||
/** Filter by maximum image width */
|
||||
maxWidth?: number;
|
||||
/** Filter by minimum aspect ratio (width/height) */
|
||||
minAspectRatio?: number;
|
||||
/** Filter by minimum image height */
|
||||
minHeight?: number;
|
||||
/** Filter by minimum image width */
|
||||
minWidth?: number;
|
||||
/** Filter by camera model */
|
||||
model?: string | null;
|
||||
/** Filter by OCR text content */
|
||||
|
|
@ -1863,6 +1899,18 @@ export type StatisticsSearchDto = {
|
|||
libraryId?: string | null;
|
||||
/** Filter by camera make */
|
||||
make?: string | null;
|
||||
/** Filter by maximum aspect ratio (width/height) */
|
||||
maxAspectRatio?: number;
|
||||
/** Filter by maximum image height */
|
||||
maxHeight?: number;
|
||||
/** Filter by maximum image width */
|
||||
maxWidth?: number;
|
||||
/** Filter by minimum aspect ratio (width/height) */
|
||||
minAspectRatio?: number;
|
||||
/** Filter by minimum image height */
|
||||
minHeight?: number;
|
||||
/** Filter by minimum image width */
|
||||
minWidth?: number;
|
||||
/** Filter by camera model */
|
||||
model?: string | null;
|
||||
/** Filter by OCR text content */
|
||||
|
|
@ -5484,7 +5532,7 @@ export function getExploreData(opts?: Oazapfts.RequestOpts) {
|
|||
/**
|
||||
* Search large assets
|
||||
*/
|
||||
export function searchLargeAssets({ albumIds, city, country, createdAfter, createdBefore, isEncoded, isFavorite, isMotion, isNotInAlbum, isOffline, lensModel, libraryId, make, minFileSize, model, ocr, personIds, rating, size, state, tagIds, takenAfter, takenBefore, trashedAfter, trashedBefore, $type, updatedAfter, updatedBefore, visibility, withDeleted, withExif }: {
|
||||
export function searchLargeAssets({ albumIds, city, country, createdAfter, createdBefore, isEncoded, isFavorite, isMotion, isNotInAlbum, isOffline, lensModel, libraryId, make, maxAspectRatio, maxHeight, maxWidth, minAspectRatio, minFileSize, minHeight, minWidth, model, ocr, personIds, rating, size, state, tagIds, takenAfter, takenBefore, trashedAfter, trashedBefore, $type, updatedAfter, updatedBefore, visibility, withDeleted, withExif }: {
|
||||
albumIds?: string[];
|
||||
city?: string | null;
|
||||
country?: string | null;
|
||||
|
|
@ -5498,7 +5546,13 @@ export function searchLargeAssets({ albumIds, city, country, createdAfter, creat
|
|||
lensModel?: string | null;
|
||||
libraryId?: string | null;
|
||||
make?: string | null;
|
||||
maxAspectRatio?: number;
|
||||
maxHeight?: number;
|
||||
maxWidth?: number;
|
||||
minAspectRatio?: number;
|
||||
minFileSize?: number;
|
||||
minHeight?: number;
|
||||
minWidth?: number;
|
||||
model?: string | null;
|
||||
ocr?: string;
|
||||
personIds?: string[];
|
||||
|
|
@ -5534,7 +5588,13 @@ export function searchLargeAssets({ albumIds, city, country, createdAfter, creat
|
|||
lensModel,
|
||||
libraryId,
|
||||
make,
|
||||
maxAspectRatio,
|
||||
maxHeight,
|
||||
maxWidth,
|
||||
minAspectRatio,
|
||||
minFileSize,
|
||||
minHeight,
|
||||
minWidth,
|
||||
model,
|
||||
ocr,
|
||||
personIds,
|
||||
|
|
|
|||
|
|
@ -120,6 +120,42 @@ describe(SearchController.name, () => {
|
|||
);
|
||||
});
|
||||
|
||||
it('should reject minWidth as a negative number', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer()).post('/search/metadata').send({ minWidth: -1 });
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(
|
||||
errorDto.validationError([{ path: ['minWidth'], message: 'Too small: expected number to be >=1' }]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject minAspectRatio as zero', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer()).post('/search/metadata').send({ minAspectRatio: 0 });
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(
|
||||
errorDto.validationError([{ path: ['minAspectRatio'], message: expect.stringContaining('Too small') }]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject maxAspectRatio as zero', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer()).post('/search/metadata').send({ maxAspectRatio: 0 });
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(
|
||||
errorDto.validationError([{ path: ['maxAspectRatio'], message: expect.stringContaining('Too small') }]),
|
||||
);
|
||||
});
|
||||
|
||||
it('should reject minAspectRatio as a string', async () => {
|
||||
const { status, body } = await request(ctx.getHttpServer())
|
||||
.post('/search/metadata')
|
||||
.send({ minAspectRatio: 'abc' });
|
||||
expect(status).toBe(400);
|
||||
expect(body).toEqual(
|
||||
errorDto.validationError([
|
||||
{ path: ['minAspectRatio'], message: 'Invalid input: expected number, received NaN' },
|
||||
]),
|
||||
);
|
||||
});
|
||||
|
||||
describe('POST /search/random', () => {
|
||||
it('should be an authenticated route', async () => {
|
||||
await request(ctx.getHttpServer()).post('/search/random');
|
||||
|
|
|
|||
|
|
@ -29,6 +29,12 @@ const BaseSearchSchema = z.object({
|
|||
make: emptyStringToNull(z.string().nullable()).optional().describe('Filter by camera make'),
|
||||
model: emptyStringToNull(z.string().nullable()).optional().describe('Filter by camera model'),
|
||||
lensModel: emptyStringToNull(z.string().nullable()).optional().describe('Filter by lens model'),
|
||||
minAspectRatio: z.coerce.number().positive().optional().describe('Filter by minimum aspect ratio (width/height)'),
|
||||
maxAspectRatio: z.coerce.number().positive().optional().describe('Filter by maximum aspect ratio (width/height)'),
|
||||
minWidth: z.coerce.number().int().min(1).optional().describe('Filter by minimum image width'),
|
||||
maxWidth: z.coerce.number().int().min(1).optional().describe('Filter by maximum image width'),
|
||||
minHeight: z.coerce.number().int().min(1).optional().describe('Filter by minimum image height'),
|
||||
maxHeight: z.coerce.number().int().min(1).optional().describe('Filter by maximum image height'),
|
||||
isNotInAlbum: z.boolean().optional().describe('Filter assets not in any album'),
|
||||
personIds: z.array(z.uuidv4()).optional().describe('Filter by person IDs'),
|
||||
tagIds: z.array(z.uuidv4()).nullish().describe('Filter by tag IDs'),
|
||||
|
|
|
|||
|
|
@ -69,6 +69,12 @@ export interface SearchExifOptions {
|
|||
country?: string | null;
|
||||
lensModel?: string | null;
|
||||
make?: string | null;
|
||||
maxAspectRatio?: number;
|
||||
maxHeight?: number;
|
||||
maxWidth?: number;
|
||||
minAspectRatio?: number;
|
||||
minHeight?: number;
|
||||
minWidth?: number;
|
||||
model?: string | null;
|
||||
state?: string | null;
|
||||
description?: string | null;
|
||||
|
|
|
|||
|
|
@ -428,6 +428,16 @@ export function searchAssetBuilder(kysely: Kysely<DB>, options: AssetSearchBuild
|
|||
.innerJoin('asset_exif', 'asset.id', 'asset_exif.assetId')
|
||||
.where('asset_exif.rating', options.rating === null ? 'is' : '=', options.rating!),
|
||||
)
|
||||
.$if(options.minAspectRatio !== undefined, (qb) =>
|
||||
qb.where(sql`asset.width::double precision / nullif(asset.height, 0)`, '>=', options.minAspectRatio!),
|
||||
)
|
||||
.$if(options.maxAspectRatio !== undefined, (qb) =>
|
||||
qb.where(sql`asset.width::double precision / nullif(asset.height, 0)`, '<=', options.maxAspectRatio!),
|
||||
)
|
||||
.$if(options.minWidth !== undefined, (qb) => qb.where('asset.width', '>=', options.minWidth!))
|
||||
.$if(options.maxWidth !== undefined, (qb) => qb.where('asset.width', '<=', options.maxWidth!))
|
||||
.$if(options.minHeight !== undefined, (qb) => qb.where('asset.height', '>=', options.minHeight!))
|
||||
.$if(options.maxHeight !== undefined, (qb) => qb.where('asset.height', '<=', options.maxHeight!))
|
||||
.$if(!!options.checksum, (qb) => qb.where('asset.checksum', '=', options.checksum!))
|
||||
.$if(!!options.id, (qb) => qb.where('asset.id', '=', asUuid(options.id!)))
|
||||
.$if(!!options.libraryId, (qb) => qb.where('asset.libraryId', '=', asUuid(options.libraryId!)))
|
||||
|
|
|
|||
|
|
@ -110,6 +110,83 @@ describe(SearchService.name, () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('aspect ratio filter', () => {
|
||||
it('should filter by minAspectRatio', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
|
||||
const { asset: wideAsset } = await ctx.newAsset({ ownerId: user.id, width: 4000, height: 1000 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 3000, height: 3000 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 1000, height: 4000 });
|
||||
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
const response = await sut.searchMetadata(auth, { minAspectRatio: 2 });
|
||||
|
||||
expect(response.assets.items).toEqual([expect.objectContaining({ id: wideAsset.id })]);
|
||||
});
|
||||
|
||||
it('should filter by maxAspectRatio', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
|
||||
await ctx.newAsset({ ownerId: user.id, width: 4000, height: 3000 });
|
||||
const { asset: narrowAsset } = await ctx.newAsset({ ownerId: user.id, width: 1000, height: 4000 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 3000, height: 3000 });
|
||||
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
const response = await sut.searchMetadata(auth, { maxAspectRatio: 0.5 });
|
||||
|
||||
expect(response.assets.items).toEqual([expect.objectContaining({ id: narrowAsset.id })]);
|
||||
});
|
||||
|
||||
it('should filter by both minAspectRatio and maxAspectRatio', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
|
||||
// ratio 4:3 = 1.333 — within [1.2, 1.5]
|
||||
const { asset: inRangeAsset } = await ctx.newAsset({ ownerId: user.id, width: 4000, height: 3000 });
|
||||
// ratio 4:1 = 4.0 — above max
|
||||
await ctx.newAsset({ ownerId: user.id, width: 4000, height: 1000 });
|
||||
// ratio 1:4 = 0.25 — below min
|
||||
await ctx.newAsset({ ownerId: user.id, width: 1000, height: 4000 });
|
||||
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
const response = await sut.searchMetadata(auth, { minAspectRatio: 1.2, maxAspectRatio: 1.5 });
|
||||
|
||||
expect(response.assets.items).toEqual([expect.objectContaining({ id: inRangeAsset.id })]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('resolution filter', () => {
|
||||
it('should filter by minimum width and height', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
|
||||
const { asset: highResAsset } = await ctx.newAsset({ ownerId: user.id, width: 4000, height: 3000 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 3000, height: 3000 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 4000, height: 2000 });
|
||||
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
const response = await sut.searchMetadata(auth, { minWidth: 3500, minHeight: 2500 });
|
||||
|
||||
expect(response.assets.items).toEqual([expect.objectContaining({ id: highResAsset.id })]);
|
||||
});
|
||||
|
||||
it('should filter by maximum width and height', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
const { user } = await ctx.newUser();
|
||||
|
||||
await ctx.newAsset({ ownerId: user.id, width: 2000, height: 1500 });
|
||||
const { asset: lowResAsset } = await ctx.newAsset({ ownerId: user.id, width: 1000, height: 800 });
|
||||
await ctx.newAsset({ ownerId: user.id, width: 1200, height: 1600 });
|
||||
|
||||
const auth = factory.auth({ user: { id: user.id } });
|
||||
const response = await sut.searchMetadata(auth, { maxWidth: 1200, maxHeight: 1000 });
|
||||
|
||||
expect(response.assets.items).toEqual([expect.objectContaining({ id: lowResAsset.id })]);
|
||||
});
|
||||
});
|
||||
|
||||
describe('getSearchSuggestions', () => {
|
||||
it('should filter out empty search suggestions', async () => {
|
||||
const { sut, ctx } = setup();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,79 @@
|
|||
<script lang="ts">
|
||||
import type { SearchImagePropsFilter } from '$lib/types';
|
||||
import { Input, Text } from '@immich/ui';
|
||||
import { t } from 'svelte-i18n';
|
||||
|
||||
type Props = {
|
||||
filters: SearchImagePropsFilter;
|
||||
};
|
||||
|
||||
let { filters = $bindable() }: Props = $props();
|
||||
</script>
|
||||
|
||||
<div id="image-selection">
|
||||
<Text fontWeight="medium">{$t('image_properties')}</Text>
|
||||
|
||||
<div class="mt-1 grid grid-auto-fit-40 gap-5">
|
||||
<fieldset>
|
||||
<Text class="mb-1 block text-xs font-light text-neutral-500" fontWeight="medium">{$t('aspect_ratio')}</Text>
|
||||
<div class="grid grid-cols-2 gap-1">
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('min_width')}
|
||||
aria-label={`${$t('min_aspect_ratio')} ${$t('width')}`}
|
||||
bind:value={filters.minAspectRatioWidth}
|
||||
/>
|
||||
<div class="flex items-center gap-1">
|
||||
<Text aria-hidden="true" class="text-sm text-neutral-500">:</Text>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('min_height')}
|
||||
aria-label={`${$t('min_aspect_ratio')} ${$t('height')}`}
|
||||
bind:value={filters.minAspectRatioHeight}
|
||||
/>
|
||||
</div>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('max_width')}
|
||||
aria-label={`${$t('max_aspect_ratio')} ${$t('width')}`}
|
||||
bind:value={filters.maxAspectRatioWidth}
|
||||
/>
|
||||
<div class="flex items-center gap-1">
|
||||
<Text aria-hidden="true" class="text-sm text-neutral-500">:</Text>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('max_height')}
|
||||
aria-label={`${$t('max_aspect_ratio')} ${$t('height')}`}
|
||||
bind:value={filters.maxAspectRatioHeight}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
<fieldset>
|
||||
<Text class="mb-1 block text-xs font-light text-neutral-500" fontWeight="medium">{$t('resolution')}</Text>
|
||||
<div class="grid grid-cols-2 gap-1">
|
||||
<Input type="text" placeholder={$t('min_width')} aria-label={$t('min_width')} bind:value={filters.minWidth} />
|
||||
<div class="flex items-center gap-1">
|
||||
<Text aria-hidden="true" class="text-sm text-neutral-500">x</Text>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('min_height')}
|
||||
aria-label={$t('min_height')}
|
||||
bind:value={filters.minHeight}
|
||||
/>
|
||||
</div>
|
||||
<Input type="text" placeholder={$t('max_width')} aria-label={$t('max_width')} bind:value={filters.maxWidth} />
|
||||
<div class="flex items-center gap-1">
|
||||
<Text aria-hidden="true" class="text-sm text-neutral-500">x</Text>
|
||||
<Input
|
||||
type="text"
|
||||
placeholder={$t('max_height')}
|
||||
aria-label={$t('max_height')}
|
||||
bind:value={filters.maxHeight}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -8,6 +8,7 @@
|
|||
import SearchRatingsSection from '$lib/components/shared-components/search-bar/SearchRatingsSection.svelte';
|
||||
import SearchTagsSection from '$lib/components/shared-components/search-bar/SearchTagsSection.svelte';
|
||||
import SearchTextSection from '$lib/components/shared-components/search-bar/SearchTextSection.svelte';
|
||||
import SearchImagePropsSection from '$lib/components/shared-components/search-bar/SearchImagePropsSection.svelte';
|
||||
import { MediaType, QueryType, validQueryTypes } from '$lib/constants';
|
||||
import { authManager } from '$lib/managers/auth-manager.svelte';
|
||||
import type { SearchFilter } from '$lib/types';
|
||||
|
|
@ -28,6 +29,73 @@
|
|||
let { searchQuery, onClose }: Props = $props();
|
||||
|
||||
const parseOptionalDate = (dateString?: DateTime) => (dateString ? parseUtcDate(dateString.toString()) : undefined);
|
||||
|
||||
const numberToOptionalString = (value?: number | null) =>
|
||||
value === null || value === undefined ? undefined : value.toString();
|
||||
|
||||
const parseOptionalPositiveInteger = (value?: string) => {
|
||||
if (!value?.trim()) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
const trimmed = value.trim();
|
||||
const parsed = Number(trimmed);
|
||||
return Number.isInteger(parsed) && parsed > 0 ? parsed : undefined;
|
||||
};
|
||||
|
||||
const greatestCommonDivisor = (left: number, right: number): number => {
|
||||
let a = Math.abs(left);
|
||||
let b = Math.abs(right);
|
||||
|
||||
while (b !== 0) {
|
||||
[a, b] = [b, a % b];
|
||||
}
|
||||
|
||||
return a || 1;
|
||||
};
|
||||
|
||||
const ratioToOptionalPair = (value?: number | null) => {
|
||||
if (value === null || value === undefined || !Number.isFinite(value) || value <= 0) {
|
||||
return { width: undefined, height: undefined };
|
||||
}
|
||||
|
||||
let bestWidth = 1;
|
||||
let bestHeight = 1;
|
||||
let bestError = Number.POSITIVE_INFINITY;
|
||||
|
||||
for (let denominator = 1; denominator <= 1000; denominator++) {
|
||||
const numerator = Math.max(1, Math.round(value * denominator));
|
||||
const error = Math.abs(numerator / denominator - value);
|
||||
|
||||
if (error < bestError) {
|
||||
bestWidth = numerator;
|
||||
bestHeight = denominator;
|
||||
bestError = error;
|
||||
}
|
||||
|
||||
if (error < Number.EPSILON) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const divisor = greatestCommonDivisor(bestWidth, bestHeight);
|
||||
return {
|
||||
width: numberToOptionalString(bestWidth / divisor),
|
||||
height: numberToOptionalString(bestHeight / divisor),
|
||||
};
|
||||
};
|
||||
|
||||
const parseOptionalAspectRatio = (width?: string, height?: string) => {
|
||||
const parsedWidth = parseOptionalPositiveInteger(width);
|
||||
const parsedHeight = parseOptionalPositiveInteger(height);
|
||||
|
||||
if (!parsedWidth || !parsedHeight) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
return parsedWidth / parsedHeight;
|
||||
};
|
||||
|
||||
const toStartOfDayDate = (dateString: string) => parseUtcDate(dateString)?.startOf('day') || undefined;
|
||||
const formId = generateId();
|
||||
|
||||
|
|
@ -58,6 +126,9 @@
|
|||
query = searchQuery.originalPath;
|
||||
}
|
||||
|
||||
const minAspectRatio = ratioToOptionalPair(searchQuery.minAspectRatio);
|
||||
const maxAspectRatio = ratioToOptionalPair(searchQuery.maxAspectRatio);
|
||||
|
||||
return {
|
||||
query,
|
||||
ocr: searchQuery.ocr,
|
||||
|
|
@ -96,6 +167,16 @@
|
|||
? MediaType.Video
|
||||
: MediaType.All,
|
||||
rating: searchQuery.rating,
|
||||
imageProperties: {
|
||||
minAspectRatioWidth: minAspectRatio.width,
|
||||
minAspectRatioHeight: minAspectRatio.height,
|
||||
maxAspectRatioWidth: maxAspectRatio.width,
|
||||
maxAspectRatioHeight: maxAspectRatio.height,
|
||||
minWidth: numberToOptionalString(searchQuery.minWidth),
|
||||
maxWidth: numberToOptionalString(searchQuery.maxWidth),
|
||||
minHeight: numberToOptionalString(searchQuery.minHeight),
|
||||
maxHeight: numberToOptionalString(searchQuery.maxHeight),
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -118,6 +199,16 @@
|
|||
},
|
||||
mediaType: MediaType.All,
|
||||
rating: undefined,
|
||||
imageProperties: {
|
||||
minAspectRatioWidth: undefined,
|
||||
minAspectRatioHeight: undefined,
|
||||
maxAspectRatioWidth: undefined,
|
||||
maxAspectRatioHeight: undefined,
|
||||
minWidth: undefined,
|
||||
maxWidth: undefined,
|
||||
minHeight: undefined,
|
||||
maxHeight: undefined,
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -149,6 +240,18 @@
|
|||
visibility: filter.display.isArchive ? AssetVisibility.Archive : undefined,
|
||||
isFavorite: filter.display.isFavorite || undefined,
|
||||
isNotInAlbum: filter.display.isNotInAlbum || undefined,
|
||||
minAspectRatio: parseOptionalAspectRatio(
|
||||
filter.imageProperties.minAspectRatioWidth,
|
||||
filter.imageProperties.minAspectRatioHeight,
|
||||
),
|
||||
maxAspectRatio: parseOptionalAspectRatio(
|
||||
filter.imageProperties.maxAspectRatioWidth,
|
||||
filter.imageProperties.maxAspectRatioHeight,
|
||||
),
|
||||
minWidth: parseOptionalPositiveInteger(filter.imageProperties.minWidth),
|
||||
maxWidth: parseOptionalPositiveInteger(filter.imageProperties.maxWidth),
|
||||
minHeight: parseOptionalPositiveInteger(filter.imageProperties.minHeight),
|
||||
maxHeight: parseOptionalPositiveInteger(filter.imageProperties.maxHeight),
|
||||
personIds: filter.personIds.size > 0 ? [...filter.personIds] : undefined,
|
||||
tagIds: filter.tagIds === null ? null : filter.tagIds.size > 0 ? [...filter.tagIds] : undefined,
|
||||
type,
|
||||
|
|
@ -209,6 +312,9 @@
|
|||
<!-- DISPLAY OPTIONS -->
|
||||
<SearchDisplaySection bind:filters={filter.display} />
|
||||
</div>
|
||||
|
||||
<!-- IMAGE PROPERTIES -->
|
||||
<SearchImagePropsSection bind:filters={filter.imageProperties} />
|
||||
</div>
|
||||
</form>
|
||||
</ModalBody>
|
||||
|
|
|
|||
|
|
@ -63,6 +63,17 @@ export type SearchDisplayFilters = {
|
|||
isFavorite: boolean;
|
||||
};
|
||||
|
||||
export type SearchImagePropsFilter = {
|
||||
minAspectRatioWidth?: string;
|
||||
minAspectRatioHeight?: string;
|
||||
maxAspectRatioWidth?: string;
|
||||
maxAspectRatioHeight?: string;
|
||||
minWidth?: string;
|
||||
maxWidth?: string;
|
||||
minHeight?: string;
|
||||
maxHeight?: string;
|
||||
};
|
||||
|
||||
export type SearchLocationFilter = {
|
||||
country?: string;
|
||||
state?: string;
|
||||
|
|
@ -82,6 +93,7 @@ export type SearchFilter = {
|
|||
display: SearchDisplayFilters;
|
||||
mediaType: MediaType;
|
||||
rating?: number | null;
|
||||
imageProperties: SearchImagePropsFilter;
|
||||
};
|
||||
|
||||
export type JSONSchemaType = 'string' | 'number' | 'integer' | 'boolean' | 'object';
|
||||
|
|
|
|||
|
|
@ -189,6 +189,12 @@
|
|||
description: $t('description'),
|
||||
queryAssetId: $t('query_asset_id'),
|
||||
ocr: $t('ocr'),
|
||||
minAspectRatio: $t('min_aspect_ratio'),
|
||||
maxAspectRatio: $t('max_aspect_ratio'),
|
||||
minWidth: $t('min_width'),
|
||||
maxWidth: $t('max_width'),
|
||||
minHeight: $t('min_height'),
|
||||
maxHeight: $t('max_height'),
|
||||
};
|
||||
return keyMap[key] || key;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue