mirror of
https://github.com/xuthus83/pigallery2.git
synced 2025-01-14 14:43:17 +08:00
implementing mysql GalleryManager
This commit is contained in:
parent
bb139b8159
commit
53ab3d34a9
@ -2,12 +2,12 @@ import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import {NextFunction, Request, Response} from "express";
|
||||
import {Error, ErrorCodes} from "../../common/entities/Error";
|
||||
import {Directory} from "../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../common/entities/DirectoryDTO";
|
||||
import {ObjectManagerRepository} from "../model/ObjectManagerRepository";
|
||||
import {AutoCompleteItem, SearchTypes} from "../../common/entities/AutoCompleteItem";
|
||||
import {ContentWrapper} from "../../common/entities/ConentWrapper";
|
||||
import {SearchResult} from "../../common/entities/SearchResult";
|
||||
import {Photo} from "../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../common/entities/PhotoDTO";
|
||||
import {Config} from "../config/Config";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
|
||||
@ -22,7 +22,7 @@ export class GalleryMWs {
|
||||
return next();
|
||||
}
|
||||
|
||||
ObjectManagerRepository.getInstance().getGalleryManager().listDirectory(directoryName, (err, directory:Directory) => {
|
||||
ObjectManagerRepository.getInstance().getGalleryManager().listDirectory(directoryName, (err, directory: DirectoryDTO) => {
|
||||
if (err || !directory) {
|
||||
return next(new Error(ErrorCodes.GENERAL_ERROR, err));
|
||||
}
|
||||
@ -40,9 +40,13 @@ export class GalleryMWs {
|
||||
|
||||
let cw:ContentWrapper = req.resultPipe;
|
||||
if (cw.directory) {
|
||||
cw.directory.photos.forEach((photo:Photo) => {
|
||||
cw.directory.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.directory = null;
|
||||
});
|
||||
|
||||
cw.directory.directories.forEach((photo: DirectoryDTO) => {
|
||||
photo.parent = null;
|
||||
});
|
||||
}
|
||||
|
||||
return next();
|
||||
|
@ -1,6 +1,4 @@
|
||||
///<reference path="customtypings/jimp.d.ts"/>
|
||||
|
||||
|
||||
import * as path from "path";
|
||||
import * as Jimp from "jimp";
|
||||
import * as crypto from "crypto";
|
||||
@ -9,15 +7,21 @@ import {NextFunction, Request, Response} from "express";
|
||||
import {Error, ErrorCodes} from "../../common/entities/Error";
|
||||
import {Config} from "../config/Config";
|
||||
import {ContentWrapper} from "../../common/entities/ConentWrapper";
|
||||
import {Directory} from "../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../common/entities/DirectoryDTO";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
import {Photo} from "../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../common/entities/PhotoDTO";
|
||||
|
||||
|
||||
export class ThumbnailGeneratorMWs {
|
||||
|
||||
|
||||
private static addThInfoTODir(directory:Directory) {
|
||||
private static addThInfoTODir(directory: DirectoryDTO) {
|
||||
if (typeof directory.photos == "undefined") {
|
||||
directory.photos = [];
|
||||
}
|
||||
if (typeof directory.directories == "undefined") {
|
||||
directory.directories = [];
|
||||
}
|
||||
ThumbnailGeneratorMWs.addThInfoToPhotos(directory.photos);
|
||||
|
||||
for (let i = 0; i < directory.directories.length; i++) {
|
||||
@ -26,7 +30,7 @@ export class ThumbnailGeneratorMWs {
|
||||
|
||||
}
|
||||
|
||||
private static addThInfoToPhotos(photos:Array<Photo>) {
|
||||
private static addThInfoToPhotos(photos: Array<PhotoDTO>) {
|
||||
let thumbnailFolder = ProjectPath.ThumbnailFolder;
|
||||
for (let j = 0; j < Config.Client.thumbnailSizes.length; j++) {
|
||||
let size = Config.Client.thumbnailSizes[j];
|
||||
@ -34,17 +38,20 @@ export class ThumbnailGeneratorMWs {
|
||||
let fullImagePath = path.join(ProjectPath.ImageFolder, photos[i].directory.path, photos[i].directory.name, photos[i].name);
|
||||
let thPath = path.join(thumbnailFolder, ThumbnailGeneratorMWs.generateThumbnailName(fullImagePath, size));
|
||||
if (fs.existsSync(thPath) === true) {
|
||||
if (typeof photos[i].readyThumbnails == "undefined") {
|
||||
photos[i].readyThumbnails = [];
|
||||
}
|
||||
photos[i].readyThumbnails.push(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static addThumbnailInformation(req:Request, res:Response, next:NextFunction) {
|
||||
public static addThumbnailInformation(req: Request, res: Response, next: NextFunction) {
|
||||
if (!req.resultPipe)
|
||||
return next();
|
||||
|
||||
let cw:ContentWrapper = req.resultPipe;
|
||||
let cw: ContentWrapper = req.resultPipe;
|
||||
if (cw.directory) {
|
||||
ThumbnailGeneratorMWs.addThInfoTODir(cw.directory);
|
||||
}
|
||||
@ -54,16 +61,16 @@ export class ThumbnailGeneratorMWs {
|
||||
|
||||
|
||||
return next();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static generateThumbnail(req:Request, res:Response, next:NextFunction) {
|
||||
public static generateThumbnail(req: Request, res: Response, next: NextFunction) {
|
||||
if (!req.resultPipe)
|
||||
return next();
|
||||
|
||||
//load parameters
|
||||
let imagePath = req.resultPipe;
|
||||
let size:number = parseInt(req.params.size) || Config.Client.thumbnailSizes[0];
|
||||
let size: number = parseInt(req.params.size) || Config.Client.thumbnailSizes[0];
|
||||
|
||||
//validate size
|
||||
if (Config.Client.thumbnailSizes.indexOf(size) === -1) {
|
||||
@ -112,7 +119,7 @@ export class ThumbnailGeneratorMWs {
|
||||
|
||||
}
|
||||
|
||||
private static generateThumbnailName(imagePath:string, size:number):string {
|
||||
private static generateThumbnailName(imagePath: string, size: number): string {
|
||||
return crypto.createHash('md5').update(imagePath).digest('hex') + "_" + size + ".jpg";
|
||||
}
|
||||
}
|
@ -4,25 +4,32 @@ import * as path from "path";
|
||||
import * as mime from "mime";
|
||||
import * as iptc from "node-iptc";
|
||||
import * as exif_parser from "exif-parser";
|
||||
import {Directory} from "../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../common/entities/DirectoryDTO";
|
||||
import {
|
||||
Photo,
|
||||
PhotoDTO,
|
||||
PhotoMetadata,
|
||||
ImageSize,
|
||||
CameraMetadata,
|
||||
PositionMetaData,
|
||||
GPSMetadata
|
||||
} from "../../common/entities/Photo";
|
||||
} from "../../common/entities/PhotoDTO";
|
||||
import {ProjectPath} from "../ProjectPath";
|
||||
|
||||
export class DiskManager {
|
||||
public static scanDirectory(relativeDirectoryName: string, cb: (error: any, result: Directory) => void) {
|
||||
public static scanDirectory(relativeDirectoryName: string, cb: (error: any, result: DirectoryDTO) => void) {
|
||||
console.log("DiskManager: scanDirectory");
|
||||
let directoryName = path.basename(relativeDirectoryName);
|
||||
let directoryParent = path.join(path.dirname(relativeDirectoryName), "/");
|
||||
let absoluteDirectoryName = path.join(ProjectPath.ImageFolder, relativeDirectoryName);
|
||||
let directoryName = path.normalize(path.basename(relativeDirectoryName));
|
||||
let directoryParent = path.normalize(path.join(path.dirname(relativeDirectoryName), "/"));
|
||||
let absoluteDirectoryName = path.normalize(path.join(ProjectPath.ImageFolder, relativeDirectoryName));
|
||||
console.log(directoryName, directoryParent, path.dirname(relativeDirectoryName), path.join(path.dirname(relativeDirectoryName), "/"));
|
||||
|
||||
let directory = new Directory(1, directoryName, directoryParent, new Date(), [], []);
|
||||
let directory = <DirectoryDTO>{
|
||||
name: directoryName,
|
||||
path: directoryParent,
|
||||
lastUpdate: new Date(),
|
||||
directories: [],
|
||||
photos: []
|
||||
};
|
||||
|
||||
let promises: Array< Promise<any> > = [];
|
||||
fs.readdir(absoluteDirectoryName, function (err, list) {
|
||||
@ -34,16 +41,22 @@ export class DiskManager {
|
||||
|
||||
for (let i = 0; i < list.length; i++) {
|
||||
let file = list[i];
|
||||
let fullFilePath = path.resolve(absoluteDirectoryName, file);
|
||||
let fullFilePath = path.normalize(path.resolve(absoluteDirectoryName, file));
|
||||
if (fs.statSync(fullFilePath).isDirectory()) {
|
||||
directory.directories.push(new Directory(2, file, relativeDirectoryName, new Date(), [], []));
|
||||
directory.directories.push(<DirectoryDTO>{
|
||||
name: file,
|
||||
path: relativeDirectoryName,
|
||||
lastUpdate: new Date(),
|
||||
directories: [],
|
||||
photos: []
|
||||
});
|
||||
}
|
||||
|
||||
if (DiskManager.isImage(fullFilePath)) {
|
||||
|
||||
|
||||
let promise = DiskManager.loadPhotoMetadata(fullFilePath).then((photoMetadata) => {
|
||||
directory.photos.push(new Photo(1, file, directory, photoMetadata));
|
||||
directory.photos.push(<PhotoDTO>{name: file, directory: directory, metadata: photoMetadata});
|
||||
});
|
||||
|
||||
promises.push(promise);
|
||||
@ -156,10 +169,15 @@ export class DiskManager {
|
||||
|
||||
let keywords: [string] = iptcData.keywords.map((s: string) => decode(s));
|
||||
let creationDate: Date = iptcData.date_time;
|
||||
console.log(keywords);
|
||||
|
||||
|
||||
let metadata: PhotoMetadata = new PhotoMetadata(keywords, cameraData, positionData, imageSize, creationDate);
|
||||
let metadata: PhotoMetadata = <PhotoMetadata>{
|
||||
keywords: keywords,
|
||||
cameraData: cameraData,
|
||||
positionData: positionData,
|
||||
size: imageSize,
|
||||
creationDate: creationDate
|
||||
};
|
||||
resolve(metadata);
|
||||
}
|
||||
});
|
||||
|
@ -23,7 +23,7 @@ export class ObjectManagerRepository {
|
||||
public static InitMySQLManagers(): Promise<boolean> {
|
||||
return new Promise<boolean>((resolve, reject) => {
|
||||
MySQLConnection.init().then(() => {
|
||||
const GalleryManager = require("./memory/GalleryManager").GalleryManager;
|
||||
const GalleryManager = require("./mysql/GalleryManager").GalleryManager;
|
||||
const UserManager = require("./mysql/UserManager").UserManager;
|
||||
const SearchManager = require("./memory/SearchManager").SearchManager;
|
||||
ObjectManagerRepository.getInstance().setGalleryManager(new GalleryManager());
|
||||
|
@ -1,4 +1,4 @@
|
||||
import {Directory} from "../../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
export interface IGalleryManager {
|
||||
listDirectory(relativeDirectoryName: string, cb: (error: any, result: Directory) => void): void;
|
||||
listDirectory(relativeDirectoryName: string, cb: (error: any, result: DirectoryDTO) => void): void;
|
||||
}
|
@ -1,11 +1,11 @@
|
||||
import {Directory} from "../../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {IGalleryManager} from "../interfaces/IGalleryManager";
|
||||
import {DiskManager} from "../DiskManger";
|
||||
|
||||
export class GalleryManager implements IGalleryManager {
|
||||
|
||||
|
||||
public listDirectory(relativeDirectoryName: string, cb: (error: any, result: Directory) => void) {
|
||||
public listDirectory(relativeDirectoryName: string, cb: (error: any, result: DirectoryDTO) => void) {
|
||||
return DiskManager.scanDirectory(relativeDirectoryName, cb);
|
||||
}
|
||||
|
||||
|
91
backend/model/mysql/GalleryManager.ts
Normal file
91
backend/model/mysql/GalleryManager.ts
Normal file
@ -0,0 +1,91 @@
|
||||
import {IGalleryManager} from "../interfaces/IGalleryManager";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import * as path from "path";
|
||||
import {DirectoryEnitity} from "./enitites/DirectoryEntity";
|
||||
import {MySQLConnection} from "./MySQLConnection";
|
||||
import {DiskManager} from "../DiskManger";
|
||||
import {PhotoEntity} from "./enitites/PhotoEntity";
|
||||
import {Utils} from "../../../common/Utils";
|
||||
|
||||
export class GalleryManager implements IGalleryManager {
|
||||
|
||||
|
||||
public listDirectory(relativeDirectoryName, cb: (error: any, result: DirectoryDTO) => void) {
|
||||
let directoryName = path.normalize(path.basename(relativeDirectoryName));
|
||||
let directoryParent = path.normalize(path.join(path.dirname(relativeDirectoryName), "/"));
|
||||
console.log("GalleryManager:listDirectory");
|
||||
console.log(directoryName, directoryParent, path.dirname(relativeDirectoryName), path.join(path.dirname(relativeDirectoryName), "/"));
|
||||
MySQLConnection.getConnection().then(async connection => {
|
||||
|
||||
let dir = await connection
|
||||
.getRepository(DirectoryEnitity)
|
||||
.createQueryBuilder("directory_entity")
|
||||
.where("directory_entity.name = :name AND directory_entity.path = :path", {
|
||||
name: directoryName,
|
||||
path: directoryParent
|
||||
})
|
||||
.innerJoinAndSelect("directory_entity.directories", "directories")
|
||||
.innerJoinAndSelect("directory_entity.photos", "photos")
|
||||
.getOne();
|
||||
|
||||
|
||||
console.log(dir);
|
||||
if (dir) {
|
||||
for (let i = 0; i < dir.photos.length; i++) {
|
||||
dir.photos[i].directory = dir;
|
||||
dir.photos[i].metadata.keywords = <any>JSON.parse(<any>dir.photos[i].metadata.keywords);
|
||||
dir.photos[i].metadata.cameraData = <any>JSON.parse(<any>dir.photos[i].metadata.cameraData);
|
||||
dir.photos[i].metadata.positionData = <any>JSON.parse(<any>dir.photos[i].metadata.positionData);
|
||||
dir.photos[i].metadata.size = <any>JSON.parse(<any>dir.photos[i].metadata.size);
|
||||
}
|
||||
return cb(null, dir);
|
||||
}
|
||||
return this.indexDirectory(relativeDirectoryName, cb);
|
||||
|
||||
|
||||
}).catch((error) => {
|
||||
return cb(error, null);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
public indexDirectory(relativeDirectoryName, cb: (error: any, result: DirectoryDTO) => void) {
|
||||
DiskManager.scanDirectory(relativeDirectoryName, (err, scannedDirectory) => {
|
||||
MySQLConnection.getConnection().then(async connection => {
|
||||
|
||||
let directoryRepository = connection.getRepository(DirectoryEnitity);
|
||||
let photosRepository = connection.getRepository(PhotoEntity);
|
||||
|
||||
let parentDir = await directoryRepository.persist(scannedDirectory);
|
||||
|
||||
for (let i = 0; i < scannedDirectory.directories.length; i++) {
|
||||
scannedDirectory.directories[i].parent = parentDir;
|
||||
await directoryRepository.persist(scannedDirectory.directories[i]);
|
||||
}
|
||||
|
||||
for (let i = 0; i < scannedDirectory.photos.length; i++) {
|
||||
|
||||
//typeorm not supports recursive embended: TODO:fix it
|
||||
scannedDirectory.photos[i].directory = null;
|
||||
let photo = Utils.clone(scannedDirectory.photos[i]);
|
||||
scannedDirectory.photos[i].directory = scannedDirectory;
|
||||
photo.directory = parentDir;
|
||||
photo.metadata.keywords = <any>JSON.stringify(photo.metadata.keywords);
|
||||
photo.metadata.cameraData = <any>JSON.stringify(photo.metadata.cameraData);
|
||||
photo.metadata.positionData = <any>JSON.stringify(photo.metadata.positionData);
|
||||
photo.metadata.size = <any>JSON.stringify(photo.metadata.size);
|
||||
await photosRepository.persist(photo);
|
||||
}
|
||||
|
||||
|
||||
return cb(null, parentDir);
|
||||
|
||||
|
||||
}).catch((error) => {
|
||||
return cb(error, null);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
@ -3,6 +3,8 @@ import {createConnection, Connection} from "typeorm";
|
||||
import {Config} from "../../config/Config";
|
||||
import {UserEntity} from "./enitites/UserEntity";
|
||||
import {UserRoles} from "../../../common/entities/UserDTO";
|
||||
import {PhotoEntity, PhotoMetadataEntity} from "./enitites/PhotoEntity";
|
||||
import {DirectoryEnitity} from "./enitites/DirectoryEntity";
|
||||
|
||||
|
||||
export class MySQLConnection {
|
||||
@ -31,9 +33,18 @@ export class MySQLConnection {
|
||||
database: Config.Server.database.mysql.database
|
||||
},
|
||||
entities: [
|
||||
UserEntity
|
||||
UserEntity,
|
||||
DirectoryEnitity,
|
||||
PhotoMetadataEntity,
|
||||
PhotoEntity
|
||||
],
|
||||
autoSchemaSync: true,
|
||||
logging: {
|
||||
logQueries: true,
|
||||
logOnlyFailedQueries: true,
|
||||
logFailedQueryError: true,
|
||||
logSchemaCreation: true
|
||||
}
|
||||
}).then((conn) => {
|
||||
this.connection = conn;
|
||||
return resolve(this.connection);
|
||||
|
34
backend/model/mysql/enitites/DirectoryEntity.ts
Normal file
34
backend/model/mysql/enitites/DirectoryEntity.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import {Table, Column, PrimaryGeneratedColumn, OneToMany, ManyToOne} from "typeorm";
|
||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||
import {PhotoEntity} from "./PhotoEntity";
|
||||
|
||||
@Table()
|
||||
export class DirectoryEnitity implements DirectoryDTO {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column({
|
||||
length: 500
|
||||
})
|
||||
name: string;
|
||||
|
||||
@Column({
|
||||
length: 500
|
||||
})
|
||||
path: string;
|
||||
|
||||
|
||||
@Column('datetime')
|
||||
public lastUpdate: Date;
|
||||
|
||||
@ManyToOne(type => DirectoryEnitity, directory => directory.directories)
|
||||
public parent: DirectoryEnitity;
|
||||
|
||||
@OneToMany(type => DirectoryEnitity, dir => dir.parent)
|
||||
public directories: Array<DirectoryEnitity>;
|
||||
|
||||
@OneToMany(type => PhotoEntity, photo => photo.directory)
|
||||
public photos: Array<PhotoEntity>;
|
||||
|
||||
}
|
114
backend/model/mysql/enitites/PhotoEntity.ts
Normal file
114
backend/model/mysql/enitites/PhotoEntity.ts
Normal file
@ -0,0 +1,114 @@
|
||||
import {Table, EmbeddableTable, Column, Embedded, PrimaryGeneratedColumn, ManyToOne} from "typeorm";
|
||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||
import {
|
||||
PhotoDTO,
|
||||
PhotoMetadata,
|
||||
CameraMetadata,
|
||||
ImageSize,
|
||||
PositionMetaData
|
||||
} from "../../../../common/entities/PhotoDTO";
|
||||
import {DirectoryEnitity} from "./DirectoryEntity";
|
||||
|
||||
@Table()
|
||||
export class PhotoEntity implements PhotoDTO {
|
||||
|
||||
@PrimaryGeneratedColumn()
|
||||
id: number;
|
||||
|
||||
@Column("string")
|
||||
name: string;
|
||||
|
||||
@ManyToOne(type => DirectoryEnitity, directory => directory.photos)
|
||||
directory: DirectoryDTO;
|
||||
|
||||
@Embedded(type => PhotoMetadataEntity)
|
||||
metadata: PhotoMetadataEntity;
|
||||
|
||||
readyThumbnails: Array<number> = [];
|
||||
|
||||
}
|
||||
|
||||
|
||||
@EmbeddableTable()
|
||||
export class PhotoMetadataEntity implements PhotoMetadata {
|
||||
|
||||
@Column("string")
|
||||
keywords: Array<string>;
|
||||
|
||||
@Column("string")
|
||||
cameraData: CameraMetadata;
|
||||
|
||||
@Column("string")
|
||||
positionData: PositionMetaData;
|
||||
|
||||
@Column("string")
|
||||
size: ImageSize;
|
||||
|
||||
@Column("datetime")
|
||||
creationDate: Date;
|
||||
}
|
||||
|
||||
/*
|
||||
@EmbeddableTable()
|
||||
export class CameraMetadataEntity implements CameraMetadata {
|
||||
|
||||
@Column("string")
|
||||
ISO: number;
|
||||
|
||||
@Column("string")
|
||||
model: string;
|
||||
|
||||
@Column("string")
|
||||
maker: string;
|
||||
|
||||
@Column("int")
|
||||
fStop: number;
|
||||
|
||||
@Column("int")
|
||||
exposure: number;
|
||||
|
||||
@Column("int")
|
||||
focalLength: number;
|
||||
|
||||
@Column("string")
|
||||
lens: string;
|
||||
}
|
||||
|
||||
|
||||
@EmbeddableTable()
|
||||
export class PositionMetaDataEntity implements PositionMetaData {
|
||||
|
||||
@Embedded(type => GPSMetadataEntity)
|
||||
GPSData: GPSMetadataEntity;
|
||||
|
||||
@Column("string")
|
||||
country: string;
|
||||
|
||||
@Column("string")
|
||||
state: string;
|
||||
|
||||
@Column("string")
|
||||
city: string;
|
||||
}
|
||||
|
||||
|
||||
@EmbeddableTable()
|
||||
export class GPSMetadataEntity implements GPSMetadata {
|
||||
|
||||
@Column("string")
|
||||
latitude: string;
|
||||
@Column("string")
|
||||
longitude: string;
|
||||
@Column("string")
|
||||
altitude: string;
|
||||
}
|
||||
|
||||
@EmbeddableTable()
|
||||
export class ImageSizeEntity implements ImageSize {
|
||||
|
||||
@Column("int")
|
||||
width: number;
|
||||
|
||||
@Column("int")
|
||||
height: number;
|
||||
}*/
|
@ -54,8 +54,9 @@ export class Server {
|
||||
this.app.use(_bodyParser.json());
|
||||
|
||||
|
||||
ObjectManagerRepository.InitMySQLManagers().catch(() => {
|
||||
ObjectManagerRepository.InitMySQLManagers().catch((err) => {
|
||||
console.error("Erro during initailizing mysql falling back to memory DB");
|
||||
console.log(err);
|
||||
Config.setDatabaseType(DatabaseType.memory);
|
||||
ObjectManagerRepository.InitMemoryManagers();
|
||||
});
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {Directory} from "./Directory";
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {SearchResult} from "./SearchResult";
|
||||
export class ContentWrapper {
|
||||
|
||||
public directory:Directory;
|
||||
public directory: DirectoryDTO;
|
||||
public searchResult:SearchResult;
|
||||
|
||||
constructor(directory:Directory = null, searchResult:SearchResult = null) {
|
||||
constructor(directory: DirectoryDTO = null, searchResult: SearchResult = null) {
|
||||
this.directory = directory;
|
||||
this.searchResult = searchResult;
|
||||
}
|
||||
|
@ -1,11 +0,0 @@
|
||||
import {Photo} from "./Photo";
|
||||
export class Directory {
|
||||
|
||||
constructor(public id?:number,
|
||||
public name?:string,
|
||||
public path?:string,
|
||||
public lastUpdate?:Date,
|
||||
public directories:Array<Directory> = [],
|
||||
public photos:Array<Photo> = []) {
|
||||
}
|
||||
}
|
11
common/entities/DirectoryDTO.ts
Normal file
11
common/entities/DirectoryDTO.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import {PhotoDTO} from "./PhotoDTO";
|
||||
|
||||
export interface DirectoryDTO {
|
||||
id: number;
|
||||
name: string;
|
||||
path: string;
|
||||
lastUpdate: Date;
|
||||
parent: DirectoryDTO;
|
||||
directories: Array<DirectoryDTO>;
|
||||
photos: Array<PhotoDTO>;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import {Directory} from "./Directory";
|
||||
|
||||
export class Photo {
|
||||
constructor(public id?:number,
|
||||
public name?:string,
|
||||
public directory?:Directory,
|
||||
public metadata?:PhotoMetadata,
|
||||
public readyThumbnails:Array<number> = []) {
|
||||
}
|
||||
}
|
||||
|
||||
export class PhotoMetadata {
|
||||
constructor(public keywords?:Array<string>,
|
||||
public cameraData?:CameraMetadata,
|
||||
public positionData?:PositionMetaData,
|
||||
public size?:ImageSize,
|
||||
public creationDate?:Date) {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ImageSize {
|
||||
width:number;
|
||||
height:number;
|
||||
}
|
||||
|
||||
export interface CameraMetadata {
|
||||
ISO?:number;
|
||||
model?:string;
|
||||
maker?:string;
|
||||
fStop?:number;
|
||||
exposure?:number;
|
||||
focalLength?:number;
|
||||
lens?:string;
|
||||
}
|
||||
|
||||
export interface PositionMetaData {
|
||||
GPSData?:GPSMetadata;
|
||||
country?:string;
|
||||
state?:string;
|
||||
city?:string;
|
||||
}
|
||||
|
||||
export interface GPSMetadata {
|
||||
latitude?:string;
|
||||
longitude?:string;
|
||||
altitude?:string;
|
||||
|
||||
}
|
46
common/entities/PhotoDTO.ts
Normal file
46
common/entities/PhotoDTO.ts
Normal file
@ -0,0 +1,46 @@
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
|
||||
export interface PhotoDTO {
|
||||
id: number;
|
||||
name: string;
|
||||
directory: DirectoryDTO;
|
||||
metadata: PhotoMetadata;
|
||||
readyThumbnails: Array<number>;
|
||||
}
|
||||
|
||||
export interface PhotoMetadata {
|
||||
keywords: Array<string>;
|
||||
cameraData: CameraMetadata;
|
||||
positionData: PositionMetaData;
|
||||
size: ImageSize;
|
||||
creationDate: Date;
|
||||
}
|
||||
|
||||
export interface ImageSize {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
export interface CameraMetadata {
|
||||
ISO?: number;
|
||||
model?: string;
|
||||
maker?: string;
|
||||
fStop?: number;
|
||||
exposure?: number;
|
||||
focalLength?: number;
|
||||
lens?: string;
|
||||
}
|
||||
|
||||
export interface PositionMetaData {
|
||||
GPSData?: GPSMetadata;
|
||||
country?: string;
|
||||
state?: string;
|
||||
city?: string;
|
||||
}
|
||||
|
||||
export interface GPSMetadata {
|
||||
latitude?: string;
|
||||
longitude?: string;
|
||||
altitude?: string;
|
||||
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
import {Directory} from "./Directory";
|
||||
import {Photo} from "./Photo";
|
||||
import {DirectoryDTO} from "./DirectoryDTO";
|
||||
import {PhotoDTO} from "./PhotoDTO";
|
||||
import {SearchTypes} from "./AutoCompleteItem";
|
||||
export class SearchResult {
|
||||
public searchText:string = "";
|
||||
public searchType:SearchTypes;
|
||||
public directories:Array<Directory> = [];
|
||||
public photos:Array<Photo> = [];
|
||||
public directories: Array<DirectoryDTO> = [];
|
||||
public photos: Array<PhotoDTO> = [];
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
import {Injectable} from "@angular/core";
|
||||
import {Photo} from "../../../common/entities/Photo";
|
||||
import {Directory} from "../../../common/entities/Directory";
|
||||
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {Utils} from "../../../common/Utils";
|
||||
import {Config} from "../config/Config";
|
||||
|
||||
@ -8,20 +8,20 @@ import {Config} from "../config/Config";
|
||||
export class GalleryCacheService {
|
||||
|
||||
|
||||
public getDirectory(directoryName: string): Directory {
|
||||
public getDirectory(directoryName: string): DirectoryDTO {
|
||||
if (Config.Client.enableCache == false) {
|
||||
return null;
|
||||
}
|
||||
let value = localStorage.getItem(directoryName);
|
||||
if (value != null) {
|
||||
let directory: Directory = JSON.parse(value);
|
||||
let directory: DirectoryDTO = JSON.parse(value);
|
||||
|
||||
|
||||
directory.photos.forEach((photo: Photo) => {
|
||||
directory.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.metadata.creationDate = new Date(<any>photo.metadata.creationDate);
|
||||
});
|
||||
|
||||
directory.photos.forEach((photo: Photo) => {
|
||||
directory.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.directory = directory;
|
||||
});
|
||||
|
||||
@ -30,14 +30,14 @@ export class GalleryCacheService {
|
||||
return null;
|
||||
}
|
||||
|
||||
public setDirectory(directory: Directory): void {
|
||||
public setDirectory(directory: DirectoryDTO): void {
|
||||
if (Config.Client.enableCache == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
localStorage.setItem(Utils.concatUrls(directory.path, directory.name), JSON.stringify(directory));
|
||||
|
||||
directory.directories.forEach((dir: Directory) => {
|
||||
directory.directories.forEach((dir: DirectoryDTO) => {
|
||||
let name = Utils.concatUrls(dir.path, dir.name);
|
||||
if (localStorage.getItem(name) == null) { //don't override existing
|
||||
localStorage.setItem(Utils.concatUrls(dir.path, dir.name), JSON.stringify(dir));
|
||||
@ -50,7 +50,7 @@ export class GalleryCacheService {
|
||||
* Update photo state at cache too (Eg.: thumbnail rendered)
|
||||
* @param photo
|
||||
*/
|
||||
public photoUpdated(photo: Photo): void {
|
||||
public photoUpdated(photo: PhotoDTO): void {
|
||||
|
||||
if (Config.Client.enableCache == false) {
|
||||
return;
|
||||
@ -59,7 +59,7 @@ export class GalleryCacheService {
|
||||
let directoryName = Utils.concatUrls(photo.directory.path, photo.directory.name);
|
||||
let value = localStorage.getItem(directoryName);
|
||||
if (value != null) {
|
||||
let directory: Directory = JSON.parse(value);
|
||||
let directory: DirectoryDTO = JSON.parse(value);
|
||||
directory.photos.forEach((p) => {
|
||||
if (p.name === photo.name) {
|
||||
//update data
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Component, Input} from "@angular/core";
|
||||
import {Directory} from "../../../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||
import {RouterLink} from "@angular/router";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
|
||||
@ -9,7 +9,7 @@ import {Utils} from "../../../../common/Utils";
|
||||
providers: [RouterLink],
|
||||
})
|
||||
export class GalleryDirectoryComponent {
|
||||
@Input() directory:Directory;
|
||||
@Input() directory: DirectoryDTO;
|
||||
|
||||
constructor() {
|
||||
}
|
||||
|
@ -2,8 +2,8 @@ import {Injectable} from "@angular/core";
|
||||
import {NetworkService} from "../model/network/network.service";
|
||||
import {Message} from "../../../common/entities/Message";
|
||||
import {ContentWrapper} from "../../../common/entities/ConentWrapper";
|
||||
import {Photo} from "../../../common/entities/Photo";
|
||||
import {Directory} from "../../../common/entities/Directory";
|
||||
import {PhotoDTO} from "../../../common/entities/PhotoDTO";
|
||||
import {DirectoryDTO} from "../../../common/entities/DirectoryDTO";
|
||||
import {SearchTypes} from "../../../common/entities/AutoCompleteItem";
|
||||
import {GalleryCacheService} from "./cache.gallery.service";
|
||||
|
||||
@ -11,7 +11,7 @@ import {GalleryCacheService} from "./cache.gallery.service";
|
||||
export class GalleryService {
|
||||
|
||||
public content:ContentWrapper;
|
||||
private lastDirectory:Directory;
|
||||
private lastDirectory: DirectoryDTO;
|
||||
private searchId:any;
|
||||
|
||||
constructor(private networkService:NetworkService, private galleryCacheService:GalleryCacheService) {
|
||||
@ -38,11 +38,11 @@ export class GalleryService {
|
||||
}
|
||||
|
||||
|
||||
message.result.directory.photos.forEach((photo:Photo) => {
|
||||
message.result.directory.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.metadata.creationDate = new Date(<any>photo.metadata.creationDate);
|
||||
});
|
||||
|
||||
message.result.directory.photos.forEach((photo:Photo) => {
|
||||
message.result.directory.photos.forEach((photo: PhotoDTO) => {
|
||||
photo.directory = message.result.directory;
|
||||
});
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../../../common/entities/PhotoDTO";
|
||||
import {Config} from "../../config/Config";
|
||||
import {Utils} from "../../../../common/Utils";
|
||||
export class GridPhoto {
|
||||
|
||||
private replacementSizeCache:boolean|number = false;
|
||||
|
||||
constructor(public photo:Photo, public renderWidth:number, public renderHeight:number, public rowId:number) {
|
||||
constructor(public photo: PhotoDTO, public renderWidth: number, public renderHeight: number, public rowId: number) {
|
||||
|
||||
}
|
||||
|
||||
|
@ -1,13 +1,13 @@
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../../../common/entities/PhotoDTO";
|
||||
|
||||
export class GridRowBuilder {
|
||||
|
||||
private photoRow:Array<Photo> = [];
|
||||
private photoRow: Array<PhotoDTO> = [];
|
||||
|
||||
private photoIndex:number = 0; //index of the last pushed photo to the photoRow
|
||||
|
||||
|
||||
constructor(private photos:Array<Photo>, private startIndex:number, private photoMargin:number, private containerWidth:number) {
|
||||
constructor(private photos: Array<PhotoDTO>, private startIndex: number, private photoMargin: number, private containerWidth: number) {
|
||||
this.photoIndex = startIndex;
|
||||
}
|
||||
|
||||
@ -35,7 +35,7 @@ export class GridRowBuilder {
|
||||
return true;
|
||||
}
|
||||
|
||||
public getPhotoRow():Array<Photo> {
|
||||
public getPhotoRow(): Array<PhotoDTO> {
|
||||
return this.photoRow;
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ import {
|
||||
AfterViewInit,
|
||||
HostListener
|
||||
} from "@angular/core";
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../../../common/entities/PhotoDTO";
|
||||
import {GridRowBuilder} from "./GridRowBuilder";
|
||||
import {GalleryLightboxComponent} from "../lightbox/lightbox.gallery.component";
|
||||
import {GridPhoto} from "./GridPhoto";
|
||||
@ -26,7 +26,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
|
||||
@ViewChild('gridContainer') gridContainer:ElementRef;
|
||||
@ViewChildren(GalleryPhotoComponent) gridPhotoQL:QueryList<GalleryPhotoComponent>;
|
||||
|
||||
@Input() photos:Array<Photo>;
|
||||
@Input() photos: Array<PhotoDTO>;
|
||||
@Input() lightbox:GalleryLightboxComponent;
|
||||
|
||||
photosToRender:Array<GridPhoto> = [];
|
||||
@ -87,7 +87,7 @@ export class GalleryGridComponent implements OnChanges,AfterViewInit {
|
||||
|
||||
private sortPhotos() {
|
||||
//sort pohots by date
|
||||
this.photos.sort((a:Photo, b:Photo) => {
|
||||
this.photos.sort((a: PhotoDTO, b: PhotoDTO) => {
|
||||
return a.metadata.creationDate.getTime() - b.metadata.creationDate.getTime();
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Component, QueryList, Output, EventEmitter, HostListener, ElementRef, ViewChild} from "@angular/core";
|
||||
import {Photo} from "../../../../common/entities/Photo";
|
||||
import {PhotoDTO} from "../../../../common/entities/PhotoDTO";
|
||||
import {GalleryPhotoComponent} from "../grid/photo/photo.grid.gallery.component";
|
||||
import {Dimension} from "../../model/IRenderable";
|
||||
import {FullScreenService} from "../fullscreen.service";
|
||||
@ -75,11 +75,11 @@ export class GalleryLightboxComponent {
|
||||
});
|
||||
}
|
||||
|
||||
public show(photo: Photo) {
|
||||
public show(photo: PhotoDTO) {
|
||||
this.visible = true;
|
||||
let selectedPhoto = this.findPhotoComponent(photo);
|
||||
if (selectedPhoto === null) {
|
||||
throw new Error("Can't find Photo");
|
||||
throw new Error("Can't find PhotoDTO");
|
||||
}
|
||||
|
||||
|
||||
@ -144,7 +144,7 @@ export class GalleryLightboxComponent {
|
||||
}
|
||||
|
||||
|
||||
private calcLightBoxPhotoDimension(photo: Photo): Dimension {
|
||||
private calcLightBoxPhotoDimension(photo: PhotoDTO): Dimension {
|
||||
let width = 0;
|
||||
let height = 0;
|
||||
if (photo.metadata.size.height > photo.metadata.size.width) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {Component, Input, OnChanges} from "@angular/core";
|
||||
import {Directory} from "../../../../common/entities/Directory";
|
||||
import {DirectoryDTO} from "../../../../common/entities/DirectoryDTO";
|
||||
import {RouterLink} from "@angular/router";
|
||||
|
||||
@Component({
|
||||
@ -8,7 +8,7 @@ import {RouterLink} from "@angular/router";
|
||||
providers: [RouterLink],
|
||||
})
|
||||
export class GalleryNavigatorComponent implements OnChanges {
|
||||
@Input() directory: Directory;
|
||||
@Input() directory: DirectoryDTO;
|
||||
|
||||
routes: Array<any> = [];
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user