Generate done.
This commit is contained in:
parent
222a3c2ddc
commit
ed022f7a55
|
@ -9,3 +9,4 @@ S3_ENDPOINT=""
|
||||||
UMAMI=""
|
UMAMI=""
|
||||||
DB="data/site.db"
|
DB="data/site.db"
|
||||||
ARTIST="Unknown"
|
ARTIST="Unknown"
|
||||||
|
GEOCODE_API_KEY=""
|
|
@ -9,7 +9,7 @@ class DB {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.log = (0, log_1.createLog)('db');
|
this.log = (0, log_1.createLog)('db');
|
||||||
this.db = new sqlite3_1.Database((0, env_1.envString)('DB', 'data/site.db'));
|
this.db = new sqlite3_1.Database((0, env_1.envString)('DB', 'data/site.db'));
|
||||||
this.db.run('PRAGMA journal_mode = WAL;');
|
//this.db.run( 'PRAGMA journal_mode = WAL;');
|
||||||
}
|
}
|
||||||
async run(query, args = null) {
|
async run(query, args = null) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
|
@ -20,6 +20,15 @@ class DB {
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
async all(query, args = null) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return this.db.all(query, args, (err, rows) => {
|
||||||
|
if (err)
|
||||||
|
return reject(err);
|
||||||
|
return resolve(rows);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
toBoolean(val) {
|
toBoolean(val) {
|
||||||
return val === 1 ? true : false;
|
return val === 1 ? true : false;
|
||||||
}
|
}
|
||||||
|
@ -41,12 +50,69 @@ class DB {
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.run(query, values);
|
await this.run(query, values);
|
||||||
this.log.info(`Inserted new photo`);
|
this.log.info(`Inserted new photo ${photo.name}`);
|
||||||
}
|
}
|
||||||
catch (err) {
|
catch (err) {
|
||||||
throw err;
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
async existsName(name) {
|
||||||
|
const query = `SELECT id FROM photos WHERE name = ? LIMIT 1;`;
|
||||||
|
let rows = [];
|
||||||
|
let exists = false;
|
||||||
|
try {
|
||||||
|
rows = await this.all(query, [name]);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error finding photo by name ${name}`, err);
|
||||||
|
}
|
||||||
|
if (rows.length > 0) {
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
async existsHash(hash) {
|
||||||
|
const query = `SELECT id FROM photos WHERE hash = ? LIMIT 1;`;
|
||||||
|
let rows = [];
|
||||||
|
let exists = false;
|
||||||
|
try {
|
||||||
|
rows = await this.all(query, [hash]);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error finding photo by hash ${hash}`, err);
|
||||||
|
}
|
||||||
|
if (rows.length > 0) {
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
async cacheLocation(location, latlng) {
|
||||||
|
const query = `INSERT OR IGNORE INTO geocode (location, latitude, longitude) VALUES (?, ?, ?);`;
|
||||||
|
try {
|
||||||
|
await this.run(query, [location, latlng.latitude, latlng.longitude]);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async getLocation(location) {
|
||||||
|
const query = `SELECT latitude, longitude FROM geocode WHERE location = ? LIMIT 1;`;
|
||||||
|
let rows = [];
|
||||||
|
let res = null;
|
||||||
|
try {
|
||||||
|
rows = await this.all(query, [location]);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
if (rows.length > 0) {
|
||||||
|
res = {
|
||||||
|
latitude: rows[0].latitude,
|
||||||
|
longitude: rows[0].longitude
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
exports.DB = DB;
|
exports.DB = DB;
|
||||||
module.exports = { DB };
|
module.exports = { DB };
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":";;;AAAA,yBAAuB;AAEvB,gCAAmC;AAEnC,qCAAmC;AACnC,gCAAmC;AAmBnC,MAAa,EAAE;IAId;QACC,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,IAAI,CAAC,CAAC;QAC3B,IAAI,CAAC,EAAE,GAAG,IAAI,kBAAQ,CAAC,IAAA,eAAS,EAAC,IAAI,EAAE,cAAc,CAAC,CAAC,CAAC;QACxD,IAAI,CAAC,EAAE,CAAC,GAAG,CAAE,4BAA4B,CAAC,CAAC;IAC5C,CAAC;IAEO,KAAK,CAAC,GAAG,CAAE,KAAc,EAAE,OAAe,IAAI;QACrD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;YAC5D,OAAO,IAAI,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,GAAW,EAAE,IAAY,EAAE,EAAE;gBAC7D,IAAI,GAAG;oBAAE,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;gBAC5B,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,SAAS,CAAE,GAAY;QAC9B,OAAO,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;IACjC,CAAC;IAEO,WAAW,CAAE,GAAa;QACjC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACpB,CAAC;IAED,mEAAmE;IAC5D,KAAK,CAAC,MAAM,CAAE,KAAa;QACjC,MAAM,IAAI,GAAc,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC3C,MAAM,KAAK,GAAY,uBAAuB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,aAAa,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA,EAAE,CAAA,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;QACzG,MAAM,MAAM,GAAW,EAAE,CAAC;QAC1B,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;YACtB,IAAI,OAAQ,KAAa,CAAC,GAAG,CAAC,KAAK,SAAS,EAAE,CAAC;gBAC9C,MAAM,CAAC,IAAI,CAAE,IAAI,CAAC,WAAW,CAAG,KAAa,CAAC,GAAG,CAAC,CAAE,CAAC,CAAC;YACvD,CAAC;iBAAM,CAAC;gBACP,MAAM,CAAC,IAAI,CAAE,KAAa,CAAC,GAAG,CAAC,CAAC,CAAC;YAClC,CAAC;QACF,CAAC;QACD,IAAI,CAAC;YACJ,MAAM,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC;YAC9B,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAA;QACpC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,MAAM,GAAG,CAAC;QACX,CAAC;IACF,CAAC;CAED;AA/CD,gBA+CC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,EAAE,EAAE,CAAC"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/db/index.ts"],"names":[],"mappings":"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"}
|
File diff suppressed because one or more lines are too long
|
@ -1,25 +1,43 @@
|
||||||
"use strict";
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
Object.defineProperty(exports, "__esModule", { value: true });
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
require("dotenv/config");
|
require("dotenv/config");
|
||||||
const log_1 = require("./log");
|
const log_1 = require("./log");
|
||||||
const promises_1 = require("fs/promises");
|
const promises_1 = require("fs/promises");
|
||||||
const path_1 = require("path");
|
const path_1 = require("path");
|
||||||
const util_1 = require("util");
|
const util_1 = require("util");
|
||||||
|
const uuid_1 = require("uuid");
|
||||||
|
const crypto_1 = require("crypto");
|
||||||
|
const os_1 = require("os");
|
||||||
|
const moment_1 = __importDefault(require("moment"));
|
||||||
|
const argparse_1 = require("argparse");
|
||||||
const shell_1 = require("./shell");
|
const shell_1 = require("./shell");
|
||||||
const hash_1 = require("./hash");
|
const hash_1 = require("./hash");
|
||||||
const files3_1 = require("./files3");
|
const files3_1 = require("./files3");
|
||||||
const env_1 = require("./env");
|
const env_1 = require("./env");
|
||||||
const db_1 = require("./db");
|
const db_1 = require("./db");
|
||||||
|
const geocode_1 = require("./geocode");
|
||||||
const sizeOf = (0, util_1.promisify)(require('image-size'));
|
const sizeOf = (0, util_1.promisify)(require('image-size'));
|
||||||
class Generate {
|
class Generate {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.inbox = (0, env_1.envString)('INBOX', '~/Photos/toprocess');
|
this.inbox = (0, env_1.envString)('INBOX', '~/Photos/toprocess');
|
||||||
this.photos = (0, env_1.envString)('PHOTOS', '~/Photos/processed');
|
this.photos = (0, env_1.envString)('PHOTOS', '~/Photos/processed');
|
||||||
|
this.artist = (0, env_1.envString)('ARTIST', 'Unknown');
|
||||||
|
this.tmp = (0, os_1.tmpdir)();
|
||||||
this.log = (0, log_1.createLog)('generate');
|
this.log = (0, log_1.createLog)('generate');
|
||||||
|
const parser = new argparse_1.ArgumentParser({
|
||||||
|
description: 'Generate script'
|
||||||
|
});
|
||||||
|
parser.add_argument('-s', '--score', { type: 'int', default: 0, help: 'Starting score' });
|
||||||
|
const args = parser.parse_args();
|
||||||
this.log.info(`Generating site: ${new Date()}`);
|
this.log.info(`Generating site: ${new Date()}`);
|
||||||
this.db = new db_1.DB();
|
this.db = new db_1.DB();
|
||||||
this.s3 = new files3_1.Files3((0, env_1.envString)('S3_BUCKET', 'mmcwilliamsphotos'), true);
|
this.s3 = new files3_1.Files3((0, env_1.envString)('S3_BUCKET', 's3bucket'), true);
|
||||||
|
this.geocode = new geocode_1.Geocode();
|
||||||
this.generate();
|
this.generate();
|
||||||
|
this.score = args.score;
|
||||||
}
|
}
|
||||||
async generate() {
|
async generate() {
|
||||||
//check version
|
//check version
|
||||||
|
@ -33,6 +51,7 @@ class Generate {
|
||||||
let filename;
|
let filename;
|
||||||
let meta;
|
let meta;
|
||||||
let photo;
|
let photo;
|
||||||
|
let exif;
|
||||||
try {
|
try {
|
||||||
inbox = await (0, promises_1.realpath)(this.inbox);
|
inbox = await (0, promises_1.realpath)(this.inbox);
|
||||||
}
|
}
|
||||||
|
@ -74,6 +93,19 @@ class Generate {
|
||||||
this.log.error(`Error creating photo record metadata`, err);
|
this.log.error(`Error creating photo record metadata`, err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (await this.db.existsName(filename)) {
|
||||||
|
this.log.info(`Image ${filename} already exists`);
|
||||||
|
if (await this.db.existsHash(photo.hash)) {
|
||||||
|
this.log.warn(`Image ${name} already exists, moving...`);
|
||||||
|
await this.move(image);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (await this.db.existsHash(photo.hash)) {
|
||||||
|
this.log.warn(`Image exists under different name, update?`);
|
||||||
|
await this.move(image);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
await this.db.create(photo);
|
await this.db.create(photo);
|
||||||
}
|
}
|
||||||
|
@ -88,11 +120,56 @@ class Generate {
|
||||||
this.log.error(`Error uploading image`, err);
|
this.log.error(`Error uploading image`, err);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
//await this.move(image);
|
try {
|
||||||
|
exif = await this.exif(photo);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error building EXIF data`, err);
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.img(image, photo.id, exif);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error running img.sh script`, err);
|
||||||
|
}
|
||||||
|
await this.move(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async img(file, exif) {
|
//Artist string
|
||||||
const cmd = ['bash', 'scripts/img.sh', file, exif];
|
//ImageTitle string
|
||||||
|
//ImageUniqueID string
|
||||||
|
//ISO int16u[n]
|
||||||
|
//DateTimeOriginal string (YYYY:MM:DD HH:MM:SS)
|
||||||
|
//
|
||||||
|
//GPSLatitude rational64u[3]
|
||||||
|
//GPSLongitude
|
||||||
|
async exif(photo) {
|
||||||
|
const filePath = await this.mktemp('photosite_exif');
|
||||||
|
const created = moment_1.default.unix(photo.created / 1000).format('YYYY:MM:DD HH:mm:ss');
|
||||||
|
let exif = `-Artist=${this.artist}
|
||||||
|
-ImageTitle=${photo.name}
|
||||||
|
-ImageUniqueId=${photo.id}
|
||||||
|
-DateTimeOriginal=${created}`;
|
||||||
|
const iso = photo.filmstock.split(' ').filter(el => this.isOnlyNumbers(el)).map(el => parseInt(el)).filter(el => el > 25);
|
||||||
|
if (iso.length > 0) {
|
||||||
|
exif += `
|
||||||
|
-ISO=${iso}`;
|
||||||
|
}
|
||||||
|
if (photo.latitude !== null && photo.longitude !== null) {
|
||||||
|
exif += `
|
||||||
|
-GPSLatitude=${photo.latitude}
|
||||||
|
-GPSLongitude=${photo.longitude}`;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await (0, promises_1.writeFile)(filePath, exif, 'utf8');
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error writing EXIF data`, err);
|
||||||
|
}
|
||||||
|
return filePath;
|
||||||
|
}
|
||||||
|
async img(file, id, exif) {
|
||||||
|
const cmd = ['bash', 'scripts/img.sh', file, id, exif];
|
||||||
const shell = new shell_1.Shell(cmd);
|
const shell = new shell_1.Shell(cmd);
|
||||||
try {
|
try {
|
||||||
await shell.execute();
|
await shell.execute();
|
||||||
|
@ -166,7 +243,9 @@ class Generate {
|
||||||
const hash = await hash_1.Hashes.fileHash(image);
|
const hash = await hash_1.Hashes.fileHash(image);
|
||||||
const dimensions = await this.getImageDimensions(image);
|
const dimensions = await this.getImageDimensions(image);
|
||||||
const now = Date.now();
|
const now = Date.now();
|
||||||
|
const latlng = await this.geocode.query(meta.location);
|
||||||
return {
|
return {
|
||||||
|
id: (0, uuid_1.v4)(),
|
||||||
name: (0, path_1.basename)(image),
|
name: (0, path_1.basename)(image),
|
||||||
original: meta.original,
|
original: meta.original,
|
||||||
hash,
|
hash,
|
||||||
|
@ -175,15 +254,48 @@ class Generate {
|
||||||
format: meta.format,
|
format: meta.format,
|
||||||
filmstock: meta.filmstock,
|
filmstock: meta.filmstock,
|
||||||
location: meta.location,
|
location: meta.location,
|
||||||
|
latitude: latlng === null ? null : latlng.latitude,
|
||||||
|
longitude: latlng === null ? null : latlng.longitude,
|
||||||
discovered: now,
|
discovered: now,
|
||||||
updated: now,
|
updated: now,
|
||||||
created: +new Date(meta.year, meta.month, meta.day)
|
created: +new Date(meta.year, meta.month, meta.day),
|
||||||
|
score: this.score
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
async upload(image) {
|
async upload(image) {
|
||||||
const name = (0, path_1.basename)(image);
|
const name = (0, path_1.basename)(image);
|
||||||
return this.s3.createFromPath(image, name);
|
return this.s3.createFromPath(image, name);
|
||||||
}
|
}
|
||||||
|
async move(image) {
|
||||||
|
const name = (0, path_1.basename)(image);
|
||||||
|
const dest = (0, path_1.join)(this.photos, name);
|
||||||
|
try {
|
||||||
|
//await rename(image, dest);
|
||||||
|
this.log.info(`Moved image ${name} to outbox`);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error(`Error moving image`, err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async mktemp(prefix = 'tmp') {
|
||||||
|
const uniqueId = (0, crypto_1.randomBytes)(16).toString('hex');
|
||||||
|
const tempFilePath = (0, path_1.join)(this.tmp, `${prefix}-${uniqueId}`);
|
||||||
|
try {
|
||||||
|
await (0, promises_1.writeFile)(tempFilePath, '', { flag: 'wx' });
|
||||||
|
return tempFilePath;
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
if (err.code === 'EEXIST') {
|
||||||
|
return this.mktemp(prefix);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isOnlyNumbers(str) {
|
||||||
|
return /^[0-9]+$/.test(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
new Generate();
|
new Generate();
|
||||||
//# sourceMappingURL=generate.js.map
|
//# sourceMappingURL=generate.js.map
|
File diff suppressed because one or more lines are too long
|
@ -0,0 +1,74 @@
|
||||||
|
"use strict";
|
||||||
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||||
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||||
|
};
|
||||||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||||||
|
exports.Geocode = void 0;
|
||||||
|
require("dotenv/config");
|
||||||
|
const url_1 = require("url");
|
||||||
|
const node_fetch_1 = __importDefault(require("node-fetch"));
|
||||||
|
const log_1 = require("../log");
|
||||||
|
const env_1 = require("../env");
|
||||||
|
const db_1 = require("../db");
|
||||||
|
class Geocode {
|
||||||
|
constructor() {
|
||||||
|
this.log = (0, log_1.createLog)('geocode');
|
||||||
|
this.baseUrl = 'https://geocode.maps.co/search';
|
||||||
|
this.apiKey = (0, env_1.envString)('GEOCODE_API_KEY', null);
|
||||||
|
this.db = new db_1.DB();
|
||||||
|
}
|
||||||
|
async query(location) {
|
||||||
|
let res = await this.db.getLocation(location);
|
||||||
|
if (res === null) {
|
||||||
|
res = await this.api(location);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
toLatLng(obj) {
|
||||||
|
return {
|
||||||
|
latitude: parseFloat(obj.lat),
|
||||||
|
longitude: parseFloat(obj.lon)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
//https://geocode.maps.co/search?q=&api_key=675738aa38619885468998kehbf6458
|
||||||
|
async api(location) {
|
||||||
|
const url = new url_1.URL(this.baseUrl);
|
||||||
|
let response;
|
||||||
|
let json;
|
||||||
|
let res = null;
|
||||||
|
url.searchParams.append('q', location);
|
||||||
|
this.log.info(`Querying API: ${url.href}`);
|
||||||
|
url.searchParams.append('api_key', this.apiKey);
|
||||||
|
await this.delay(1000); //rate limit to 1/sec
|
||||||
|
try {
|
||||||
|
response = await (0, node_fetch_1.default)(url.href);
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error('Error getting response', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
json = await response.json();
|
||||||
|
}
|
||||||
|
catch (err) {
|
||||||
|
this.log.error('Error parsing json', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (json.length < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
res = this.toLatLng(json[0]);
|
||||||
|
await this.db.cacheLocation(location, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
async delay(ms) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
return setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
cache(location, latitude, longitude) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exports.Geocode = Geocode;
|
||||||
|
module.exports = { Geocode };
|
||||||
|
//# sourceMappingURL=index.js.map
|
|
@ -0,0 +1 @@
|
||||||
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/geocode/index.ts"],"names":[],"mappings":";;;;;;AAAA,yBAAuB;AAEvB,6BAA0B;AAC1B,4DAA+B;AAG/B,gCAAmC;AAEnC,gCAAmC;AACnC,8BAA2B;AAG3B,MAAa,OAAO;IAMnB;QALQ,QAAG,GAAY,IAAA,eAAS,EAAC,SAAS,CAAC,CAAC;QACpC,YAAO,GAAY,gCAAgC,CAAC;QACpD,WAAM,GAAY,IAAA,eAAS,EAAC,iBAAiB,EAAE,IAAI,CAAC,CAAC;QACrD,OAAE,GAAQ,IAAI,OAAE,EAAE,CAAC;IAI3B,CAAC;IAEM,KAAK,CAAC,KAAK,CAAE,QAAiB;QACpC,IAAI,GAAG,GAAY,MAAM,IAAI,CAAC,EAAE,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAC;QACvD,IAAI,GAAG,KAAK,IAAI,EAAE,CAAC;YAClB,GAAG,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QACD,OAAO,GAAG,CAAC;IACZ,CAAC;IAEO,QAAQ,CAAE,GAAS;QAC1B,OAAO;YACN,QAAQ,EAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;YAC9B,SAAS,EAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC;SAC/B,CAAC;IACH,CAAC;IAED,2EAA2E;IACnE,KAAK,CAAC,GAAG,CAAE,QAAiB;QACnC,MAAM,GAAG,GAAS,IAAI,SAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxC,IAAI,QAAmB,CAAC;QACxB,IAAI,IAAU,CAAC;QACf,IAAI,GAAG,GAAY,IAAI,CAAC;QAExB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;QAEvC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC;QAC3C,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;QAEhD,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,qBAAqB;QAE7C,IAAI,CAAC;YACJ,QAAQ,GAAG,MAAM,IAAA,oBAAK,EAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAClC,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,wBAAwB,EAAE,GAAG,CAAC,CAAC;YAC9C,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,CAAC;YACJ,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QAC9B,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACd,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,EAAE,GAAG,CAAC,CAAC;YAC1C,OAAO,IAAI,CAAC;QACb,CAAC;QAED,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,OAAO,IAAI,CAAC;QACb,CAAC;QAED,GAAG,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;QAE7B,MAAM,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;QAE3C,OAAO,GAAG,CAAC;IAEZ,CAAC;IAEO,KAAK,CAAC,KAAK,CAAE,EAAW;QAC/B,OAAO,IAAI,OAAO,CAAE,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;YAC7D,OAAO,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;QAChC,CAAC,CAAC,CAAC;IACJ,CAAC;IAEO,KAAK,CAAE,QAAiB,EAAE,QAAiB,EAAE,SAAkB;IAEvE,CAAC;CACD;AA1ED,0BA0EC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,OAAO,EAAE,CAAC"}
|
|
@ -24,7 +24,8 @@ class Shell {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
this.child = (0, child_process_1.spawn)(this.bin, this.args);
|
this.child = (0, child_process_1.spawn)(this.bin, this.args);
|
||||||
this.log.info(`Shell: ${this.bin} ${this.args.join(' ')}`);
|
this.log.info(`Shell: ${this.bin} ${this.args.join(' ')}`);
|
||||||
this.child.stdout.on('data', (data) => {
|
this.child.stdout.on('data', (output) => {
|
||||||
|
const data = output.toString();
|
||||||
if (!this.silent)
|
if (!this.silent)
|
||||||
this.log.info(data);
|
this.log.info(data);
|
||||||
if (this.after !== null)
|
if (this.after !== null)
|
||||||
|
@ -33,7 +34,8 @@ class Shell {
|
||||||
this.stdio(data);
|
this.stdio(data);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
this.child.stderr.on('data', (data) => {
|
this.child.stderr.on('data', (output) => {
|
||||||
|
const data = output.toString();
|
||||||
if (!this.silent)
|
if (!this.silent)
|
||||||
this.log.warn(data);
|
this.log.warn(data);
|
||||||
if (this.stderr !== null) {
|
if (this.stderr !== null) {
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":";;;AAAA,iDAAsE;AACtE,gCAAmC;AAEnC,2BAAyB;AAEzB,MAAa,KAAK;IAWjB,YAAa,IAAY,EAAE,QAAmB,IAAI,EAAE,SAAoB,IAAI,EAAE,QAAmB,IAAI,EAAE,SAAmB,KAAK;QANvH,UAAK,GAAc,EAAE,CAAC;QACtB,UAAK,GAAc,IAAI,CAAC;QACxB,WAAM,GAAc,IAAI,CAAC;QACzB,UAAK,GAAc,IAAI,CAAC;QACxB,WAAM,GAAa,KAAK,CAAC;QAGhC,MAAM,GAAG,GAAY,IAAI,CAAC,KAAK,EAAE,CAAC;QAClC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,GAAG,GAAG,IAAA,eAAS,EAAC,GAAG,CAAC,CAAC;IAC3B,CAAC;IAEM,KAAK,CAAC,OAAO;QACnB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAkB,EAAE,MAAiB,EAAE,EAAE;YAC5D,IAAI,CAAC,KAAK,GAAG,IAAA,qBAAK,EAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;YAExC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,UAAU,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAE3D,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAa,EAAE,EAAE;gBAC9C,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI;oBAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBAC/C,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;oBACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAClB,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAa,EAAE,EAAE;gBAC9C,IAAI,CAAC,IAAI,CAAC,MAAM;oBAAE,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtC,IAAI,IAAI,CAAC,MAAM,KAAK,IAAI,EAAE,CAAC;oBAC1B,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;gBACnB,CAAC;YACF,CAAC,CAAC,CAAC;YAEH,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAa,EAAE,EAAE;gBACxC,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;oBACzB,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAG,CAAC,CAAC,CAAC;gBAClC,CAAC;gBACD,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;oBAChB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBAC9D,OAAO,OAAO,CAAC,IAAI,CAAC,CAAC;gBACtB,CAAC;qBAAM,CAAC;oBACP,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,oBAAoB,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;oBACtE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;gBACrB,CAAC;YACF,CAAC,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;IAEM,IAAI;QACV,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,IAAI,CAAC,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC7D,2BAA2B;QAC3B,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IACnB,CAAC;CACD;AA/DD,sBA+DC;AAED,MAAM,CAAC,OAAO,GAAG,EAAE,KAAK,EAAE,CAAC"}
|
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/shell/index.ts"],"names":[],"mappings":"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"}
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
exiftool -overwrite_original -@ exif_test.txt exif_test.jpg
|
|
@ -0,0 +1,7 @@
|
||||||
|
-Artist=Test Artist
|
||||||
|
-ImageTitle=A title that I selected
|
||||||
|
-ImageUniqueID=11111111111111
|
||||||
|
-ISOSpeed=400
|
||||||
|
-DateTimeOriginal=2024:12:08 12:00:00
|
||||||
|
-GPSLatitude=42.000000
|
||||||
|
-GPSLongitude=71.000000
|
|
@ -1,8 +0,0 @@
|
||||||
-XPTitle=Title here
|
|
||||||
-XPSubject=Subject here
|
|
||||||
-XPComment=Comments here
|
|
||||||
-XPArtist=Test Artist
|
|
||||||
-XPImageTitle
|
|
||||||
-XPImageUniqueID
|
|
||||||
-XPISOSpeed
|
|
||||||
-XPDateTimeOriginal
|
|
|
@ -10,14 +10,16 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.13.18",
|
"@atproto/api": "^0.13.18",
|
||||||
|
"argparse": "^2.0.1",
|
||||||
"aws-sdk": "^2.1692.0",
|
"aws-sdk": "^2.1692.0",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"handlebars-helpers": "^0.10.0",
|
"handlebars-helpers": "^0.10.0",
|
||||||
"image-size": "^1.1.1",
|
"image-size": "^1.1.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mime": "^4.0.1",
|
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"node-fetch": "^2.7.0",
|
||||||
"s3-cli": "^0.13.0",
|
"s3-cli": "^0.13.0",
|
||||||
"s3-upload-stream": "^1.0.7",
|
"s3-upload-stream": "^1.0.7",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
@ -26,10 +28,13 @@
|
||||||
"winston": "^3.11.0"
|
"winston": "^3.11.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/argparse": "^2.0.17",
|
||||||
"@types/handlebars-helpers": "^0.5.6",
|
"@types/handlebars-helpers": "^0.5.6",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
"@types/node": "^20.10.6",
|
"@types/node": "^20.10.6",
|
||||||
|
"@types/node-fetch": "^2.6.11",
|
||||||
"@types/s3-upload-stream": "^1.0.7",
|
"@types/s3-upload-stream": "^1.0.7",
|
||||||
"@types/sqlite3": "^3.1.11",
|
"@types/sqlite3": "^3.1.11",
|
||||||
"@types/triple-beam": "^1.3.5",
|
"@types/triple-beam": "^1.3.5",
|
||||||
|
@ -188,6 +193,13 @@
|
||||||
"node": ">= 6"
|
"node": ">= 6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/argparse": {
|
||||||
|
"version": "2.0.17",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/argparse/-/argparse-2.0.17.tgz",
|
||||||
|
"integrity": "sha512-fueJssTf+4dW4HODshEGkIZbkLKHzgu1FvCI4cTc/MKum/534Euo3SrN+ilq8xgyHnOjtmg33/hee8iXLRg1XA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/@types/aws-sdk2-types": {
|
"node_modules/@types/aws-sdk2-types": {
|
||||||
"version": "0.0.5",
|
"version": "0.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/@types/aws-sdk2-types/-/aws-sdk2-types-0.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/@types/aws-sdk2-types/-/aws-sdk2-types-0.0.5.tgz",
|
||||||
|
@ -222,6 +234,17 @@
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/moment": {
|
||||||
|
"version": "2.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/moment/-/moment-2.13.0.tgz",
|
||||||
|
"integrity": "sha512-DyuyYGpV6r+4Z1bUznLi/Y7HpGn4iQ4IVcGn8zrr1P4KotKLdH0sbK1TFR6RGyX6B+G8u83wCzL+bpawKU/hdQ==",
|
||||||
|
"deprecated": "This is a stub types definition for Moment (https://github.com/moment/moment). Moment provides its own type definitions, so you don't need @types/moment installed!",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"moment": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/node": {
|
"node_modules/@types/node": {
|
||||||
"version": "20.17.9",
|
"version": "20.17.9",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.9.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.9.tgz",
|
||||||
|
@ -232,6 +255,17 @@
|
||||||
"undici-types": "~6.19.2"
|
"undici-types": "~6.19.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/node-fetch": {
|
||||||
|
"version": "2.6.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.11.tgz",
|
||||||
|
"integrity": "sha512-24xFj9R5+rfQJLRyM56qh+wnVSYhyXC2tkoBndtY0U+vubqNsYXGjufB2nn8Q6gt0LrARwL6UBtMCSVCwl4B1g==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/node": "*",
|
||||||
|
"form-data": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@types/s3-upload-stream": {
|
"node_modules/@types/s3-upload-stream": {
|
||||||
"version": "1.0.7",
|
"version": "1.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/@types/s3-upload-stream/-/s3-upload-stream-1.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/@types/s3-upload-stream/-/s3-upload-stream-1.0.7.tgz",
|
||||||
|
@ -741,13 +775,10 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/argparse": {
|
"node_modules/argparse": {
|
||||||
"version": "1.0.10",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
|
||||||
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
"integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==",
|
||||||
"license": "MIT",
|
"license": "Python-2.0"
|
||||||
"dependencies": {
|
|
||||||
"sprintf-js": "~1.0.2"
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"node_modules/arr-diff": {
|
"node_modules/arr-diff": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
|
@ -823,6 +854,13 @@
|
||||||
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
"integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/asynckit": {
|
||||||
|
"version": "0.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
|
||||||
|
"integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/atob": {
|
"node_modules/atob": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
|
||||||
|
@ -1254,6 +1292,19 @@
|
||||||
"text-hex": "1.0.x"
|
"text-hex": "1.0.x"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/combined-stream": {
|
||||||
|
"version": "1.0.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
|
||||||
|
"integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"delayed-stream": "~1.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 0.8"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/component-emitter": {
|
"node_modules/component-emitter": {
|
||||||
"version": "1.3.1",
|
"version": "1.3.1",
|
||||||
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
|
"resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.1.tgz",
|
||||||
|
@ -1442,6 +1493,16 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/delayed-stream": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
|
"integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.4.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/delegates": {
|
"node_modules/delegates": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
|
@ -1785,6 +1846,21 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/form-data": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"asynckit": "^0.4.0",
|
||||||
|
"combined-stream": "^1.0.8",
|
||||||
|
"mime-types": "^2.1.12"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/fragment-cache": {
|
"node_modules/fragment-cache": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
|
||||||
|
@ -3065,21 +3141,6 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/mime": {
|
|
||||||
"version": "4.0.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/mime/-/mime-4.0.4.tgz",
|
|
||||||
"integrity": "sha512-v8yqInVjhXyqP6+Kw4fV3ZzeMRqEW6FotRsKXjRS5VMTNIuXsdRoAvklpoRgSqXm6o9VNH4/C0mgedko9DdLsQ==",
|
|
||||||
"funding": [
|
|
||||||
"https://github.com/sponsors/broofa"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"bin": {
|
|
||||||
"mime": "bin/cli.js"
|
|
||||||
},
|
|
||||||
"engines": {
|
|
||||||
"node": ">=16"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/mime-db": {
|
"node_modules/mime-db": {
|
||||||
"version": "1.52.0",
|
"version": "1.52.0",
|
||||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||||
|
@ -3401,6 +3462,26 @@
|
||||||
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
"integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/node-fetch": {
|
||||||
|
"version": "2.7.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
|
||||||
|
"integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"whatwg-url": "^5.0.0"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "4.x || >=6.0.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"encoding": "^0.1.0"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"encoding": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/node-gyp": {
|
"node_modules/node-gyp": {
|
||||||
"version": "8.4.1",
|
"version": "8.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz",
|
||||||
|
@ -3864,6 +3945,15 @@
|
||||||
"node": ">= 0.10.0"
|
"node": ">= 0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/remarkable/node_modules/argparse": {
|
||||||
|
"version": "1.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||||
|
"integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"sprintf-js": "~1.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/repeat-element": {
|
"node_modules/repeat-element": {
|
||||||
"version": "1.1.4",
|
"version": "1.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
"resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.4.tgz",
|
||||||
|
@ -4837,6 +4927,12 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/tr46": {
|
||||||
|
"version": "0.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||||
|
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/triple-beam": {
|
"node_modules/triple-beam": {
|
||||||
"version": "1.4.1",
|
"version": "1.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz",
|
||||||
|
@ -5081,6 +5177,22 @@
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webidl-conversions": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==",
|
||||||
|
"license": "BSD-2-Clause"
|
||||||
|
},
|
||||||
|
"node_modules/whatwg-url": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
||||||
|
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"tr46": "~0.0.3",
|
||||||
|
"webidl-conversions": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
@ -17,10 +17,13 @@
|
||||||
"author": "Matthew McWilliams",
|
"author": "Matthew McWilliams",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@types/argparse": "^2.0.17",
|
||||||
"@types/handlebars-helpers": "^0.5.6",
|
"@types/handlebars-helpers": "^0.5.6",
|
||||||
"@types/lodash": "^4.14.202",
|
"@types/lodash": "^4.14.202",
|
||||||
"@types/mime-types": "^2.1.4",
|
"@types/mime-types": "^2.1.4",
|
||||||
|
"@types/moment": "^2.13.0",
|
||||||
"@types/node": "^20.10.6",
|
"@types/node": "^20.10.6",
|
||||||
|
"@types/node-fetch": "^2.6.11",
|
||||||
"@types/s3-upload-stream": "^1.0.7",
|
"@types/s3-upload-stream": "^1.0.7",
|
||||||
"@types/sqlite3": "^3.1.11",
|
"@types/sqlite3": "^3.1.11",
|
||||||
"@types/triple-beam": "^1.3.5",
|
"@types/triple-beam": "^1.3.5",
|
||||||
|
@ -30,14 +33,16 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@atproto/api": "^0.13.18",
|
"@atproto/api": "^0.13.18",
|
||||||
|
"argparse": "^2.0.1",
|
||||||
"aws-sdk": "^2.1692.0",
|
"aws-sdk": "^2.1692.0",
|
||||||
"dotenv": "^16.3.1",
|
"dotenv": "^16.3.1",
|
||||||
"handlebars": "^4.7.8",
|
"handlebars": "^4.7.8",
|
||||||
"handlebars-helpers": "^0.10.0",
|
"handlebars-helpers": "^0.10.0",
|
||||||
"image-size": "^1.1.1",
|
"image-size": "^1.1.1",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
"mime": "^4.0.1",
|
|
||||||
"mime-types": "^2.1.35",
|
"mime-types": "^2.1.35",
|
||||||
|
"moment": "^2.30.1",
|
||||||
|
"node-fetch": "^2.7.0",
|
||||||
"s3-cli": "^0.13.0",
|
"s3-cli": "^0.13.0",
|
||||||
"s3-upload-stream": "^1.0.7",
|
"s3-upload-stream": "^1.0.7",
|
||||||
"sqlite3": "^5.1.7",
|
"sqlite3": "^5.1.7",
|
||||||
|
|
|
@ -2,5 +2,5 @@
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
node dist/generate
|
bash scripts/generate.sh
|
||||||
node dist/build
|
bash scripts/build.sh
|
|
@ -6,6 +6,7 @@ source .env
|
||||||
|
|
||||||
rm -rf data/site.db
|
rm -rf data/site.db
|
||||||
mkdir -p data
|
mkdir -p data
|
||||||
|
mkdir -p www
|
||||||
|
|
||||||
cat "sql/setup.sql" | sqlite3 "${DB}"
|
cat "sql/setup.sql" | sqlite3 "${DB}"
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ ID="${2}"
|
||||||
EXIF="${3}"
|
EXIF="${3}"
|
||||||
|
|
||||||
SIZES=(
|
SIZES=(
|
||||||
"home:420"
|
"thumb:420"
|
||||||
"full:2000"
|
"full:2000"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,9 +26,7 @@ for sizeRaw in ${SIZES[@]}; do
|
||||||
size=$(echo $sizeRaw | awk -F':' '{print $2}')
|
size=$(echo $sizeRaw | awk -F':' '{print $2}')
|
||||||
name=$(basename "${1}")
|
name=$(basename "${1}")
|
||||||
name=${name%.*}
|
name=${name%.*}
|
||||||
output="${WWW}/img/${ID}_${size}.jpg"
|
output="${WWW}/img/${ID}_${sizeName}.jpg"
|
||||||
img "${1}" "${output}" "${size}"
|
img "${1}" "${output}" "${size}"
|
||||||
exiftool -overwrite_original -@ "${EXIF}" "${output}"
|
exiftool -overwrite_original -@ "${EXIF}" "${output}"
|
||||||
done
|
done
|
||||||
|
|
||||||
mv "${1}" "${PHOTOS}/"
|
|
||||||
|
|
|
@ -8,6 +8,8 @@ CREATE TABLE IF NOT EXISTS photos (
|
||||||
format TEXT,
|
format TEXT,
|
||||||
filmstock TEXT,
|
filmstock TEXT,
|
||||||
location TEXT,
|
location TEXT,
|
||||||
|
latitude REAL,
|
||||||
|
longitude REAL,
|
||||||
discovered INTEGER,
|
discovered INTEGER,
|
||||||
created INTEGER,
|
created INTEGER,
|
||||||
updated INTEGER,
|
updated INTEGER,
|
||||||
|
@ -16,7 +18,8 @@ CREATE TABLE IF NOT EXISTS photos (
|
||||||
deleted INTEGER DEFAULT 0
|
deleted INTEGER DEFAULT 0
|
||||||
);
|
);
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS version (
|
CREATE TABLE IF NOT EXISTS geocode (
|
||||||
id TEXT PRIMARY KEY,
|
location TEXT PRIMARY KEY,
|
||||||
updated INTEGER UNIQUE
|
latitude REAL,
|
||||||
)
|
longitude REAL
|
||||||
|
);
|
|
@ -5,6 +5,11 @@ import type { Logger } from 'winston';
|
||||||
import { Database } from 'sqlite3';
|
import { Database } from 'sqlite3';
|
||||||
import { envString } from '../env';
|
import { envString } from '../env';
|
||||||
|
|
||||||
|
interface LatLng {
|
||||||
|
latitude : number;
|
||||||
|
longitude : number;
|
||||||
|
}
|
||||||
|
|
||||||
interface Photo {
|
interface Photo {
|
||||||
id : string;
|
id : string;
|
||||||
name : string;
|
name : string;
|
||||||
|
@ -15,6 +20,8 @@ interface Photo {
|
||||||
format? : string;
|
format? : string;
|
||||||
filmstock? : string;
|
filmstock? : string;
|
||||||
location? : string;
|
location? : string;
|
||||||
|
latitude? : number;
|
||||||
|
longitude? : number;
|
||||||
discovered ? : number;
|
discovered ? : number;
|
||||||
created? : number;
|
created? : number;
|
||||||
updated? : number;
|
updated? : number;
|
||||||
|
@ -30,7 +37,7 @@ export class DB {
|
||||||
constructor () {
|
constructor () {
|
||||||
this.log = createLog('db');
|
this.log = createLog('db');
|
||||||
this.db = new Database(envString('DB', 'data/site.db'));
|
this.db = new Database(envString('DB', 'data/site.db'));
|
||||||
this.db.run( 'PRAGMA journal_mode = WAL;');
|
//this.db.run( 'PRAGMA journal_mode = WAL;');
|
||||||
}
|
}
|
||||||
|
|
||||||
private async run (query : string, args : any[] = null) {
|
private async run (query : string, args : any[] = null) {
|
||||||
|
@ -109,7 +116,37 @@ export class DB {
|
||||||
return exists;
|
return exists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async cacheLocation (location : string, latlng : LatLng) {
|
||||||
|
const query : string = `INSERT OR IGNORE INTO geocode (location, latitude, longitude) VALUES (?, ?, ?);`;
|
||||||
|
try {
|
||||||
|
await this.run(query, [location, latlng.latitude, latlng.longitude]);
|
||||||
|
} catch (err) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getLocation (location : string) : Promise<LatLng> {
|
||||||
|
const query : string = `SELECT latitude, longitude FROM geocode WHERE location = ? LIMIT 1;`;
|
||||||
|
let rows : any[] = [];
|
||||||
|
let res : LatLng = null;
|
||||||
|
try {
|
||||||
|
rows = await this.all(query, [location]);
|
||||||
|
} catch (err) {
|
||||||
|
//ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows.length > 0) {
|
||||||
|
res = {
|
||||||
|
latitude : rows[0].latitude,
|
||||||
|
longitude : rows[0].longitude
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = { DB };
|
module.exports = { DB };
|
||||||
export type { Photo };
|
export type { Photo, LatLng };
|
|
@ -7,12 +7,15 @@ import { promisify } from 'util';
|
||||||
import { v4 as uuid } from 'uuid';
|
import { v4 as uuid } from 'uuid';
|
||||||
import { randomBytes } from 'crypto';
|
import { randomBytes } from 'crypto';
|
||||||
import { tmpdir } from 'os';
|
import { tmpdir } from 'os';
|
||||||
|
import moment from 'moment';
|
||||||
|
import { ArgumentParser } from 'argparse';
|
||||||
import { Shell } from './shell';
|
import { Shell } from './shell';
|
||||||
import { Hashes } from './hash';
|
import { Hashes } from './hash';
|
||||||
import { Files3 } from './files3'
|
import { Files3 } from './files3'
|
||||||
import { envString } from './env';
|
import { envString } from './env';
|
||||||
import { DB } from './db';
|
import { DB } from './db';
|
||||||
import type { Photo } from './db';
|
import type { Photo, LatLng } from './db';
|
||||||
|
import { Geocode } from './geocode';
|
||||||
|
|
||||||
const sizeOf = promisify(require('image-size'));
|
const sizeOf = promisify(require('image-size'));
|
||||||
|
|
||||||
|
@ -35,14 +38,24 @@ class Generate {
|
||||||
private artist : string = envString('ARTIST', 'Unknown');
|
private artist : string = envString('ARTIST', 'Unknown');
|
||||||
private s3 : Files3;
|
private s3 : Files3;
|
||||||
private db : DB;
|
private db : DB;
|
||||||
|
private geocode : Geocode;
|
||||||
private tmp : string = tmpdir();
|
private tmp : string = tmpdir();
|
||||||
|
private score : number;
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
this.log = createLog('generate');
|
this.log = createLog('generate');
|
||||||
|
const parser = new ArgumentParser({
|
||||||
|
description: 'Generate script'
|
||||||
|
});
|
||||||
|
parser.add_argument('-s', '--score', { type : 'int', default : 0, help: 'Starting score' });
|
||||||
|
const args : any = parser.parse_args();
|
||||||
|
|
||||||
this.log.info(`Generating site: ${new Date()}`);
|
this.log.info(`Generating site: ${new Date()}`);
|
||||||
this.db = new DB();
|
this.db = new DB();
|
||||||
this.s3 = new Files3(envString('S3_BUCKET', 's3bucket'), true);
|
this.s3 = new Files3(envString('S3_BUCKET', 's3bucket'), true);
|
||||||
|
this.geocode = new Geocode();
|
||||||
this.generate();
|
this.generate();
|
||||||
|
this.score = args.score;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async generate () {
|
private async generate () {
|
||||||
|
@ -59,6 +72,7 @@ class Generate {
|
||||||
let filename : string;
|
let filename : string;
|
||||||
let meta : Metadata;
|
let meta : Metadata;
|
||||||
let photo : Photo;
|
let photo : Photo;
|
||||||
|
let exif : string;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
inbox = await realpath(this.inbox);
|
inbox = await realpath(this.inbox);
|
||||||
|
@ -136,27 +150,60 @@ class Generate {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
exif = await this.exif(photo);
|
||||||
|
} catch (err) {
|
||||||
|
this.log.error(`Error building EXIF data`, err);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
await this.img(image, photo.id, exif);
|
||||||
|
} catch (err) {
|
||||||
|
this.log.error(`Error running img.sh script`, err);
|
||||||
|
}
|
||||||
|
|
||||||
await this.move(image);
|
await this.move(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//Artist
|
//Artist string
|
||||||
//ImageTitle
|
//ImageTitle string
|
||||||
//ImageUniqueID
|
//ImageUniqueID string
|
||||||
//ISOSpeed
|
//ISO int16u[n]
|
||||||
//DateTimeOriginal
|
//DateTimeOriginal string (YYYY:MM:DD HH:MM:SS)
|
||||||
|
//
|
||||||
|
//GPSLatitude rational64u[3]
|
||||||
|
//GPSLongitude
|
||||||
private async exif (photo : Photo) : Promise<string> {
|
private async exif (photo : Photo) : Promise<string> {
|
||||||
const filePath : string = await this.mktemp('photosite_exif');
|
const filePath : string = await this.mktemp('photosite_exif');
|
||||||
|
const created : string = moment.unix(photo.created / 1000).format('YYYY:MM:DD HH:mm:ss');
|
||||||
|
let exif : string = `-Artist=${this.artist}
|
||||||
|
-ImageTitle=${photo.name}
|
||||||
|
-ImageUniqueId=${photo.id}
|
||||||
|
-DateTimeOriginal=${created}`
|
||||||
|
const iso : number[] = photo.filmstock.split(' ').filter(el => this.isOnlyNumbers(el)).map(el => parseInt(el)).filter(el => el > 25);
|
||||||
|
|
||||||
|
if (iso.length > 0) {
|
||||||
|
exif += `
|
||||||
|
-ISO=${iso}`
|
||||||
|
}
|
||||||
|
|
||||||
|
if (photo.latitude !== null && photo.longitude !== null) {
|
||||||
|
exif += `
|
||||||
|
-GPSLatitude=${photo.latitude}
|
||||||
|
-GPSLongitude=${photo.longitude}`
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
await writeFile(filePath, exif, 'utf8');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
this.log.error(`Error writing EXIF data`, err);
|
||||||
}
|
}
|
||||||
|
|
||||||
return filePath;
|
return filePath;
|
||||||
}
|
}
|
||||||
private async img (file : string, id : string, exif : string) {
|
private async img (file : string, id : string, exif : string) {
|
||||||
const cmd : string[] = ['bash', 'scripts/img.sh', file, exif];
|
const cmd : string[] = ['bash', 'scripts/img.sh', file, id, exif];
|
||||||
const shell : Shell = new Shell(cmd);
|
const shell : Shell = new Shell(cmd);
|
||||||
try {
|
try {
|
||||||
await shell.execute();
|
await shell.execute();
|
||||||
|
@ -235,6 +282,8 @@ class Generate {
|
||||||
const hash : string = await Hashes.fileHash(image);
|
const hash : string = await Hashes.fileHash(image);
|
||||||
const dimensions : any = await this.getImageDimensions(image);
|
const dimensions : any = await this.getImageDimensions(image);
|
||||||
const now : number = Date.now();
|
const now : number = Date.now();
|
||||||
|
const latlng : LatLng = await this.geocode.query(meta.location);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
id : uuid(),
|
id : uuid(),
|
||||||
name : basename(image),
|
name : basename(image),
|
||||||
|
@ -245,9 +294,12 @@ class Generate {
|
||||||
format : meta.format,
|
format : meta.format,
|
||||||
filmstock : meta.filmstock,
|
filmstock : meta.filmstock,
|
||||||
location : meta.location,
|
location : meta.location,
|
||||||
|
latitude : latlng === null ? null : latlng.latitude,
|
||||||
|
longitude : latlng === null ? null : latlng.longitude,
|
||||||
discovered : now,
|
discovered : now,
|
||||||
updated : now,
|
updated : now,
|
||||||
created : + new Date(meta.year, meta.month, meta.day)
|
created : + new Date(meta.year, meta.month, meta.day),
|
||||||
|
score : this.score
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -261,7 +313,7 @@ class Generate {
|
||||||
const dest : string = join(this.photos, name);
|
const dest : string = join(this.photos, name);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await rename(image, dest);
|
//await rename(image, dest);
|
||||||
this.log.info(`Moved image ${name} to outbox`);
|
this.log.info(`Moved image ${name} to outbox`);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.log.error(`Error moving image`, err);
|
this.log.error(`Error moving image`, err);
|
||||||
|
@ -283,6 +335,10 @@ class Generate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private isOnlyNumbers(str : string) : boolean {
|
||||||
|
return /^[0-9]+$/.test(str);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
new Generate();
|
new Generate();
|
|
@ -0,0 +1,89 @@
|
||||||
|
import 'dotenv/config';
|
||||||
|
|
||||||
|
import { URL } from 'url';
|
||||||
|
import fetch from 'node-fetch';
|
||||||
|
import type { Response } from 'node-fetch';
|
||||||
|
|
||||||
|
import { createLog } from '../log';
|
||||||
|
import type { Logger } from 'winston';
|
||||||
|
import { envString } from '../env';
|
||||||
|
import { DB } from '../db';
|
||||||
|
import type { LatLng } from '../db';
|
||||||
|
|
||||||
|
export class Geocode {
|
||||||
|
private log : Logger = createLog('geocode');
|
||||||
|
private baseUrl : string = 'https://geocode.maps.co/search';
|
||||||
|
private apiKey : string = envString('GEOCODE_API_KEY', null);
|
||||||
|
private db : DB = new DB();
|
||||||
|
|
||||||
|
constructor () {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public async query (location : string) : Promise<LatLng> {
|
||||||
|
let res : LatLng = await this.db.getLocation(location);
|
||||||
|
if (res === null) {
|
||||||
|
res = await this.api(location);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toLatLng (obj : any) : LatLng {
|
||||||
|
return {
|
||||||
|
latitude : parseFloat(obj.lat),
|
||||||
|
longitude : parseFloat(obj.lon)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//https://geocode.maps.co/search?q=&api_key=675738aa38619885468998kehbf6458
|
||||||
|
private async api (location : string) : Promise<LatLng> {
|
||||||
|
const url : URL = new URL(this.baseUrl);
|
||||||
|
let response : Response;
|
||||||
|
let json : any;
|
||||||
|
let res : LatLng = null;
|
||||||
|
|
||||||
|
url.searchParams.append('q', location);
|
||||||
|
|
||||||
|
this.log.info(`Querying API: ${url.href}`);
|
||||||
|
url.searchParams.append('api_key', this.apiKey);
|
||||||
|
|
||||||
|
await this.delay(1000); //rate limit to 1/sec
|
||||||
|
|
||||||
|
try {
|
||||||
|
response = await fetch(url.href);
|
||||||
|
} catch (err) {
|
||||||
|
this.log.error('Error getting response', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
json = await response.json();
|
||||||
|
} catch (err) {
|
||||||
|
this.log.error('Error parsing json', err);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (json.length < 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = this.toLatLng(json[0]);
|
||||||
|
|
||||||
|
await this.db.cacheLocation(location, res);
|
||||||
|
|
||||||
|
return res;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async delay (ms : number) {
|
||||||
|
return new Promise ((resolve : Function, reject : Function) => {
|
||||||
|
return setTimeout(resolve, ms);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private cache (location : string, latitude : number, longitude : number) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { Geocode };
|
|
@ -31,7 +31,8 @@ export class Shell {
|
||||||
|
|
||||||
this.log.info(`Shell: ${this.bin} ${this.args.join(' ')}`);
|
this.log.info(`Shell: ${this.bin} ${this.args.join(' ')}`);
|
||||||
|
|
||||||
this.child.stdout.on('data', (data : string) => {
|
this.child.stdout.on('data', (output : Object) => {
|
||||||
|
const data : string = output.toString();
|
||||||
if (!this.silent) this.log.info(data);
|
if (!this.silent) this.log.info(data);
|
||||||
if (this.after !== null) this.lines.push(data);
|
if (this.after !== null) this.lines.push(data);
|
||||||
if (this.stdio !== null) {
|
if (this.stdio !== null) {
|
||||||
|
@ -39,7 +40,8 @@ export class Shell {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.child.stderr.on('data', (data : string) => {
|
this.child.stderr.on('data', (output : Object) => {
|
||||||
|
const data : string = output.toString();
|
||||||
if (!this.silent) this.log.warn(data);
|
if (!this.silent) this.log.warn(data);
|
||||||
if (this.stderr !== null) {
|
if (this.stderr !== null) {
|
||||||
this.stderr(data);
|
this.stderr(data);
|
||||||
|
|
Loading…
Reference in New Issue