From 51cfe10c287e9bead16181d0ef0184f6407fcbb5 Mon Sep 17 00:00:00 2001 From: PyKen Date: Mon, 31 Jul 2023 10:31:57 +0900 Subject: [PATCH] feat(web/server): Search by panorama photos (#3470) * Add panorama filter * Add generated api changes * Fix naming --- cli/src/api/open-api/api.ts | 23 ++++++++++++---- mobile/openapi/doc/SearchApi.md | 6 +++-- mobile/openapi/lib/api/search_api.dart | 13 +++++++--- mobile/openapi/test/search_api_test.dart | 2 +- server/immich-openapi-specs.json | 8 ++++++ server/src/domain/search/dto/search.dto.ts | 5 ++++ .../infra/typesense-schemas/asset.schema.ts | 3 ++- web/src/api/open-api/api.ts | 26 ++++++++++++++----- web/src/routes/(user)/explore/+page.svelte | 10 +++++++ 9 files changed, 78 insertions(+), 18 deletions(-) diff --git a/cli/src/api/open-api/api.ts b/cli/src/api/open-api/api.ts index 384e33ca..6e237d86 100644 --- a/cli/src/api/open-api/api.ts +++ b/cli/src/api/open-api/api.ts @@ -9489,6 +9489,7 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio * @param {string} [exifInfoCountry] * @param {string} [exifInfoMake] * @param {string} [exifInfoModel] + * @param {string} [exifInfoProjectionType] * @param {Array} [smartInfoObjects] * @param {Array} [smartInfoTags] * @param {boolean} [recent] @@ -9496,7 +9497,7 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - search: async (q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options: AxiosRequestConfig = {}): Promise => { + search: async (q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, exifInfoProjectionType?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/search`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -9562,6 +9563,10 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio localVarQueryParameter['exifInfo.model'] = exifInfoModel; } + if (exifInfoProjectionType !== undefined) { + localVarQueryParameter['exifInfo.projectionType'] = exifInfoProjectionType; + } + if (smartInfoObjects) { localVarQueryParameter['smartInfo.objects'] = smartInfoObjects; } @@ -9630,6 +9635,7 @@ export const SearchApiFp = function(configuration?: Configuration) { * @param {string} [exifInfoCountry] * @param {string} [exifInfoMake] * @param {string} [exifInfoModel] + * @param {string} [exifInfoProjectionType] * @param {Array} [smartInfoObjects] * @param {Array} [smartInfoTags] * @param {boolean} [recent] @@ -9637,8 +9643,8 @@ export const SearchApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, smartInfoObjects, smartInfoTags, recent, motion, options); + async search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, exifInfoProjectionType?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, exifInfoProjectionType, smartInfoObjects, smartInfoTags, recent, motion, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -9674,7 +9680,7 @@ export const SearchApiFactory = function (configuration?: Configuration, basePat * @throws {RequiredError} */ search(requestParameters: SearchApiSearchRequest = {}, options?: AxiosRequestConfig): AxiosPromise { - return localVarFp.search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(axios, basePath)); + return localVarFp.search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.exifInfoProjectionType, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(axios, basePath)); }, }; }; @@ -9762,6 +9768,13 @@ export interface SearchApiSearchRequest { */ readonly exifInfoModel?: string + /** + * + * @type {string} + * @memberof SearchApiSearch + */ + readonly exifInfoProjectionType?: string + /** * * @type {Array} @@ -9826,7 +9839,7 @@ export class SearchApi extends BaseAPI { * @memberof SearchApi */ public search(requestParameters: SearchApiSearchRequest = {}, options?: AxiosRequestConfig) { - return SearchApiFp(this.configuration).search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(this.axios, this.basePath)); + return SearchApiFp(this.configuration).search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.exifInfoProjectionType, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(this.axios, this.basePath)); } } diff --git a/mobile/openapi/doc/SearchApi.md b/mobile/openapi/doc/SearchApi.md index 2ada86a4..74840a73 100644 --- a/mobile/openapi/doc/SearchApi.md +++ b/mobile/openapi/doc/SearchApi.md @@ -117,7 +117,7 @@ This endpoint does not need any parameter. [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) # **search** -> SearchResponseDto search(q, query, clip, type, isFavorite, isArchived, exifInfoPeriodCity, exifInfoPeriodState, exifInfoPeriodCountry, exifInfoPeriodMake, exifInfoPeriodModel, smartInfoPeriodObjects, smartInfoPeriodTags, recent, motion) +> SearchResponseDto search(q, query, clip, type, isFavorite, isArchived, exifInfoPeriodCity, exifInfoPeriodState, exifInfoPeriodCountry, exifInfoPeriodMake, exifInfoPeriodModel, exifInfoPeriodProjectionType, smartInfoPeriodObjects, smartInfoPeriodTags, recent, motion) @@ -151,13 +151,14 @@ final exifInfoPeriodState = exifInfoPeriodState_example; // String | final exifInfoPeriodCountry = exifInfoPeriodCountry_example; // String | final exifInfoPeriodMake = exifInfoPeriodMake_example; // String | final exifInfoPeriodModel = exifInfoPeriodModel_example; // String | +final exifInfoPeriodProjectionType = exifInfoPeriodProjectionType_example; // String | final smartInfoPeriodObjects = []; // List | final smartInfoPeriodTags = []; // List | final recent = true; // bool | final motion = true; // bool | try { - final result = api_instance.search(q, query, clip, type, isFavorite, isArchived, exifInfoPeriodCity, exifInfoPeriodState, exifInfoPeriodCountry, exifInfoPeriodMake, exifInfoPeriodModel, smartInfoPeriodObjects, smartInfoPeriodTags, recent, motion); + final result = api_instance.search(q, query, clip, type, isFavorite, isArchived, exifInfoPeriodCity, exifInfoPeriodState, exifInfoPeriodCountry, exifInfoPeriodMake, exifInfoPeriodModel, exifInfoPeriodProjectionType, smartInfoPeriodObjects, smartInfoPeriodTags, recent, motion); print(result); } catch (e) { print('Exception when calling SearchApi->search: $e\n'); @@ -179,6 +180,7 @@ Name | Type | Description | Notes **exifInfoPeriodCountry** | **String**| | [optional] **exifInfoPeriodMake** | **String**| | [optional] **exifInfoPeriodModel** | **String**| | [optional] + **exifInfoPeriodProjectionType** | **String**| | [optional] **smartInfoPeriodObjects** | [**List**](String.md)| | [optional] [default to const []] **smartInfoPeriodTags** | [**List**](String.md)| | [optional] [default to const []] **recent** | **bool**| | [optional] diff --git a/mobile/openapi/lib/api/search_api.dart b/mobile/openapi/lib/api/search_api.dart index 9df6c79d..8178395e 100644 --- a/mobile/openapi/lib/api/search_api.dart +++ b/mobile/openapi/lib/api/search_api.dart @@ -126,6 +126,8 @@ class SearchApi { /// /// * [String] exifInfoPeriodModel: /// + /// * [String] exifInfoPeriodProjectionType: + /// /// * [List] smartInfoPeriodObjects: /// /// * [List] smartInfoPeriodTags: @@ -133,7 +135,7 @@ class SearchApi { /// * [bool] recent: /// /// * [bool] motion: - Future searchWithHttpInfo({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List? smartInfoPeriodObjects, List? smartInfoPeriodTags, bool? recent, bool? motion, }) async { + Future searchWithHttpInfo({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, String? exifInfoPeriodProjectionType, List? smartInfoPeriodObjects, List? smartInfoPeriodTags, bool? recent, bool? motion, }) async { // ignore: prefer_const_declarations final path = r'/search'; @@ -177,6 +179,9 @@ class SearchApi { if (exifInfoPeriodModel != null) { queryParams.addAll(_queryParams('', 'exifInfo.model', exifInfoPeriodModel)); } + if (exifInfoPeriodProjectionType != null) { + queryParams.addAll(_queryParams('', 'exifInfo.projectionType', exifInfoPeriodProjectionType)); + } if (smartInfoPeriodObjects != null) { queryParams.addAll(_queryParams('multi', 'smartInfo.objects', smartInfoPeriodObjects)); } @@ -228,6 +233,8 @@ class SearchApi { /// /// * [String] exifInfoPeriodModel: /// + /// * [String] exifInfoPeriodProjectionType: + /// /// * [List] smartInfoPeriodObjects: /// /// * [List] smartInfoPeriodTags: @@ -235,8 +242,8 @@ class SearchApi { /// * [bool] recent: /// /// * [bool] motion: - Future search({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, List? smartInfoPeriodObjects, List? smartInfoPeriodTags, bool? recent, bool? motion, }) async { - final response = await searchWithHttpInfo( q: q, query: query, clip: clip, type: type, isFavorite: isFavorite, isArchived: isArchived, exifInfoPeriodCity: exifInfoPeriodCity, exifInfoPeriodState: exifInfoPeriodState, exifInfoPeriodCountry: exifInfoPeriodCountry, exifInfoPeriodMake: exifInfoPeriodMake, exifInfoPeriodModel: exifInfoPeriodModel, smartInfoPeriodObjects: smartInfoPeriodObjects, smartInfoPeriodTags: smartInfoPeriodTags, recent: recent, motion: motion, ); + Future search({ String? q, String? query, bool? clip, String? type, bool? isFavorite, bool? isArchived, String? exifInfoPeriodCity, String? exifInfoPeriodState, String? exifInfoPeriodCountry, String? exifInfoPeriodMake, String? exifInfoPeriodModel, String? exifInfoPeriodProjectionType, List? smartInfoPeriodObjects, List? smartInfoPeriodTags, bool? recent, bool? motion, }) async { + final response = await searchWithHttpInfo( q: q, query: query, clip: clip, type: type, isFavorite: isFavorite, isArchived: isArchived, exifInfoPeriodCity: exifInfoPeriodCity, exifInfoPeriodState: exifInfoPeriodState, exifInfoPeriodCountry: exifInfoPeriodCountry, exifInfoPeriodMake: exifInfoPeriodMake, exifInfoPeriodModel: exifInfoPeriodModel, exifInfoPeriodProjectionType: exifInfoPeriodProjectionType, smartInfoPeriodObjects: smartInfoPeriodObjects, smartInfoPeriodTags: smartInfoPeriodTags, recent: recent, motion: motion, ); if (response.statusCode >= HttpStatus.badRequest) { throw ApiException(response.statusCode, await _decodeBodyBytes(response)); } diff --git a/mobile/openapi/test/search_api_test.dart b/mobile/openapi/test/search_api_test.dart index a65075d1..a6bbacfa 100644 --- a/mobile/openapi/test/search_api_test.dart +++ b/mobile/openapi/test/search_api_test.dart @@ -27,7 +27,7 @@ void main() { // TODO }); - //Future search({ String q, String query, bool clip, String type, bool isFavorite, bool isArchived, String exifInfoPeriodCity, String exifInfoPeriodState, String exifInfoPeriodCountry, String exifInfoPeriodMake, String exifInfoPeriodModel, List smartInfoPeriodObjects, List smartInfoPeriodTags, bool recent, bool motion }) async + //Future search({ String q, String query, bool clip, String type, bool isFavorite, bool isArchived, String exifInfoPeriodCity, String exifInfoPeriodState, String exifInfoPeriodCountry, String exifInfoPeriodMake, String exifInfoPeriodModel, String exifInfoPeriodProjectionType, List smartInfoPeriodObjects, List smartInfoPeriodTags, bool recent, bool motion }) async test('test search', () async { // TODO }); diff --git a/server/immich-openapi-specs.json b/server/immich-openapi-specs.json index 1fc155c5..56e96bd1 100644 --- a/server/immich-openapi-specs.json +++ b/server/immich-openapi-specs.json @@ -2924,6 +2924,14 @@ "type": "string" } }, + { + "name": "exifInfo.projectionType", + "required": false, + "in": "query", + "schema": { + "type": "string" + } + }, { "name": "smartInfo.objects", "required": false, diff --git a/server/src/domain/search/dto/search.dto.ts b/server/src/domain/search/dto/search.dto.ts index 27eeb527..bb38a383 100644 --- a/server/src/domain/search/dto/search.dto.ts +++ b/server/src/domain/search/dto/search.dto.ts @@ -58,6 +58,11 @@ export class SearchDto { @IsOptional() 'exifInfo.model'?: string; + @IsString() + @IsNotEmpty() + @IsOptional() + 'exifInfo.projectionType'?: string; + @IsString({ each: true }) @IsArray() @IsOptional() diff --git a/server/src/infra/typesense-schemas/asset.schema.ts b/server/src/infra/typesense-schemas/asset.schema.ts index 5d31e67b..53729c07 100644 --- a/server/src/infra/typesense-schemas/asset.schema.ts +++ b/server/src/infra/typesense-schemas/asset.schema.ts @@ -1,6 +1,6 @@ import { CollectionCreateSchema } from 'typesense/lib/Typesense/Collections'; -export const assetSchemaVersion = 7; +export const assetSchemaVersion = 8; export const assetSchema: CollectionCreateSchema = { name: `assets-v${assetSchemaVersion}`, fields: [ @@ -23,6 +23,7 @@ export const assetSchema: CollectionCreateSchema = { { name: 'exifInfo.make', type: 'string', facet: true, optional: true }, { name: 'exifInfo.model', type: 'string', facet: true, optional: true }, { name: 'exifInfo.orientation', type: 'string', optional: true }, + { name: 'exifInfo.projectionType', type: 'string', facet: true, optional: true }, // smart info { name: 'smartInfo.objects', type: 'string[]', facet: true, optional: true }, diff --git a/web/src/api/open-api/api.ts b/web/src/api/open-api/api.ts index 02d3b414..e42b66cc 100644 --- a/web/src/api/open-api/api.ts +++ b/web/src/api/open-api/api.ts @@ -9535,6 +9535,7 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio * @param {string} [exifInfoCountry] * @param {string} [exifInfoMake] * @param {string} [exifInfoModel] + * @param {string} [exifInfoProjectionType] * @param {Array} [smartInfoObjects] * @param {Array} [smartInfoTags] * @param {boolean} [recent] @@ -9542,7 +9543,7 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio * @param {*} [options] Override http request option. * @throws {RequiredError} */ - search: async (q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options: AxiosRequestConfig = {}): Promise => { + search: async (q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, exifInfoProjectionType?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options: AxiosRequestConfig = {}): Promise => { const localVarPath = `/search`; // use dummy base URL string because the URL constructor only accepts absolute URLs. const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL); @@ -9608,6 +9609,10 @@ export const SearchApiAxiosParamCreator = function (configuration?: Configuratio localVarQueryParameter['exifInfo.model'] = exifInfoModel; } + if (exifInfoProjectionType !== undefined) { + localVarQueryParameter['exifInfo.projectionType'] = exifInfoProjectionType; + } + if (smartInfoObjects) { localVarQueryParameter['smartInfo.objects'] = smartInfoObjects; } @@ -9676,6 +9681,7 @@ export const SearchApiFp = function(configuration?: Configuration) { * @param {string} [exifInfoCountry] * @param {string} [exifInfoMake] * @param {string} [exifInfoModel] + * @param {string} [exifInfoProjectionType] * @param {Array} [smartInfoObjects] * @param {Array} [smartInfoTags] * @param {boolean} [recent] @@ -9683,8 +9689,8 @@ export const SearchApiFp = function(configuration?: Configuration) { * @param {*} [options] Override http request option. * @throws {RequiredError} */ - async search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { - const localVarAxiosArgs = await localVarAxiosParamCreator.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, smartInfoObjects, smartInfoTags, recent, motion, options); + async search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, exifInfoProjectionType?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: AxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise> { + const localVarAxiosArgs = await localVarAxiosParamCreator.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, exifInfoProjectionType, smartInfoObjects, smartInfoTags, recent, motion, options); return createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration); }, } @@ -9726,6 +9732,7 @@ export const SearchApiFactory = function (configuration?: Configuration, basePat * @param {string} [exifInfoCountry] * @param {string} [exifInfoMake] * @param {string} [exifInfoModel] + * @param {string} [exifInfoProjectionType] * @param {Array} [smartInfoObjects] * @param {Array} [smartInfoTags] * @param {boolean} [recent] @@ -9733,8 +9740,8 @@ export const SearchApiFactory = function (configuration?: Configuration, basePat * @param {*} [options] Override http request option. * @throws {RequiredError} */ - search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: any): AxiosPromise { - return localVarFp.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, smartInfoObjects, smartInfoTags, recent, motion, options).then((request) => request(axios, basePath)); + search(q?: string, query?: string, clip?: boolean, type?: 'IMAGE' | 'VIDEO' | 'AUDIO' | 'OTHER', isFavorite?: boolean, isArchived?: boolean, exifInfoCity?: string, exifInfoState?: string, exifInfoCountry?: string, exifInfoMake?: string, exifInfoModel?: string, exifInfoProjectionType?: string, smartInfoObjects?: Array, smartInfoTags?: Array, recent?: boolean, motion?: boolean, options?: any): AxiosPromise { + return localVarFp.search(q, query, clip, type, isFavorite, isArchived, exifInfoCity, exifInfoState, exifInfoCountry, exifInfoMake, exifInfoModel, exifInfoProjectionType, smartInfoObjects, smartInfoTags, recent, motion, options).then((request) => request(axios, basePath)); }, }; }; @@ -9822,6 +9829,13 @@ export interface SearchApiSearchRequest { */ readonly exifInfoModel?: string + /** + * + * @type {string} + * @memberof SearchApiSearch + */ + readonly exifInfoProjectionType?: string + /** * * @type {Array} @@ -9886,7 +9900,7 @@ export class SearchApi extends BaseAPI { * @memberof SearchApi */ public search(requestParameters: SearchApiSearchRequest = {}, options?: AxiosRequestConfig) { - return SearchApiFp(this.configuration).search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(this.axios, this.basePath)); + return SearchApiFp(this.configuration).search(requestParameters.q, requestParameters.query, requestParameters.clip, requestParameters.type, requestParameters.isFavorite, requestParameters.isArchived, requestParameters.exifInfoCity, requestParameters.exifInfoState, requestParameters.exifInfoCountry, requestParameters.exifInfoMake, requestParameters.exifInfoModel, requestParameters.exifInfoProjectionType, requestParameters.smartInfoObjects, requestParameters.smartInfoTags, requestParameters.recent, requestParameters.motion, options).then((request) => request(this.axios, this.basePath)); } } diff --git a/web/src/routes/(user)/explore/+page.svelte b/web/src/routes/(user)/explore/+page.svelte index 3972bbb4..cdedb2d1 100644 --- a/web/src/routes/(user)/explore/+page.svelte +++ b/web/src/routes/(user)/explore/+page.svelte @@ -8,6 +8,7 @@ import HeartMultipleOutline from 'svelte-material-icons/HeartMultipleOutline.svelte'; import MotionPlayOutline from 'svelte-material-icons/MotionPlayOutline.svelte'; import PlayCircleOutline from 'svelte-material-icons/PlayCircleOutline.svelte'; + import Rotate360Icon from 'svelte-material-icons/Rotate360.svelte'; import type { PageData } from './$types'; export let data: PageData; @@ -149,6 +150,15 @@ Motion photos +