diff --git a/backend/model/sql/GalleryManager.ts b/backend/model/sql/GalleryManager.ts index 937a4a28..5bfe15d2 100644 --- a/backend/model/sql/GalleryManager.ts +++ b/backend/model/sql/GalleryManager.ts @@ -36,7 +36,7 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager { .getOne(); - if (dir && dir.scanned == true) { + if (dir && dir.lastScanned == null) { //If it seems that the content did not changed, do not work on it if (knownLastModified && knownLastScanned && lastModified == knownLastModified && @@ -73,7 +73,6 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager { for (let j = 0; j < dir.directories[i].photos.length; j++) { dir.directories[i].photos[j].directory = dir.directories[i]; - // PhotoMetadataEntity.open(dir.directories[i].photos[j].metadata); dir.directories[i].photos[j].readyThumbnails = []; dir.directories[i].photos[j].readyIcon = false; } @@ -102,124 +101,127 @@ export class GalleryManager implements IGalleryManager, ISQLGalleryManager { } + public indexDirectory(relativeDirectoryName): Promise { return new Promise(async (resolve, reject) => { try { const scannedDirectory = await DiskManager.scanDirectory(relativeDirectoryName); - const connection = await SQLConnection.getConnection(); //returning with the result scannedDirectory.photos.forEach(p => p.readyThumbnails = []); resolve(scannedDirectory); - //saving to db - let directoryRepository = connection.getRepository(DirectoryEntity); - let photosRepository = connection.getRepository(PhotoEntity); - - - let parentDir = await directoryRepository.createQueryBuilder("directory") - .where("directory.name = :name AND directory.path = :path", { - name: scannedDirectory.name, - path: scannedDirectory.path - }).getOne(); - - if (!!parentDir) {//Updated parent dir (if it was in the DB previously) - parentDir.scanned = true; - parentDir.lastModified = scannedDirectory.lastModified; - parentDir.lastScanned = scannedDirectory.lastScanned; - parentDir = await directoryRepository.save(parentDir); - } else { - (scannedDirectory).scanned = true; - parentDir = await directoryRepository.save(scannedDirectory); - } - - let indexedDirectories = await directoryRepository.createQueryBuilder("directory") - .where("directory.parent = :dir", { - dir: parentDir.id - }).getMany(); - - for (let i = 0; i < scannedDirectory.directories.length; i++) { - - //Was this child Dir already indexed before? - let directory: DirectoryEntity = null; - for (let j = 0; j < indexedDirectories.length; j++) { - if (indexedDirectories[j].name == scannedDirectory.directories[i].name) { - directory = indexedDirectories[j]; - indexedDirectories.splice(j, 1); - break; - } - } - - if (directory != null) { //update existing directory - if (!directory.parent && !directory.parent.id) { - directory.parent = parentDir; - delete directory.photos; - await directoryRepository.save(directory); - } - } else { - scannedDirectory.directories[i].parent = parentDir; - (scannedDirectory.directories[i]).scanned = false; - const d = await directoryRepository.save(scannedDirectory.directories[i]); - for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) { - // PhotoMetadataEntity.close(scannedDirectory.directories[i].photos[j].metadata); - scannedDirectory.directories[i].photos[j].directory = d; - } - - await photosRepository.save(scannedDirectory.directories[i].photos); - } - } - - //Remove child Dirs that are not anymore in the parent dir - await directoryRepository.remove(indexedDirectories); - - - let indexedPhotos = await photosRepository.createQueryBuilder("photo") - .where("photo.directory = :dir", { - dir: parentDir.id - }).getMany(); - - - let photosToSave = []; - for (let i = 0; i < scannedDirectory.photos.length; i++) { - let photo = null; - for (let j = 0; j < indexedPhotos.length; j++) { - if (indexedPhotos[j].name == scannedDirectory.photos[i].name) { - photo = indexedPhotos[j]; - indexedPhotos.splice(j, 1); - break; - } - } - if (photo == null) { - scannedDirectory.photos[i].directory = null; - photo = Utils.clone(scannedDirectory.photos[i]); - scannedDirectory.photos[i].directory = scannedDirectory; - photo.directory = parentDir; - } - - //typeorm not supports recursive embended: TODO:fix it - // PhotoMetadataEntity.close(scannedDirectory.photos[i].metadata); - - if (photo.metadata.keywords != scannedDirectory.photos[i].metadata.keywords || - photo.metadata.cameraData != scannedDirectory.photos[i].metadata.cameraData || - photo.metadata.positionData != scannedDirectory.photos[i].metadata.positionData || - photo.metadata.size != scannedDirectory.photos[i].metadata.size) { - - photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords; - photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData; - photo.metadata.positionData = scannedDirectory.photos[i].metadata.positionData; - photo.metadata.size = scannedDirectory.photos[i].metadata.size; - photosToSave.push(photo); - } - } - await photosRepository.save(photosToSave); - await photosRepository.remove(indexedPhotos); - + await this.saveToDB(scannedDirectory); } catch (error) { + console.error(error); return reject(error); - } + }); } + + private async saveToDB(scannedDirectory: DirectoryDTO) { + const connection = await SQLConnection.getConnection(); + + //saving to db + const directoryRepository = connection.getRepository(DirectoryEntity); + const photosRepository = connection.getRepository(PhotoEntity); + + + let currentDir = await directoryRepository.createQueryBuilder("directory") + .where("directory.name = :name AND directory.path = :path", { + name: scannedDirectory.name, + path: scannedDirectory.path + }).getOne(); + + if (!!currentDir) {//Updated parent dir (if it was in the DB previously) + currentDir.lastModified = scannedDirectory.lastModified; + currentDir.lastScanned = scannedDirectory.lastScanned; + currentDir = await directoryRepository.save(currentDir); + } else { + (scannedDirectory).lastScanned = scannedDirectory.lastScanned; + currentDir = await directoryRepository.save(scannedDirectory); + } + + let childDirectories = await directoryRepository.createQueryBuilder("directory") + .where("directory.parent = :dir", { + dir: currentDir.id + }).getMany(); + + for (let i = 0; i < scannedDirectory.directories.length; i++) { + //Was this child Dir already indexed before? + let directory: DirectoryEntity = null; + for (let j = 0; j < childDirectories.length; j++) { + if (childDirectories[j].name == scannedDirectory.directories[i].name) { + directory = childDirectories[j]; + childDirectories.splice(j, 1); + break; + } + } + + if (directory != null) { //update existing directory + if (!directory.parent || !directory.parent.id) { //set parent if not set yet + directory.parent = currentDir; + delete directory.photos; + await directoryRepository.save(directory); + } + } else { + scannedDirectory.directories[i].parent = currentDir; + (scannedDirectory.directories[i]).lastScanned = null; //new child dir, not fully scanned yet + const d = await directoryRepository.save(scannedDirectory.directories[i]); + for (let j = 0; j < scannedDirectory.directories[i].photos.length; j++) { + scannedDirectory.directories[i].photos[j].directory = d; + } + + await photosRepository.save(scannedDirectory.directories[i].photos); + } + } + + //Remove child Dirs that are not anymore in the parent dir + await directoryRepository.remove(childDirectories); + + + let indexedPhotos = await photosRepository.createQueryBuilder("photo") + .where("photo.directory = :dir", { + dir: currentDir.id + }).getMany(); + + + let photosToSave = []; + for (let i = 0; i < scannedDirectory.photos.length; i++) { + let photo = null; + for (let j = 0; j < indexedPhotos.length; j++) { + if (indexedPhotos[j].name == scannedDirectory.photos[i].name) { + photo = indexedPhotos[j]; + indexedPhotos.splice(j, 1); + break; + } + } + if (photo == null) { + scannedDirectory.photos[i].directory = null; + photo = Utils.clone(scannedDirectory.photos[i]); + scannedDirectory.photos[i].directory = scannedDirectory; + photo.directory = currentDir; + } + + if (photo.metadata.keywords != scannedDirectory.photos[i].metadata.keywords || + photo.metadata.cameraData != scannedDirectory.photos[i].metadata.cameraData || + photo.metadata.positionData != scannedDirectory.photos[i].metadata.positionData || + photo.metadata.size != scannedDirectory.photos[i].metadata.size) { + + photo.metadata.keywords = scannedDirectory.photos[i].metadata.keywords; + photo.metadata.cameraData = scannedDirectory.photos[i].metadata.cameraData; + photo.metadata.positionData = scannedDirectory.photos[i].metadata.positionData; + photo.metadata.size = scannedDirectory.photos[i].metadata.size; + photosToSave.push(photo); + } + } + await photosRepository.save(photosToSave); + await photosRepository.remove(indexedPhotos); + + + } + } diff --git a/backend/model/sql/SQLConnection.ts b/backend/model/sql/SQLConnection.ts index ee36f97e..578254a0 100644 --- a/backend/model/sql/SQLConnection.ts +++ b/backend/model/sql/SQLConnection.ts @@ -28,15 +28,12 @@ export class SQLConnection { options.name = "main"; options.entities = [ UserEntity, - DirectoryEntity, PhotoEntity, + DirectoryEntity, SharingEntity ]; options.synchronize = true; - - //options.logging = "all" ; - - + // options.logging = "all" ; this.connection = await createConnection(options); } return this.connection; @@ -48,8 +45,16 @@ export class SQLConnection { await getConnection("test").close(); } catch (err) { } - let options: any = this.getDriver(config); + const options: any = this.getDriver(config); options.name = "test"; + options.entities = [ + UserEntity, + PhotoEntity, + DirectoryEntity, + SharingEntity + ]; + options.synchronize = true; + options.logging = "all"; const conn = await createConnection(options); await conn.close(); return true; @@ -91,8 +96,11 @@ export class SQLConnection { public static async close() { try { - await getConnection().close(); + if (this.connection != null) { + await this.connection.close(); + } } catch (err) { + console.error(err); } } diff --git a/backend/model/sql/enitites/DirectoryEntity.ts b/backend/model/sql/enitites/DirectoryEntity.ts index 5beb4c61..a136e638 100644 --- a/backend/model/sql/enitites/DirectoryEntity.ts +++ b/backend/model/sql/enitites/DirectoryEntity.ts @@ -16,11 +16,9 @@ export class DirectoryEntity implements DirectoryDTO { @Column('bigint') public lastModified: number; - @Column('bigint') - public lastScanned: number; - @Column() - public scanned: boolean; + @Column({type: "bigint", nullable: true}) + public lastScanned: number; isPartial?: boolean; diff --git a/backend/model/sql/enitites/PhotoEntity.ts b/backend/model/sql/enitites/PhotoEntity.ts index 0c20b777..cc471964 100644 --- a/backend/model/sql/enitites/PhotoEntity.ts +++ b/backend/model/sql/enitites/PhotoEntity.ts @@ -1,75 +1,10 @@ import {Column, Entity, ManyToOne, PrimaryGeneratedColumn} from "typeorm"; -import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO"; import { - CameraMetadata, - GPSMetadata, - ImageSize, - PhotoDTO, - PhotoMetadata, + CameraMetadata, GPSMetadata, ImageSize, PhotoDTO, PhotoMetadata, PositionMetaData } from "../../../../common/entities/PhotoDTO"; import {DirectoryEntity} from "./DirectoryEntity"; -@Entity() -export class PhotoEntity implements PhotoDTO { - - @PrimaryGeneratedColumn() - id: number; - - @Column("text") - name: string; - - @ManyToOne(type => DirectoryEntity, directory => directory.photos, {onDelete: "CASCADE"}) - directory: DirectoryDTO; - - @Column(type => PhotoMetadataEntity) - metadata: PhotoMetadataEntity; - - readyThumbnails: Array = []; - - readyIcon: boolean = false; - -} - - -@Entity() -export class PhotoMetadataEntity implements PhotoMetadata { - - @Column("simple-array") - keywords: Array; - - @Column(type => CameraMetadataEntity) - cameraData: CameraMetadataEntity; - - @Column(type => PositionMetaDataEntity) - positionData: PositionMetaDataEntity; - - @Column(type => ImageSizeEntity) - size: ImageSizeEntity; - - @Column("bigint") - creationDate: number; - - @Column("int") - fileSize: number; - /* - //TODO: fixit after typeorm update - public static open(m: PhotoMetadataEntity) { - m.keywords = JSON.parse(m.keywords); - m.cameraData = JSON.parse(m.cameraData); - m.positionData = JSON.parse(m.positionData); - m.size = JSON.parse(m.size); - } - - //TODO: fixit after typeorm update - public static close(m: PhotoMetadataEntity) { - m.keywords = JSON.stringify(m.keywords); - m.cameraData = JSON.stringify(m.cameraData); - m.positionData = JSON.stringify(m.positionData); - m.size = JSON.stringify(m.size); - }*/ -} - @Entity() export class CameraMetadataEntity implements CameraMetadata { @@ -97,23 +32,6 @@ export class CameraMetadataEntity implements CameraMetadata { } -@Entity() -export class PositionMetaDataEntity implements PositionMetaData { - - @Column(type => GPSMetadataEntity) - GPSData: GPSMetadataEntity; - - @Column("text", {nullable: true}) - country: string; - - @Column("text", {nullable: true}) - state: string; - - @Column("text", {nullable: true}) - city: string; -} - - @Entity() export class GPSMetadataEntity implements GPSMetadata { @@ -134,3 +52,65 @@ export class ImageSizeEntity implements ImageSize { @Column("int") height: number; } + + +@Entity() +export class PositionMetaDataEntity implements PositionMetaData { + + @Column(type => GPSMetadataEntity) + GPSData: GPSMetadataEntity; + + @Column("text", {nullable: true}) + country: string; + + @Column("text", {nullable: true}) + state: string; + + @Column("text", {nullable: true}) + city: string; +} + + +@Entity() +export class PhotoMetadataEntity implements PhotoMetadata { + + @Column("simple-array") + keywords: Array; + + @Column(type => CameraMetadataEntity) + cameraData: CameraMetadataEntity; + + @Column(type => PositionMetaDataEntity) + positionData: PositionMetaDataEntity; + + @Column(type => ImageSizeEntity) + size: ImageSizeEntity; + + @Column("bigint") + creationDate: number; + + @Column("int") + fileSize: number; +} + + +@Entity() +export class PhotoEntity implements PhotoDTO { + + @PrimaryGeneratedColumn() + id: number; + + @Column("text") + name: string; + + @ManyToOne(type => DirectoryEntity, directory => directory.photos, {onDelete: "CASCADE"}) + directory: DirectoryEntity; + + @Column(type => PhotoMetadataEntity) + metadata: PhotoMetadataEntity; + + readyThumbnails: Array = []; + + readyIcon: boolean = false; + +} diff --git a/package.json b/package.json index 970a6025..605e9f79 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "ts-exif-parser": "0.1.23", "ts-node-iptc": "1.0.9", "typeconfig": "1.0.5", - "typeorm": "0.1.9", + "typeorm": "0.1.1", "winston": "2.4.0" }, "devDependencies": {