1
0
mirror of https://github.com/bpatrik/pigallery2.git synced 2024-12-10 11:10:35 +02:00

Implementing listing metafiles in search result

This commit is contained in:
Patrik J. Braun 2021-06-19 11:20:40 +02:00
parent 57ac433c46
commit 3541eae141
18 changed files with 193 additions and 86 deletions

6
package-lock.json generated
View File

@ -14296,7 +14296,8 @@
}, },
"lodash": { "lodash": {
"version": "4.17.20", "version": "4.17.20",
"resolved": "", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz",
"integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==",
"dev": true "dev": true
}, },
"minimist": { "minimist": {
@ -21616,7 +21617,8 @@
}, },
"y18n": { "y18n": {
"version": "3.2.1", "version": "3.2.1",
"resolved": "", "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
"integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
"dev": true "dev": true
}, },
"yallist": { "yallist": {

View File

@ -33,6 +33,7 @@ import {ISQLGalleryManager} from './IGalleryManager';
import {ISQLSearchManager} from './ISearchManager'; import {ISQLSearchManager} from './ISearchManager';
import {MediaDTO} from '../../../../common/entities/MediaDTO'; import {MediaDTO} from '../../../../common/entities/MediaDTO';
import {Utils} from '../../../../common/Utils'; import {Utils} from '../../../../common/Utils';
import {FileEntity} from './enitites/FileEntity';
export class SearchManager implements ISQLSearchManager { export class SearchManager implements ISQLSearchManager {
@ -156,13 +157,15 @@ export class SearchManager implements ISQLSearchManager {
const facesQuery = Config.Server.Database.type === DatabaseType.mysql ? const facesQuery = Config.Server.Database.type === DatabaseType.mysql ?
'CONCAT(\'[\' , GROUP_CONCAT( \'{"name": "\' , person.name , \'", "box": {"top":\' , faces.box.top , \', "left":\' , faces.box.left , \', "height":\' , faces.box.height ,\', "width":\' , faces.box.width , \'}}\' ) ,\']\') as media_metadataFaces' : 'CONCAT(\'[\' , GROUP_CONCAT( \'{"name": "\' , person.name , \'", "box": {"top":\' , faces.box.top , \', "left":\' , faces.box.left , \', "height":\' , faces.box.height ,\', "width":\' , faces.box.width , \'}}\' ) ,\']\') as media_metadataFaces' :
'\'[\' || GROUP_CONCAT( \'{"name": "\' || person.name || \'", "box": {"top":\' || faces.box.top || \', "left":\' || faces.box.left || \', "height":\' || faces.box.height ||\', "width":\' || faces.box.width || \'}}\' ) ||\']\' as media_metadataFaces'; '\'[\' || GROUP_CONCAT( \'{"name": "\' || person.name || \'", "box": {"top":\' || faces.box.top || \', "left":\' || faces.box.left || \', "height":\' || faces.box.height ||\', "width":\' || faces.box.width || \'}}\' ) ||\']\' as media_metadataFaces';
const directorySelect = ['directory.id', 'directory.name', 'directory.path'];
const rawAndEntries = await connection const rawAndEntries = await connection
.getRepository(MediaEntity) .getRepository(MediaEntity)
.createQueryBuilder('media') .createQueryBuilder('media')
.select(['media', facesQuery]) .select(['media', ...directorySelect, facesQuery])
.where(this.buildWhereQuery(query)) .where(this.buildWhereQuery(query))
.leftJoinAndSelect('media.directory', 'directory') .leftJoin('media.directory', 'directory')
.leftJoin('media.metadata.faces', 'faces') .leftJoin('media.metadata.faces', 'faces')
.leftJoin('faces.person', 'person') .leftJoin('faces.person', 'person')
.limit(Config.Client.Search.maxMediaResult + 1) .limit(Config.Client.Search.maxMediaResult + 1)
@ -181,6 +184,20 @@ export class SearchManager implements ISQLSearchManager {
result.resultOverflow = true; result.resultOverflow = true;
} }
if (Config.Client.Search.listMetafiles === true) {
result.metaFile = await connection.getRepository(FileEntity)
.createQueryBuilder('file')
.select(['file', ...directorySelect])
.innerJoin(q => q.from(MediaEntity, 'media')
.select('distinct directory.id')
.where(this.buildWhereQuery(query))
.leftJoin('media.directory', 'directory'),
'dir',
'file.directory=dir.id')
.leftJoin('file.directory', 'directory')
.getMany();
}
if (Config.Client.Search.listDirectories === true) { if (Config.Client.Search.listDirectories === true) {
const dirQuery = this.filterDirectoryQuery(query); const dirQuery = this.filterDirectoryQuery(query);
if (dirQuery !== null) { if (dirQuery !== null) {

View File

@ -1,10 +1,10 @@
import {Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance, Unique, ValueTransformer} from 'typeorm'; import {Column, Entity, Index, ManyToOne, OneToMany, PrimaryGeneratedColumn, TableInheritance, Unique} from 'typeorm';
import {DirectoryEntity} from './DirectoryEntity'; import {DirectoryEntity} from './DirectoryEntity';
import {MediaDimension, MediaDTO, MediaMetadata} from '../../../../../common/entities/MediaDTO'; import {MediaDimension, MediaDTO, MediaMetadata} from '../../../../../common/entities/MediaDTO';
import {OrientationTypes} from 'ts-exif-parser'; import {OrientationTypes} from 'ts-exif-parser';
import {CameraMetadataEntity, PositionMetaDataEntity} from './PhotoEntity';
import {FaceRegionEntry} from './FaceRegionEntry'; import {FaceRegionEntry} from './FaceRegionEntry';
import {columnCharsetCS} from './EntityUtils'; import {columnCharsetCS} from './EntityUtils';
import {CameraMetadata, GPSMetadata, PositionMetaData} from '../../../../../common/entities/PhotoDTO';
export class MediaDimensionEntity implements MediaDimension { export class MediaDimensionEntity implements MediaDimension {
@ -16,6 +16,80 @@ export class MediaDimensionEntity implements MediaDimension {
} }
export class CameraMetadataEntity implements CameraMetadata {
@Column('int', {nullable: true, unsigned: true})
ISO: number;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
model: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
make: string;
@Column('float', {nullable: true})
fStop: number;
@Column('float', {nullable: true})
exposure: number;
@Column('float', {nullable: true})
focalLength: number;
@Column('text', {nullable: true})
lens: string;
}
export class GPSMetadataEntity implements GPSMetadata {
@Column('float', {nullable: true})
latitude: number;
@Column('float', {nullable: true})
longitude: number;
@Column('int', {nullable: true})
altitude: number;
}
export class PositionMetaDataEntity implements PositionMetaData {
@Column(type => GPSMetadataEntity)
GPSData: GPSMetadataEntity;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
country: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
state: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
city: string;
}
export class MediaMetadataEntity implements MediaMetadata { export class MediaMetadataEntity implements MediaMetadata {
@Column('text') @Column('text')
caption: string; caption: string;

View File

@ -3,78 +3,7 @@ import {CameraMetadata, GPSMetadata, PhotoDTO, PhotoMetadata, PositionMetaData}
import {MediaEntity, MediaMetadataEntity} from './MediaEntity'; import {MediaEntity, MediaMetadataEntity} from './MediaEntity';
import {columnCharsetCS} from './EntityUtils'; import {columnCharsetCS} from './EntityUtils';
export class CameraMetadataEntity implements CameraMetadata {
@Column('int', {nullable: true, unsigned: true})
ISO: number;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
model: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
make: string;
@Column('float', {nullable: true})
fStop: number;
@Column('float', {nullable: true})
exposure: number;
@Column('float', {nullable: true})
focalLength: number;
@Column('text', {nullable: true})
lens: string;
}
export class GPSMetadataEntity implements GPSMetadata {
@Column('float', {nullable: true})
latitude: number;
@Column('float', {nullable: true})
longitude: number;
@Column('int', {nullable: true})
altitude: number;
}
export class PositionMetaDataEntity implements PositionMetaData {
@Column(type => GPSMetadataEntity)
GPSData: GPSMetadataEntity;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
country: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
state: string;
@Column({
type: 'text', nullable: true,
charset: columnCharsetCS.charset,
collation: columnCharsetCS.collation
})
city: string;
}
export class PhotoMetadataEntity extends MediaMetadataEntity implements PhotoMetadata { export class PhotoMetadataEntity extends MediaMetadataEntity implements PhotoMetadata {

View File

@ -31,6 +31,10 @@ export class ClientSearchConfig {
maxMediaResult: number = 10000; maxMediaResult: number = 10000;
@ConfigProperty({description: 'Search returns also with directories, not just media'}) @ConfigProperty({description: 'Search returns also with directories, not just media'})
listDirectories: boolean = false; listDirectories: boolean = false;
@ConfigProperty({
description: 'Search also returns with metafiles from directories that contain a media file of the matched search result'
})
listMetafiles: boolean = false;
@ConfigProperty({type: 'unsignedInt'}) @ConfigProperty({type: 'unsignedInt'})
maxDirectoryResult: number = 200; maxDirectoryResult: number = 200;
} }

View File

@ -52,6 +52,14 @@
[simplifiedMode]="simplifiedMode"> [simplifiedMode]="simplifiedMode">
</app-settings-entry> </app-settings-entry>
<app-settings-entry
name="List metafiles"
description="Search also returns with metafiles from directories that contain a media file of the matched search result"
i18n-description i18n-name
[ngModel]="states.listMetafiles"
[simplifiedMode]="simplifiedMode">
</app-settings-entry>
</ng-container> </ng-container>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Megjeleníti az Album fület a felső sávban és engedélyezi a mentett keresések létrehozásást</target> <target>Megjeleníti az Album fület a felső sávban és engedélyezi a mentett keresések létrehozásást</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>Metafájlok listázása</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>A kersési eredmény tartalmazza azokat a metaffájlkoat is, amelyek egy mappában vannak a keresett képpel/videóval.</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -2828,6 +2828,14 @@
<source>Shows albums tab in the top bar and enables creating saved searches.</source> <source>Shows albums tab in the top bar and enables creating saved searches.</source>
<target>Shows albums tab in the top bar and enables creating saved searches.</target> <target>Shows albums tab in the top bar and enables creating saved searches.</target>
</trans-unit> </trans-unit>
<trans-unit id="709142926386769059" datatype="html">
<source>List metafiles</source>
<target>List metafiles</target>
</trans-unit>
<trans-unit id="500999559591740527" datatype="html">
<source>Search also returns with metafiles from directories that contain a media file of the matched search result</source>
<target>Search also returns with metafiles from directories that contain a media file of the matched search result</target>
</trans-unit>
</body> </body>
</file> </file>
</xliff> </xliff>

View File

@ -7,16 +7,15 @@ import {UserEntity} from '../../../../../src/backend/model/database/sql/enitites
import {UserRoles} from '../../../../../src/common/entities/UserDTO'; import {UserRoles} from '../../../../../src/common/entities/UserDTO';
import {PasswordHelper} from '../../../../../src/backend/model/PasswordHelper'; import {PasswordHelper} from '../../../../../src/backend/model/PasswordHelper';
import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity'; import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity';
import {PhotoEntity, PhotoMetadataEntity} from '../../../../../src/backend/model/database/sql/enitites/PhotoEntity';
import { import {
CameraMetadataEntity, CameraMetadataEntity,
GPSMetadataEntity, GPSMetadataEntity,
PhotoEntity, MediaDimensionEntity,
PhotoMetadataEntity,
PositionMetaDataEntity PositionMetaDataEntity
} from '../../../../../src/backend/model/database/sql/enitites/PhotoEntity'; } from '../../../../../src/backend/model/database/sql/enitites/MediaEntity';
import {MediaDimensionEntity} from '../../../../../src/backend/model/database/sql/enitites/MediaEntity';
import {VersionEntity} from '../../../../../src/backend/model/database/sql/enitites/VersionEntity'; import {VersionEntity} from '../../../../../src/backend/model/database/sql/enitites/VersionEntity';
import {DatabaseType, ServerConfig} from '../../../../../src/common/config/private/PrivateConfig'; import {DatabaseType} from '../../../../../src/common/config/private/PrivateConfig';
import {ProjectPath} from '../../../../../src/backend/ProjectPath'; import {ProjectPath} from '../../../../../src/backend/ProjectPath';

View File

@ -200,6 +200,9 @@ describe('SearchManager', (sqlHelper: DBTestHelper) => {
delete m.directory.preview; delete m.directory.preview;
delete m.directory.metaFile; delete m.directory.metaFile;
const ret = Utils.clone(m); const ret = Utils.clone(m);
delete ret.directory.lastScanned;
delete ret.directory.lastModified;
delete ret.directory.mediaCount;
if ((ret.metadata as PhotoMetadata).faces && !(ret.metadata as PhotoMetadata).faces.length) { if ((ret.metadata as PhotoMetadata).faces && !(ret.metadata as PhotoMetadata).faces.length) {
delete (ret.metadata as PhotoMetadata).faces; delete (ret.metadata as PhotoMetadata).faces;
} }

View File

@ -1,11 +1,10 @@
import {MediaDimensionEntity} from '../../../../../src/backend/model/database/sql/enitites/MediaEntity';
import { import {
CameraMetadataEntity, CameraMetadataEntity,
GPSMetadataEntity, GPSMetadataEntity,
PhotoEntity, MediaDimensionEntity,
PhotoMetadataEntity,
PositionMetaDataEntity PositionMetaDataEntity
} from '../../../../../src/backend/model/database/sql/enitites/PhotoEntity'; } from '../../../../../src/backend/model/database/sql/enitites/MediaEntity';
import {PhotoEntity, PhotoMetadataEntity} from '../../../../../src/backend/model/database/sql/enitites/PhotoEntity';
import {OrientationTypes} from 'ts-exif-parser'; import {OrientationTypes} from 'ts-exif-parser';
import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity'; import {DirectoryEntity} from '../../../../../src/backend/model/database/sql/enitites/DirectoryEntity';
import {VideoEntity, VideoMetadataEntity} from '../../../../../src/backend/model/database/sql/enitites/VideoEntity'; import {VideoEntity, VideoMetadataEntity} from '../../../../../src/backend/model/database/sql/enitites/VideoEntity';