Skip to content

Commit

Permalink
Merge pull request #707 from bpatrik/photo-groupping
Browse files Browse the repository at this point in the history
Photo groupping #706
  • Loading branch information
bpatrik authored Aug 30, 2023
2 parents a3ec587 + 6de2aee commit ad0cbed
Show file tree
Hide file tree
Showing 44 changed files with 1,349 additions and 730 deletions.
4 changes: 2 additions & 2 deletions src/backend/middlewares/GalleryMWs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {SearchQueryDTO, SearchQueryTypes,} from '../../common/entities/SearchQue
import {LocationLookupException} from '../exceptions/LocationLookupException';
import {SupportedFormats} from '../../common/SupportedFormats';
import {ServerTime} from './ServerTimingMWs';
import {SortingMethods} from '../../common/entities/SortingMethods';
import {SortByTypes} from '../../common/entities/SortingMethods';

export class GalleryMWs {
@ServerTime('1.db', 'List Directory')
Expand Down Expand Up @@ -322,7 +322,7 @@ export class GalleryMWs {
);

const photos =
await ObjectManagers.getInstance().SearchManager.getNMedia(query, [SortingMethods.random], 1, true);
await ObjectManagers.getInstance().SearchManager.getNMedia(query, [{method: SortByTypes.Random, ascending: null}], 1, true);
if (!photos || photos.length !== 1) {
return next(new ErrorDTO(ErrorCodes.INPUT_ERROR, 'No photo found'));
}
Expand Down
35 changes: 4 additions & 31 deletions src/backend/model/database/CoverManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {MediaEntity} from './enitites/MediaEntity';
import {DiskMangerWorker} from '../threading/DiskMangerWorker';
import {ObjectManagers} from '../ObjectManagers';
import {DatabaseType} from '../../../common/config/private/PrivateConfig';
import {SortingMethods} from '../../../common/entities/SortingMethods';
import {SortingMethod} from '../../../common/entities/SortingMethods';

Check warning on line 7 in src/backend/model/database/CoverManager.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

'SortingMethod' is defined but never used
import {SQLConnection} from './SQLConnection';
import {SearchQueryDTO, SearchQueryTypes, TextSearch,} from '../../../common/entities/SearchQueryDTO';
import {DirectoryEntity} from './enitites/DirectoryEntity';
Expand All @@ -14,6 +14,7 @@ import {Utils} from '../../../common/Utils';
import {CoverPhotoDTO} from '../../../common/entities/PhotoDTO';
import {IObjectManager} from './IObjectManager';
import {Logger} from '../../Logger';
import {SearchManager} from './SearchManager';

const LOG_TAG = '[CoverManager]';

Check warning on line 19 in src/backend/model/database/CoverManager.ts

View workflow job for this annotation

GitHub Actions / test (18.x)

'LOG_TAG' is assigned a value but never used

Expand All @@ -25,34 +26,6 @@ export interface CoverPhotoDTOWithID extends CoverPhotoDTO {
export class CoverManager implements IObjectManager {
private static DIRECTORY_SELECT = ['directory.name', 'directory.path'];

private static setSorting<T>(
query: SelectQueryBuilder<T>
): SelectQueryBuilder<T> {
for (const sort of Config.AlbumCover.Sorting) {
switch (sort) {
case SortingMethods.descDate:
query.addOrderBy('media.metadata.creationDate', 'DESC');
break;
case SortingMethods.ascDate:
query.addOrderBy('media.metadata.creationDate', 'ASC');
break;
case SortingMethods.descRating:
query.addOrderBy('media.metadata.rating', 'DESC');
break;
case SortingMethods.ascRating:
query.addOrderBy('media.metadata.rating', 'ASC');
break;
case SortingMethods.descName:
query.addOrderBy('media.name', 'DESC');
break;
case SortingMethods.ascName:
query.addOrderBy('media.name', 'ASC');
break;
}
}

return query;
}

public async resetCovers(): Promise<void> {
const connection = await SQLConnection.getConnection();
Expand Down Expand Up @@ -119,7 +92,7 @@ export class CoverManager implements IObjectManager {
.innerJoin('media.directory', 'directory')
.select(['media.name', 'media.id', ...CoverManager.DIRECTORY_SELECT])
.where(albumQuery);
CoverManager.setSorting(query);
SearchManager.setSorting(query, Config.AlbumCover.Sorting);
return query;
};
let coverMedia = null;
Expand Down Expand Up @@ -201,7 +174,7 @@ export class CoverManager implements IObjectManager {
'ASC'
);

CoverManager.setSorting(query);
SearchManager.setSorting(query, Config.AlbumCover.Sorting);
return query;
};

Expand Down
50 changes: 20 additions & 30 deletions src/backend/model/database/SearchManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,11 @@ import {
DatePatternFrequency,
DatePatternSearch,
DistanceSearch,
FromDateSearch, MaxPersonCountSearch,
FromDateSearch,
MaxPersonCountSearch,
MaxRatingSearch,
MaxResolutionSearch, MinPersonCountSearch,
MaxResolutionSearch,
MinPersonCountSearch,
MinRatingSearch,
MinResolutionSearch,
OrientationSearch,
Expand All @@ -34,7 +36,7 @@ import {DatabaseType} from '../../../common/config/private/PrivateConfig';
import {Utils} from '../../../common/Utils';
import {FileEntity} from './enitites/FileEntity';
import {SQL_COLLATE} from './enitites/EntityUtils';
import {SortingMethods} from '../../../common/entities/SortingMethods';
import {GroupSortByTypes, SortByTypes, SortingMethod} from '../../../common/entities/SortingMethods';

export class SearchManager {
private DIRECTORY_SELECT = [
Expand Down Expand Up @@ -349,43 +351,31 @@ export class SearchManager {
}


private static setSorting<T>(
public static setSorting<T>(
query: SelectQueryBuilder<T>,
sortings: SortingMethods[]
sortings: SortingMethod[]
): SelectQueryBuilder<T> {
if (!sortings || !Array.isArray(sortings)) {
return query;
}
if (sortings.includes(SortingMethods.random) && sortings.length > 1) {
throw new Error('Error during applying sorting: Can\' randomize and also sort the result. Bad input:' + sortings.map(s => SortingMethods[s]).join(', '));
if (sortings.findIndex(s => s.method == SortByTypes.Random) !== -1 && sortings.length > 1) {
throw new Error('Error during applying sorting: Can\' randomize and also sort the result. Bad input:' + sortings.map(s => GroupSortByTypes[s.method]).join(', '));
}
for (const sort of sortings) {
switch (sort) {
case SortingMethods.descDate:
query.addOrderBy('media.metadata.creationDate', 'DESC');
switch (sort.method) {
case SortByTypes.Date:
query.addOrderBy('media.metadata.creationDate', sort.ascending ? 'ASC' : 'DESC');
break;
case SortingMethods.ascDate:
query.addOrderBy('media.metadata.creationDate', 'ASC');
case SortByTypes.Rating:
query.addOrderBy('media.metadata.rating', sort.ascending ? 'ASC' : 'DESC');
break;
case SortingMethods.descRating:
query.addOrderBy('media.metadata.rating', 'DESC');
case SortByTypes.Name:
query.addOrderBy('media.name', sort.ascending ? 'ASC' : 'DESC');
break;
case SortingMethods.ascRating:
query.addOrderBy('media.metadata.rating', 'ASC');
case SortByTypes.PersonCount:
query.addOrderBy('media.metadata.personsLength', sort.ascending ? 'ASC' : 'DESC');
break;
case SortingMethods.descName:
query.addOrderBy('media.name', 'DESC');
break;
case SortingMethods.ascName:
query.addOrderBy('media.name', 'ASC');
break;
case SortingMethods.descPersonCount:
query.addOrderBy('media.metadata.personsLength', 'DESC');
break;
case SortingMethods.ascPersonCount:
query.addOrderBy('media.metadata.personsLength', 'ASC');
break;
case SortingMethods.random:
case SortByTypes.Random:
if (Config.Database.type === DatabaseType.mysql) {
query.groupBy('RAND(), media.id');
} else {
Expand All @@ -398,7 +388,7 @@ export class SearchManager {
return query;
}

public async getNMedia(query: SearchQueryDTO, sortings: SortingMethods[], take: number, photoOnly = false) {
public async getNMedia(query: SearchQueryDTO, sortings: SortingMethod[], take: number, photoOnly = false) {
const connection = await SQLConnection.getConnection();
const sqlQuery: SelectQueryBuilder<PhotoEntity> = connection
.getRepository(photoOnly ? PhotoEntity : MediaEntity)
Expand Down
5 changes: 3 additions & 2 deletions src/backend/model/jobs/jobs/TopPickSendJob.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import {ConfigTemplateEntry, DefaultsJobs,} from '../../../../common/entities/job/JobDTO';
import {Job} from './Job';
import {backendTexts} from '../../../../common/BackendTexts';
import {SortingMethods} from '../../../../common/entities/SortingMethods';
import {SortByTypes} from '../../../../common/entities/SortingMethods';
import {DatePatternFrequency, DatePatternSearch, SearchQueryTypes} from '../../../../common/entities/SearchQueryDTO';
import {ObjectManagers} from '../../ObjectManagers';
import {PhotoEntity} from '../../database/enitites/PhotoEntity';
Expand Down Expand Up @@ -30,7 +30,8 @@ export class TopPickSendJob extends Job<{
daysLength: 7,
frequency: DatePatternFrequency.every_year
} as DatePatternSearch,
sortBy: [SortingMethods.descRating, SortingMethods.descPersonCount],
sortBy: [{method: SortByTypes.Rating, ascending: false},
{method: SortByTypes.PersonCount, ascending: false}],
pick: 5
}] as MediaPickDTO[],
}, {
Expand Down
26 changes: 13 additions & 13 deletions src/common/PG2ConfMap.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import {SortingMethods} from './entities/SortingMethods';
import {SortByDirectionalTypes, SortByTypes, SortingMethod} from './entities/SortingMethods';
import {Utils} from './Utils';

/**
* This contains the action of the supported list of *.pg2conf files.
* These files are passed down to the client as metaFiles (like photos and directories)
*/
export const PG2ConfMap = {
sorting: {
'.order_descending_name.pg2conf': SortingMethods.descName,
'.order_ascending_name.pg2conf': SortingMethods.ascName,
'.order_descending_date.pg2conf': SortingMethods.descDate,
'.order_ascending_date.pg2conf': SortingMethods.ascDate,
'.order_descending_rating.pg2conf': SortingMethods.descRating,
'.order_ascending_rating.pg2conf': SortingMethods.ascRating,
'.order_random.pg2conf': SortingMethods.random,
'.order_descending_person_count.pg2conf': SortingMethods.descPersonCount,
'.order_ascending_person_count.pg2conf': SortingMethods.descPersonCount,
},
export const PG2ConfMap: { sorting: { [key: string]: SortingMethod } } = {
sorting: {}
};

Utils.enumToArray(SortByTypes).forEach(kv => {
if (!Utils.isValidEnumInt(SortByDirectionalTypes, kv.key)) {
PG2ConfMap.sorting['.order_random.pg2conf'] = {method: kv.key, ascending: null} as SortingMethod;
return;
}
PG2ConfMap.sorting['.order_descending' + kv.value.toLowerCase() + '.pg2conf'] = {method: kv.key, ascending: false} as SortingMethod;
PG2ConfMap.sorting['.order_ascending' + kv.value.toLowerCase() + '.pg2conf'] = {method: kv.key, ascending: true} as SortingMethod;
});

/**
* These files are processed on the server side,
* do not get passed down to the client or saved to the DB
Expand Down
4 changes: 4 additions & 0 deletions src/common/Utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,10 @@ export class Utils {
});
}

public static isValidEnumInt(EnumType: any, value: number) {
return typeof EnumType[value] === 'string';
}

public static enumToArray(EnumType: any): { key: number; value: string }[] {
const arr: Array<{ key: number; value: string }> = [];
for (const enumMember in EnumType) {
Expand Down
13 changes: 7 additions & 6 deletions src/common/config/private/PrivateConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
ClientPhotoConvertingConfig,
ClientServiceConfig,
ClientSharingConfig,
ClientSortingConfig,
ClientThumbnailConfig,
ClientUserConfig,
ClientVideoConfig,
Expand All @@ -28,7 +29,7 @@ import {SubConfigClass} from 'typeconfig/src/decorators/class/SubConfigClass';
import {ConfigProperty} from 'typeconfig/src/decorators/property/ConfigPropoerty';
import {DefaultsJobs} from '../../entities/job/JobDTO';
import {SearchQueryDTO, SearchQueryTypes, TextSearch,} from '../../entities/SearchQueryDTO';
import {SortingMethods} from '../../entities/SortingMethods';
import {SortByTypes} from '../../entities/SortingMethods';
import {UserRoles} from '../../entities/UserDTO';
import {MediaPickDTO} from '../../entities/MediaPickDTO';
import {MessagingConfig} from './MessagingConfig';
Expand Down Expand Up @@ -888,18 +889,18 @@ export class ServerAlbumCoverConfig {
text: '',
} as TextSearch;
@ConfigProperty({
arrayType: SortingMethods,
arrayType: ClientSortingConfig,
tags: {
name: $localize`Cover Sorting`,
uiResetNeeded: {db: true},
priority: ConfigPriority.advanced
},
description: $localize`If multiple cover is available sorts them by these methods and selects the first one.`,
})
Sorting: SortingMethods[] = [
SortingMethods.descRating,
SortingMethods.descDate,
SortingMethods.descPersonCount,
Sorting: ClientSortingConfig[] = [
new ClientSortingConfig(SortByTypes.Rating, false),
new ClientSortingConfig(SortByTypes.Date, false),
new ClientSortingConfig(SortByTypes.PersonCount, false)
];
}

Expand Down
Loading

0 comments on commit ad0cbed

Please sign in to comment.