dayone_photos_dumper
Advanced tools
Comparing version 0.0.2 to 0.0.3
#!/usr/bin/env node | ||
"use strict"; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
@@ -32,2 +33,3 @@ }); | ||
.option('-s, --source_dir <dir>', `source dir, default is Dayone2 document path: ${DAYONE_DOCUMENTS}, could switch to your backup dir`) | ||
.option('-d, --database_path <dir>', 'database file path, dayone2 default path would be used if undefined') | ||
.parse(process.argv); | ||
@@ -37,2 +39,3 @@ const ARGS_ENTRY_INFO = program.entry === undefined ? undefined : program.entry; | ||
const ARGS_SOURCE_DIR = program.source_dir === undefined ? DAYONE_DOCUMENTS : program.source_dir; | ||
const ARGS_DB_DIR = program.database_path === undefined ? undefined : program.database_path; | ||
class DayOnePhotosDumper { | ||
@@ -79,2 +82,6 @@ run() { | ||
} | ||
if (ARGS_DB_DIR !== undefined && !(yield LibFs.exists(ARGS_DB_DIR))) { | ||
console.log('Valid database directory required, please check -d option'); | ||
process.exit(1); | ||
} | ||
}); | ||
@@ -97,3 +104,3 @@ } | ||
// define sqlite db file path | ||
let dbPath = LibPath.join(ARGS_SOURCE_DIR, 'DayOne.sqlite'); | ||
let dbPath = (ARGS_DB_DIR === undefined) ? LibPath.join(ARGS_SOURCE_DIR, 'DayOne.sqlite') : ARGS_DB_DIR; | ||
console.log(`DB file path: ${dbPath}`); | ||
@@ -144,3 +151,3 @@ // connect db | ||
return new Promise((resolve, reject) => { | ||
db.all(`SELECT Z_PK, ZMD5, ZTYPE FROM ZPHOTO WHERE ZENTRY=${entryId};`, [], (err, rows) => { | ||
db.all(`SELECT Z_PK, ZMD5, ZTYPE FROM ZATTACHMENT WHERE ZENTRY=${entryId};`, [], (err, rows) => { | ||
if (err) { | ||
@@ -147,0 +154,0 @@ return reject(err); |
{ | ||
"name": "dayone_photos_dumper", | ||
"version": "0.0.2", | ||
"version": "0.0.3", | ||
"description": "", | ||
@@ -5,0 +5,0 @@ "main": "build/index.js", |
236
src/index.ts
@@ -25,7 +25,8 @@ #!/usr/bin/env node | ||
program.version(pkg.version) | ||
.description('Dayone2 photo dumper, supports only MacOS & Dayone2') | ||
.option('-e, --entry <string>', `entry id, like: E002D19B76E74474B6FCC2C74E3E05B2 OR entry url, like: dayone2://view?entryId=E002D19B76E74474B6FCC2C74E3E05B2`) | ||
.option('-o, --output_dir <dir>', 'output dir') | ||
.option('-s, --source_dir <dir>', `source dir, default is Dayone2 document path: ${DAYONE_DOCUMENTS}, could switch to your backup dir`) | ||
.parse(process.argv); | ||
.description('Dayone2 photo dumper, supports only MacOS & Dayone2') | ||
.option('-e, --entry <string>', `entry id, like: E002D19B76E74474B6FCC2C74E3E05B2 OR entry url, like: dayone2://view?entryId=E002D19B76E74474B6FCC2C74E3E05B2`) | ||
.option('-o, --output_dir <dir>', 'output dir') | ||
.option('-s, --source_dir <dir>', `source dir, default is Dayone2 document path: ${DAYONE_DOCUMENTS}, could switch to your backup dir`) | ||
.option('-d, --database_path <dir>', 'database file path, dayone2 default path would be used if undefined') | ||
.parse(process.argv); | ||
@@ -35,10 +36,12 @@ const ARGS_ENTRY_INFO = (program as any).entry === undefined ? undefined : (program as any).entry; | ||
const ARGS_SOURCE_DIR = (program as any).source_dir === undefined ? DAYONE_DOCUMENTS : (program as any).source_dir; | ||
const ARGS_DB_DIR = (program as any).database_path === undefined ? undefined : (program as any).database_path; | ||
interface EntryRow { | ||
Z_PK: number; | ||
Z_PK: number; | ||
} | ||
interface PhotoRow { | ||
Z_PK: number; | ||
ZMD5: string; | ||
ZTYPE: string; | ||
Z_PK: number; | ||
ZMD5: string; | ||
ZTYPE: string; | ||
} | ||
@@ -48,131 +51,136 @@ | ||
public async run() { | ||
console.log('Dump start ...'); | ||
public async run() { | ||
console.log('Dump start ...'); | ||
await this._validate(); | ||
await this._process(); | ||
} | ||
await this._validate(); | ||
await this._process(); | ||
} | ||
private async _validate() { | ||
console.log('Dump validating ...'); | ||
private async _validate() { | ||
console.log('Dump validating ...'); | ||
// os | ||
if (LibOs.platform() !== 'darwin') { | ||
console.log('Only MacOS supported!'); | ||
process.exit(1); | ||
} | ||
// os | ||
if (LibOs.platform() !== 'darwin') { | ||
console.log('Only MacOS supported!'); | ||
process.exit(1); | ||
} | ||
// dayone2 | ||
if (!(await LibFs.stat(DAYONE_DIR)).isDirectory()) { | ||
console.log(`No Dayone2 data found, files shall be: ${DAYONE_DIR}`); | ||
process.exit(1); | ||
} | ||
// dayone2 | ||
if (!(await LibFs.stat(DAYONE_DIR)).isDirectory()) { | ||
console.log(`No Dayone2 data found, files shall be: ${DAYONE_DIR}`); | ||
process.exit(1); | ||
} | ||
// -e, entry | ||
if (ARGS_ENTRY_INFO === undefined) { | ||
console.log('Entry information required, please provide -e option'); | ||
process.exit(1); | ||
} | ||
// -e, entry | ||
if (ARGS_ENTRY_INFO === undefined) { | ||
console.log('Entry information required, please provide -e option'); | ||
process.exit(1); | ||
} | ||
// -o, output_dir | ||
if (ARGS_OUTPUT_DIR === undefined) { | ||
console.log('Output directory required, please provide -o option'); | ||
process.exit(1); | ||
} | ||
let destStat: Stats = LibFs.statSync(ARGS_OUTPUT_DIR); | ||
if (!destStat.isDirectory()) { | ||
console.log('Valid output directory required, please check -o option'); | ||
process.exit(1); | ||
} | ||
// -o, output_dir | ||
if (ARGS_OUTPUT_DIR === undefined) { | ||
console.log('Output directory required, please provide -o option'); | ||
process.exit(1); | ||
} | ||
let destStat: Stats = LibFs.statSync(ARGS_OUTPUT_DIR); | ||
if (!destStat.isDirectory()) { | ||
console.log('Valid output directory required, please check -o option'); | ||
process.exit(1); | ||
} | ||
// -s, source_dir | ||
if (ARGS_SOURCE_DIR !== DAYONE_DOCUMENTS && !(await LibFs.exists(LibPath.join(DAYONE_DOCUMENTS, 'DayOne.sqlite')))) { | ||
console.log('Valid source directory required, please check -s option'); | ||
process.exit(1); | ||
} | ||
// -s, source_dir | ||
if (ARGS_SOURCE_DIR !== DAYONE_DOCUMENTS && !(await LibFs.exists(LibPath.join(DAYONE_DOCUMENTS, 'DayOne.sqlite')))) { | ||
console.log('Valid source directory required, please check -s option'); | ||
process.exit(1); | ||
} | ||
private async _process() { | ||
console.log('Dump processing ...'); | ||
if (ARGS_DB_DIR !== undefined && !(await LibFs.exists(ARGS_DB_DIR))) { | ||
console.log('Valid database directory required, please check -d option'); | ||
process.exit(1); | ||
} | ||
} | ||
// parse entry uuid | ||
let entryUUID = ARGS_ENTRY_INFO.indexOf(DAYONE_ENTRY_URL_PREFIX) === 0 | ||
? ARGS_ENTRY_INFO.replace(DAYONE_ENTRY_URL_PREFIX, '') | ||
: ARGS_ENTRY_INFO; | ||
console.log(`Entry UUID: ${entryUUID}`); | ||
private async _process() { | ||
console.log('Dump processing ...'); | ||
// ensure base path | ||
let dumpPath = LibPath.join(ARGS_OUTPUT_DIR, DAYONE_DUMP_BASE_DIR, entryUUID); | ||
if (!(await LibFs.exists(dumpPath))) { // target path does not exists | ||
await mkdirp(dumpPath); | ||
} | ||
console.log(`Dump path ensured: ${dumpPath}`); | ||
// parse entry uuid | ||
let entryUUID = ARGS_ENTRY_INFO.indexOf(DAYONE_ENTRY_URL_PREFIX) === 0 | ||
? ARGS_ENTRY_INFO.replace(DAYONE_ENTRY_URL_PREFIX, '') | ||
: ARGS_ENTRY_INFO; | ||
console.log(`Entry UUID: ${entryUUID}`); | ||
// define sqlite db file path | ||
let dbPath = LibPath.join(ARGS_SOURCE_DIR, 'DayOne.sqlite'); | ||
console.log(`DB file path: ${dbPath}`); | ||
// ensure base path | ||
let dumpPath = LibPath.join(ARGS_OUTPUT_DIR, DAYONE_DUMP_BASE_DIR, entryUUID); | ||
if (!(await LibFs.exists(dumpPath))) { // target path does not exists | ||
await mkdirp(dumpPath); | ||
} | ||
console.log(`Dump path ensured: ${dumpPath}`); | ||
// connect db | ||
let db = new sqlite3.Database(dbPath, async (err) => { | ||
if (err) { | ||
console.log(err); | ||
} | ||
console.log('DB connected ...'); | ||
// define sqlite db file path | ||
let dbPath = (ARGS_DB_DIR === undefined) ? LibPath.join(ARGS_SOURCE_DIR, 'DayOne.sqlite') : ARGS_DB_DIR; | ||
console.log(`DB file path: ${dbPath}`); | ||
let entryId: number = await this._selectEntryId(db, entryUUID); | ||
let photos: Array<PhotoRow> = await this._selectPhotos(db, entryId); | ||
db.close(); | ||
// connect db | ||
let db = new sqlite3.Database(dbPath, async (err) => { | ||
if (err) { | ||
console.log(err); | ||
} | ||
console.log('DB connected ...'); | ||
if (photos.length === 0) { | ||
console.log(`No photos in entry: ${entryUUID}, stop ...`); | ||
return; | ||
} | ||
let entryId: number = await this._selectEntryId(db, entryUUID); | ||
let photos: Array<PhotoRow> = await this._selectPhotos(db, entryId); | ||
db.close(); | ||
for (let photo of photos) { | ||
let srcPath = LibPath.join(DAYONE_PHOTOS, `${photo.ZMD5}.${photo.ZTYPE}`); | ||
let destPath = LibPath.join(dumpPath, `${photo.Z_PK}.${photo.ZTYPE}`); | ||
if (photos.length === 0) { | ||
console.log(`No photos in entry: ${entryUUID}, stop ...`); | ||
return; | ||
} | ||
await LibFs.copyFile(srcPath, destPath); | ||
for (let photo of photos) { | ||
let srcPath = LibPath.join(DAYONE_PHOTOS, `${photo.ZMD5}.${photo.ZTYPE}`); | ||
let destPath = LibPath.join(dumpPath, `${photo.Z_PK}.${photo.ZTYPE}`); | ||
console.log(`Copy, from: ${srcPath}, to: ${destPath}`); | ||
} | ||
await LibFs.copyFile(srcPath, destPath); | ||
console.log('Dump done ...'); | ||
}); | ||
} | ||
console.log(`Copy, from: ${srcPath}, to: ${destPath}`); | ||
} | ||
private async _selectEntryId(db: sqlite3.Database, entryUUID: string): Promise<number> { | ||
return new Promise<number>((resolve, reject) => { | ||
db.all(`SELECT Z_PK FROM ZENTRY WHERE ZUUID="${entryUUID}";`, [], (err, rows) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
console.log('Dump done ...'); | ||
}); | ||
} | ||
if (rows.length === 0) { | ||
console.log(`No entry found for UUID: ${entryUUID}`); | ||
process.exit(1); | ||
} | ||
private async _selectEntryId(db: sqlite3.Database, entryUUID: string): Promise<number> { | ||
return new Promise<number>((resolve, reject) => { | ||
db.all(`SELECT Z_PK FROM ZENTRY WHERE ZUUID="${entryUUID}";`, [], (err, rows) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
let entryId = (rows[0] as EntryRow).Z_PK; | ||
console.log(`Entry ID: ${entryId}`); | ||
if (rows.length === 0) { | ||
console.log(`No entry found for UUID: ${entryUUID}`); | ||
process.exit(1); | ||
} | ||
return resolve(entryId); | ||
}); | ||
}); | ||
} | ||
let entryId = (rows[0] as EntryRow).Z_PK; | ||
console.log(`Entry ID: ${entryId}`); | ||
private async _selectPhotos(db: sqlite3.Database, entryId: number): Promise<Array<PhotoRow>> { | ||
return new Promise<Array<PhotoRow>>((resolve, reject) => { | ||
db.all(`SELECT Z_PK, ZMD5, ZTYPE FROM ZPHOTO WHERE ZENTRY=${entryId};`, [], (err, rows) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
return resolve(entryId); | ||
}); | ||
}); | ||
} | ||
console.log(`Count of photos found: ${rows.length}`); | ||
private async _selectPhotos(db: sqlite3.Database, entryId: number): Promise<Array<PhotoRow>> { | ||
return new Promise<Array<PhotoRow>>((resolve, reject) => { | ||
db.all(`SELECT Z_PK, ZMD5, ZTYPE FROM ZATTACHMENT WHERE ZENTRY=${entryId};`, [], (err, rows) => { | ||
if (err) { | ||
return reject(err); | ||
} | ||
return resolve(rows as Array<PhotoRow>); | ||
}); | ||
}); | ||
} | ||
console.log(`Count of photos found: ${rows.length}`); | ||
return resolve(rows as Array<PhotoRow>); | ||
}); | ||
}); | ||
} | ||
} | ||
@@ -183,7 +191,7 @@ | ||
process.on('uncaughtException', (error) => { | ||
console.error(`Process on uncaughtException error = ${error.stack}`); | ||
console.error(`Process on uncaughtException error = ${error.stack}`); | ||
}); | ||
process.on('unhandledRejection', (error) => { | ||
console.error(`Process on unhandledRejection error = ${error.stack}`); | ||
}); | ||
console.error(`Process on unhandledRejection error = ${error.stack}`); | ||
}); |
Sorry, the diff of this file is not supported yet
333
29788
7