camera-media-extractor
Advanced tools
Comparing version 1.1.0 to 1.2.0
@@ -16,3 +16,3 @@ "use strict"; | ||
const file_reconciliation_1 = require("./file-reconciliation"); | ||
async function copyFiles(src, dest, dryRun) { | ||
async function copyFiles(src, dest, dryRun, fileDatePattern) { | ||
const spinner = ora_1.default({ | ||
@@ -65,3 +65,17 @@ text: 'Finding your files', | ||
console.log(`Exif files found: ${exifFiles}, non exif files: ${nonExifFiles}`); | ||
const filesWithCreated = utils_1.replaceDateOnFiles(filesWithStats, exifFileDates); | ||
let filesWithCreated = utils_1.replaceDateOnFiles(filesWithStats, exifFileDates, true); | ||
if (fileDatePattern !== '') { | ||
const dateFormat = utils_1.parseDateFormatString(fileDatePattern); | ||
const filesWithDatesFromPattern = filesWithCreated | ||
.filter((file) => !file.isExif) | ||
.map((file) => { | ||
const name = path_1.basename(file.fileName); | ||
const fileDate = utils_1.parseDateFromString(dateFormat, name); | ||
return { | ||
fileName: file.fileName, | ||
created: fileDate, | ||
}; | ||
}); | ||
filesWithCreated = utils_1.replaceDateOnFiles(filesWithStats, filesWithDatesFromPattern, false); | ||
} | ||
const filesWithDest = utils_1.addDestinationDir(path_1.resolve(dest), filesWithCreated); | ||
@@ -68,0 +82,0 @@ const filteredFilesWithDest = await file_reconciliation_1.filterExistingFiles(filesWithDest); |
@@ -14,2 +14,3 @@ "use strict"; | ||
birthtime: mockFileCreationDate, | ||
isExif: false, | ||
}, | ||
@@ -20,2 +21,3 @@ { | ||
birthtime: mockFileCreationDate, | ||
isExif: false, | ||
}, | ||
@@ -26,2 +28,3 @@ { | ||
birthtime: mockFileCreationDate, | ||
isExif: false, | ||
}, | ||
@@ -32,2 +35,3 @@ { | ||
birthtime: mockFileCreationDate, | ||
isExif: false, | ||
}, | ||
@@ -34,0 +38,0 @@ ]; |
@@ -41,2 +41,3 @@ "use strict"; | ||
fileName: path_1.resolve(__dirname, './test/file_2.txt'), | ||
isExif: false, | ||
size: 1024, | ||
@@ -43,0 +44,0 @@ }; |
@@ -140,2 +140,3 @@ "use strict"; | ||
birthtime: expect.any(Date), | ||
isExif: false, | ||
}; | ||
@@ -142,0 +143,0 @@ const stats = await _1.getFileStats(file); |
@@ -77,2 +77,3 @@ "use strict"; | ||
birthtime: new Date(stats.birthtime), | ||
isExif: false, | ||
}); | ||
@@ -79,0 +80,0 @@ } |
@@ -19,2 +19,4 @@ #!/usr/bin/env node | ||
.describe('n', 'dry run, shows files that would be copied') | ||
.string('file-date-pattern') | ||
.describe('file-date-pattern', 'parse date from file pattern if exif fails') | ||
.example('', 'camera-media-exctractor /mnt/f/photos /username/pictures/') | ||
@@ -24,2 +26,2 @@ .showHelpOnFail(true) | ||
.argv; | ||
copy_files_1.copyFiles(argv._[0], argv._[1], argv['dry-run'] || false); | ||
copy_files_1.copyFiles(argv._[0], argv._[1], argv['dry-run'] || false, argv['file-date-pattern'] || ''); |
@@ -7,3 +7,3 @@ "use strict"; | ||
*/ | ||
function replaceDateOnFiles(annotatedFiles, filesWithCreated) { | ||
function replaceDateOnFiles(annotatedFiles, filesWithCreated, isExif) { | ||
return annotatedFiles.map((annotatedFile) => { | ||
@@ -17,2 +17,3 @@ const newDateFile = filesWithCreated.find((fileWithDate) => { | ||
birthtime: newDateFile.created, | ||
isExif, | ||
}; | ||
@@ -41,1 +42,58 @@ } | ||
} | ||
function parseDateFormatString(format) { | ||
const parts = [ | ||
'yyyy', | ||
'mm', | ||
'dd', | ||
]; | ||
const partOrder = []; | ||
let regexFormat = format; | ||
parts.forEach((part, i) => { | ||
const partIdx = format.indexOf(part); | ||
if (partIdx === -1) { | ||
throw new Error(`not found expected date format part "${part}"`); | ||
} | ||
partOrder.push([partIdx, i]); | ||
regexFormat = regexFormat.replace(part, `(\\d{${part.length}})`); | ||
}); | ||
partOrder.sort((a, b) => a[0] - b[0]); | ||
return { | ||
regex: new RegExp(regexFormat), | ||
order: [ | ||
partOrder[0][1], | ||
partOrder[1][1], | ||
partOrder[2][1], | ||
], | ||
}; | ||
} | ||
exports.parseDateFormatString = parseDateFormatString; | ||
function parseDateFromString(format, input) { | ||
const match = input.match(format.regex); | ||
if (match === null) { | ||
throw new Error(`unable to parse date from ${input}`); | ||
} | ||
else { | ||
const [year, month, day] = [1, 2, 3].map((regexIdx, i) => { | ||
const orderIdx = format.order[i]; | ||
const value = match[regexIdx]; | ||
if (!value) { | ||
throw new Error(`unable to parse date from ${input}`); | ||
} | ||
let intVal; | ||
try { | ||
intVal = parseInt(value, 10); | ||
} | ||
catch (e) { | ||
throw new Error(`unable to parse date from ${input}`); | ||
} | ||
if (orderIdx === 1) { | ||
intVal -= 1; | ||
} | ||
return [orderIdx, intVal]; | ||
}) | ||
.sort((a, b) => a[0] - b[0]) | ||
.map((v) => v[1]); | ||
return new Date(year, month, day); | ||
} | ||
} | ||
exports.parseDateFromString = parseDateFromString; |
@@ -7,6 +7,6 @@ "use strict"; | ||
const files = [ | ||
{ size: 4, fileName: './some-file.txt', birthtime: new Date('2015-05-05T18:00') }, | ||
{ size: 5, fileName: './some-file2.txt', birthtime: new Date('2015-05-05T20:00') }, | ||
{ size: 7, fileName: './some-file8.txt', birthtime: new Date('2015-05-05T22:00') }, | ||
{ size: 80, fileName: './some-file5.txt', birthtime: new Date('2015-05-06T23:00') }, | ||
{ size: 4, fileName: './some-file.txt', birthtime: new Date('2015-05-05T18:00'), isExif: false }, | ||
{ size: 5, fileName: './some-file2.txt', birthtime: new Date('2015-05-05T20:00'), isExif: false }, | ||
{ size: 7, fileName: './some-file8.txt', birthtime: new Date('2015-05-05T22:00'), isExif: false }, | ||
{ size: 80, fileName: './some-file5.txt', birthtime: new Date('2015-05-06T23:00'), isExif: false }, | ||
]; | ||
@@ -24,4 +24,26 @@ const newDate = new Date('2018-06-21T06:30'); | ||
expectedFiles[3].birthtime = newDate2; | ||
expect(_1.replaceDateOnFiles(files, newDateFiles)).toEqual(expectedFiles); | ||
expect(_1.replaceDateOnFiles(files, newDateFiles, false)).toEqual(expectedFiles); | ||
}); | ||
it('returns a new array of files with updated dates and mark as exif', () => { | ||
const files = [ | ||
{ size: 4, fileName: './some-file.txt', birthtime: new Date('2015-05-05T18:00'), isExif: false }, | ||
{ size: 5, fileName: './some-file2.txt', birthtime: new Date('2015-05-05T20:00'), isExif: false }, | ||
{ size: 7, fileName: './some-file8.txt', birthtime: new Date('2015-05-05T22:00'), isExif: false }, | ||
{ size: 80, fileName: './some-file5.txt', birthtime: new Date('2015-05-06T23:00'), isExif: false }, | ||
]; | ||
const newDate = new Date('2018-06-21T06:30'); | ||
const newDate2 = new Date('2017-09-21T04:30'); | ||
const newDateFiles = [ | ||
{ fileName: './some-file2.txt', created: newDate }, | ||
{ fileName: './some-file5.txt', created: newDate2 }, | ||
]; | ||
const expectedFiles = [ | ||
...files, | ||
]; | ||
expectedFiles[1].birthtime = newDate; | ||
expectedFiles[1].isExif = true; | ||
expectedFiles[3].birthtime = newDate2; | ||
expectedFiles[3].isExif = true; | ||
expect(_1.replaceDateOnFiles(files, newDateFiles, true)).toEqual(expectedFiles); | ||
}); | ||
}); | ||
@@ -31,7 +53,7 @@ describe('addDestinationDir()', () => { | ||
const files = [ | ||
{ size: 5, fileName: './file1.txt', birthtime: new Date('2019-04-03T15:25') }, | ||
{ size: 5, fileName: './file2.txt', birthtime: new Date('2019-04-03T15:28') }, | ||
{ size: 5, fileName: './file3.txt', birthtime: new Date('2019-04-03T15:40') }, | ||
{ size: 5, fileName: './file4.txt', birthtime: new Date('2019-04-18T15:40') }, | ||
{ size: 5, fileName: './file5.txt', birthtime: new Date('2018-12-21T11:59') }, | ||
{ size: 5, fileName: './file1.txt', birthtime: new Date('2019-04-03T15:25'), isExif: false }, | ||
{ size: 5, fileName: './file2.txt', birthtime: new Date('2019-04-03T15:28'), isExif: false }, | ||
{ size: 5, fileName: './file3.txt', birthtime: new Date('2019-04-03T15:40'), isExif: false }, | ||
{ size: 5, fileName: './file4.txt', birthtime: new Date('2019-04-18T15:40'), isExif: false }, | ||
{ size: 5, fileName: './file5.txt', birthtime: new Date('2018-12-21T11:59'), isExif: false }, | ||
]; | ||
@@ -41,7 +63,7 @@ const dest = './dest-dir'; | ||
// tslint:disable max-line-length | ||
{ size: 5, fileName: './file1.txt', birthtime: new Date('2019-04-03T15:25'), dest: `${dest}/2019-04-03/file1.txt` }, | ||
{ size: 5, fileName: './file2.txt', birthtime: new Date('2019-04-03T15:28'), dest: `${dest}/2019-04-03/file2.txt` }, | ||
{ size: 5, fileName: './file3.txt', birthtime: new Date('2019-04-03T15:40'), dest: `${dest}/2019-04-03/file3.txt` }, | ||
{ size: 5, fileName: './file4.txt', birthtime: new Date('2019-04-18T15:40'), dest: `${dest}/2019-04-18/file4.txt` }, | ||
{ size: 5, fileName: './file5.txt', birthtime: new Date('2018-12-21T11:59'), dest: `${dest}/2018-12-21/file5.txt` }, | ||
{ size: 5, fileName: './file1.txt', birthtime: new Date('2019-04-03T15:25'), dest: `${dest}/2019-04-03/file1.txt`, isExif: false }, | ||
{ size: 5, fileName: './file2.txt', birthtime: new Date('2019-04-03T15:28'), dest: `${dest}/2019-04-03/file2.txt`, isExif: false }, | ||
{ size: 5, fileName: './file3.txt', birthtime: new Date('2019-04-03T15:40'), dest: `${dest}/2019-04-03/file3.txt`, isExif: false }, | ||
{ size: 5, fileName: './file4.txt', birthtime: new Date('2019-04-18T15:40'), dest: `${dest}/2019-04-18/file4.txt`, isExif: false }, | ||
{ size: 5, fileName: './file5.txt', birthtime: new Date('2018-12-21T11:59'), dest: `${dest}/2018-12-21/file5.txt`, isExif: false }, | ||
]; | ||
@@ -51,1 +73,34 @@ expect(_1.addDestinationDir(dest, files)).toEqual(expectedResult); | ||
}); | ||
describe('parseDateFormatString()', () => { | ||
const testSuite = [ | ||
{ input: 'yyyymmdd', expected: { regex: /(\d{4})(\d{2})(\d{2})/, order: [0, 1, 2] } }, | ||
{ input: 'yyyyddmm', expected: { regex: /(\d{4})(\d{2})(\d{2})/, order: [0, 2, 1] } }, | ||
{ input: 'ddmmyyyy', expected: { regex: /(\d{2})(\d{2})(\d{4})/, order: [2, 1, 0] } }, | ||
{ input: '^ddmmyyyy.*', expected: { regex: /^(\d{2})(\d{2})(\d{4}).*/, order: [2, 1, 0] } }, | ||
{ input: '.*yyyy_mm_dd.*', expected: { regex: /.*(\d{4})_(\d{2})_(\d{2}).*/, order: [0, 1, 2] } }, | ||
]; | ||
for (const test of testSuite) { | ||
expect(_1.parseDateFormatString(test.input)).toEqual(test.expected); | ||
} | ||
}); | ||
describe('parseDateFromString()', () => { | ||
it('parses dates from the expected input + formats', () => { | ||
const testSuite = [ | ||
{ format: { regex: /(\d{4})(\d{2})(\d{2})/, order: [0, 1, 2] }, | ||
input: '20110324', expected: new Date(2011, 2, 24), | ||
}, | ||
{ format: { regex: /(\d{4})(\d{2})(\d{2})/, order: [0, 2, 1] }, | ||
input: '20112403', expected: new Date(2011, 2, 24), | ||
}, | ||
{ format: { regex: /.*(\d{4})(\d{2})(\d{2}).*/, order: [0, 1, 2] }, | ||
input: 'abc20110324_other.txt', expected: new Date(2011, 2, 24), | ||
}, | ||
{ format: { regex: /.*(\d{4})_(\d{2})_(\d{2}).*/, order: [0, 1, 2] }, | ||
input: 'abc2011_03_24_other.file', expected: new Date(2011, 2, 24), | ||
}, | ||
]; | ||
for (const test of testSuite) { | ||
expect(_1.parseDateFromString(test.format, test.input)).toEqual(test.expected); | ||
} | ||
}); | ||
}); |
{ | ||
"name": "camera-media-extractor", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"description": "A media extractor from removable media", | ||
@@ -5,0 +5,0 @@ "bin": { |
36159
21
892
6