diff --git a/README.md b/README.md index 1e8f76c..180047f 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ mais ce n'est pas encore prêt à être utilisé en production. # Roadmap * Internationalisation of console texts * Proper testing - +* Template configuration for auto dispatching of files after rename * Handle a configuration file - * create config file if needed * batch rename like the python pip script "guessfilename" diff --git a/configs.mjs b/configs.mjs index 8a7b3c0..aa93229 100644 --- a/configs.mjs +++ b/configs.mjs @@ -1,46 +1,48 @@ - -class config_rangement{ - log_level ='debug' // 'debug' | 'warn' |'info' - version = '1.0.0' - tagSeparator = '1.0.0' - tagSectionSeparator = '1.0.0' - keepFreeText= true - keepTags= true - enableTestsLocally= false - reportStatistics= false - base_archive_folder= '/home/poule/encrypted/stockage-syncable/' - photos_sub_folder= 'photos' - photos_sorting_base_sub_folder= 'photos/a_dispatcher' - bazar_sub_folder= 'BAZAR' - panoramax_captures_folder= 'photos/imagerie kartaview carto tel/open camera' - templates = { - // example FyB8cZnWIAc21rw.jpg - 'downloaded_pic': { - 'pattern' : /^\-\w{15}\.jpg/, - 'auto_sort_folder' : this.bazar_sub_folder - }, - // example -4900281569878475578_1109.jpg - 'telegram_pic': { - 'pattern' : /^\-\d{19}_\d{4}/, - 'auto_sort_folder' : '' - }, - // example IMG_20230617_092120_3.jpg - 'open_camera_default': { - 'pattern' : /^IMG_\d{8}/i, - 'auto_sort_folder' : this.panoramax_captures_folder - }, - // example IMG_OC_20230617_092120_3.jpg - 'open_camera_custom': { - 'pattern' : /^IMG_OC_\d{8}/i, - 'auto_sort_folder' : this.panoramax_captures_folder - }, - // example "Screenshot 2023-06-15 at 15-26-04 Instance Panoramax OSM-FR.png" - 'screenshot': { - 'pattern' : /^Screenshot/i, - 'auto_sort_folder': 'photos/captures écran screenshots' - } , - } +class config_rangement { + log_level = 'info' // 'debug' | 'warn' |'info' + version = '1.0.0' + tagSeparator = '1.0.0' + tagSectionSeparator = '1.0.0' + keepFreeText = true + keepTags = true + replaceUnderscoreWithSpaces = true + renameFolders = false + enableTestsLocally = false + reportStatistics = false + base_archive_folder = '/home/poule/encrypted/stockage-syncable/' + photos_sub_folder = this.base_archive_folder + 'photos/' + photos_sorting_base_sub_folder = this.base_archive_folder + 'photos/a_dispatcher/' + bazar_sub_folder = this.base_archive_folder + 'BAZAR/' + panoramax_captures_folder = 'photos/imagerie kartaview carto tel/open camera/' + templates = { + // example FyB8cZnWIAc21rw.jpg + 'downloaded_pic': { + 'pattern': /^\-\w{15}\.jpg/, + 'auto_sort_folder': this.bazar_sub_folder + }, + // example -4900281569878475578_1109.jpg + 'telegram_pic': { + 'pattern': /^\-\d{19}_\d{4}/, + 'auto_sort_folder': this.bazar_sub_folder + }, + // example IMG_20230617_092120_3.jpg + 'open_camera_default': { + 'pattern': /^IMG_\d{8}/i, + 'auto_sort_folder': this.panoramax_captures_folder + }, + // example IMG_OC_20230617_092120_3.jpg + 'open_camera_custom': { + 'pattern': /^IMG_OC_\d{8}/i, + 'auto_sort_folder': this.panoramax_captures_folder + }, + // example "Screenshot 2023-06-15 at 15-26-04 Instance Panoramax OSM-FR.png" + 'screenshot': { + 'pattern': /^Screenshot/i, + 'auto_sort_folder': 'photos/captures écran screenshots' + }, + } } + const rangement_instance = new config_rangement(); export const tagSeparator = rangement_instance.tagSeparator diff --git a/finder.mjs b/finder.mjs index 350b9f5..1a41ecc 100644 --- a/finder.mjs +++ b/finder.mjs @@ -28,7 +28,7 @@ export default class finder { static findFormattedDate (filepath) { let match = filepath.match(/\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/ig) - // log.debug('match findFormattedDate', match) + log.debug(' finder - match findFormattedDate', match) let result = '' if (match && match[0]) { result = match[0] @@ -51,7 +51,7 @@ export default class finder { let boom = fileName.split(tagSectionSeparator) if (boom.length) { let freeTextPart = boom[0].trim() - log.debug('freeTextPart', freeTextPart) + log.debug(' finder - freeTextPart', freeTextPart) return freeTextPart } return fileName.trim() @@ -70,24 +70,24 @@ export default class finder { if (extensionFile) { extensionFile = extensionFile[0] } else { - log.debug('no extensionFile', extensionFile, inputString) + log.debug(' finder - no extensionFile', extensionFile, inputString) extensionFile = '' } inputString = inputString.replace(extensionFile, '') - // log.debug('extensionFile', extensionFile) + log.debug(' finder - extensionFile', extensionFile) if (inputString.includes(tagSectionSeparator)) { - // log.debug('inputString', inputString) + log.debug(' finder - inputString', inputString) if (inputString.length) { let boom = inputString.split(tagSectionSeparator) - // log.debug('boom', boom) + // log.debug(' finder - boom', boom) if (boom.length) { let fileSectionsName = boom.splice(tagSeparator) listOfTags = [...fileSectionsName[1].trim().split(tagSeparator)] - // log.debug('listOfTags', listOfTags) + log.debug(' finder - listOfTags', listOfTags) } else { - log.debug('no boom', boom) + log.debug(' finder - no boom', boom) } } } @@ -108,15 +108,15 @@ export default class finder { static searchAndRenameScreenshots (fileName) { if (finder.findScreenshot(fileName)) { let tags = this.findTagSectionInString(fileName) - log.debug('tags', tags) + log.debug(' finder - tags', tags) if (!tags.includes('screenshot')) { fileName = this.addTagInFileName('screenshot', fileName) fileName = this.searchAndReplaceInFileName('Screenshot', '', fileName) - log.debug('screenShotMockFileName:', fileName) + log.debug(' finder - screenShotMockFileName:', fileName) return this.cleanSpaces(fileName) } - log.debug('is a screenshot, remove screenshot in name, and add tag screenshot') + log.debug(' finder - is a screenshot, remove screenshot in name, and add tag screenshot') } else { return null } @@ -166,17 +166,17 @@ export default class finder { let moments = [] - // log.debug('exif data : ', exifData) // Do something with your data! + log.debug(' finder - exif data : ', exifData) // Do something with your data! if (exifData.DateTimeOriginal) { - // log.debug('image créée le : DateTimeOriginal : ', exifData.DateTimeOriginal) // Do something with your data! + log.debug(' finder - image créée le : DateTimeOriginal : ', exifData.DateTimeOriginal) // Do something with your data! moments.push(exifData.DateTimeOriginal) } if (exifData.ModificationDateTime) { - // log.debug('image créée le : ModificationDateTime : ', exifData.ModificationDateTime) // Do something with your data! + log.debug(' finder - image créée le : ModificationDateTime : ', exifData.ModificationDateTime) // Do something with your data! moments.push(exifData.ModificationDateTime) } if (exifData.ModifyDate) { - // log.debug('image créée le : ModifyDate : ', exifData.ModifyDate) // Do something with your data! + log.debug(' finder - image créée le : ModifyDate : ', exifData.ModifyDate) // Do something with your data! moments.push(exifData.ModifyDate) } if (exifData.FileAccessDateTime) { @@ -186,11 +186,11 @@ export default class finder { moments.push(exifData.FileInodeChangeDateTime) } if (exifData.FileModificationDateTime) { - // log.debug('image créée le : FileModificationDateTime : ', exifData.FileModificationDateTime) // Do something with your data! + log.debug(' finder - image créée le : FileModificationDateTime : ', exifData.FileModificationDateTime) // Do something with your data! moments.push(exifData.FileModificationDateTime) } if (exifData.CreateDate) { - // log.debug('image créée le : CreateDate : ', exifData.CreateDate) // Do something with your data! + log.debug(' finder - image créée le : CreateDate : ', exifData.CreateDate) // Do something with your data! moments.push(exifData.CreateDate) } @@ -200,27 +200,31 @@ export default class finder { }) let minDate = moment.min(moments) - // log.debug('minDate :::::::::', minDate) - log.debug('minDate :::::::::', minDate.format('yyyy-MM-DDTHH:mm:ss')) + log.debug(' finder - minDate :::::::::', minDate) + log.debug(' finder - minDate :::::::::', minDate.format('yyyy-MM-DDTHH:mm:ss')) return minDate.format('yyyy-MM-DDTHH:mm:ss') } else { - log.debug('pas de exif data') + log.debug(' finder - pas de exif data') return '' } } + static findTemplateInFileName(fileName){ + // test all templates from configuration + } + /** * examine plusieurs propriétés exif de date et retourne la plus ancienne * @param filepath */ static async findExifCreationDate (filepath) { - log.debug('filepath', filepath) + log.debug(' finder - filepath', filepath) let dateAlreadyInFileName = finder.findFormattedDate(filepath) if (dateAlreadyInFileName) { - log.debug('------ dateAlreadyInFileName', dateAlreadyInFileName) + log.debug(' finder - ------ dateAlreadyInFileName', dateAlreadyInFileName) } return await exifr.parse(filepath) @@ -232,8 +236,8 @@ export default class finder { let fileName = folders.pop() folders = filePath.replace(fileName, '') - log.debug('\n - folders', folders) - log.debug(' - fileName', fileName, '\n') + log.debug(' finder - \n - folders', folders) + log.debug(' finder - - fileName', fileName, '\n') return [folders, fileName] } diff --git a/index.mjs b/index.mjs index 6c0f07b..a149219 100644 --- a/index.mjs +++ b/index.mjs @@ -35,16 +35,16 @@ function parseArguments() { function addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) { - const ep = new exiftool.ExiftoolProcess() - - ep - .open(fileMixedNewName) - .then(() => ep.writeMetadata(fileMixedNewName, { - 'OriginalFileName+': originalFileName, - })) - .then(console.log, console.error) - .then(() => ep.close()) - .catch(console.error) + // const ep = new exiftool.ExiftoolProcess() + // + // ep + // .open(fileMixedNewName) + // .then(() => ep.writeMetadata(fileMixedNewName, { + // 'OriginalFileName+': originalFileName, + // })) + // .then(console.log, console.error) + // .then(() => ep.close()) + // .catch(console.error) } function renameFile(originalFileName, fileMixedNewName) { @@ -54,7 +54,7 @@ function renameFile(originalFileName, fileMixedNewName) { log.info('rename ERROR: ' + err) } else { addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) - rangement_instance.statistics['filesModified']++ + // rangement_instance.statistics['filesModified']++ } }) } @@ -72,16 +72,29 @@ function prependFileName(fileProperties, newText) { function makeFileNameFromProperties(fileProperties) { let tagPlace = '' - if (fileProperties.tags.length) { - tagPlace = ' ' + rangement_instance.tagSectionSeparator + ' ' + if (fileProperties.tags.length && rangement_instance.keepTags) { + tagPlace = ' ' + rangement_instance.tagSectionSeparator + ' '+ fileProperties.tags.join(rangement_instance.tagSeparator) } - return '' + fileProperties.dateStampExif + ' ' + fileProperties.freeText + tagPlace + fileProperties.tags.join(tagSeparator) + fileProperties.extension + let newName = '' + + fileProperties.dateStampExif + + ' ' + + (rangement_instance.keepFreeText? fileProperties.freeText : '') + + tagPlace + + fileProperties.extension; + + if(rangement_instance.replaceUnderscoreWithSpaces){ + newName = newName.replace('_', ' ') + } + + newName = newName.replace(' ', '') + + return newName } function shouldWeChangeName(structureForFile) { - log.info(' ______ allez hop fini la recherche on fait un nouveau nom') - log.info('structureForFile', structureForFile) + log.info(' ______ shouldWeChangeName ', structureForFile.fileNameOriginal) let newName = makeFileNameFromProperties(structureForFile) + log.debug('newName', newName) if (structureForFile.fileNameOriginal !== newName) { log.info('\n ancien nom :', structureForFile.fileNameOriginal) @@ -95,7 +108,6 @@ function shouldWeChangeName(structureForFile) { } else { log.info(' rien à changer') } - } /** @@ -104,6 +116,7 @@ function shouldWeChangeName(structureForFile) { */ function guessFileNameOnOnefile(fullPath) { + log.info('go guess file name on file: ', fullPath ) fs.stat(fullPath, (err, stats) => { if (err) { @@ -116,22 +129,20 @@ function guessFileNameOnOnefile(fullPath) { // examiner les infos exif de chaque fichier pour proposer un nouveau nom if (!structureForFile.dateStampInFileNameOriginal) { - log.debug(' le nom de fichier ne contient pas de date formatée au début') + log.info(' le nom de fichier "'+structureForFile.freeText +'" ne contient pas de date formatée au début') finder.findExifCreationDate(structureForFile.fullPath) .then(data => { - log.debug(' ... chercher la date de création') + log.info(' ... chercher la date de création : "'+structureForFile.freeText +'"') let foundDate = finder.findEarliestDateInExifData(data) log.info(' =>>>>>>> foundDate : ', foundDate) if (foundDate) { structureForFile.dateStampExif = foundDate - shouldWeChangeName(structureForFile) - } else { log.info('pas de date trouvée dans le nom') } - + shouldWeChangeName(structureForFile) } , (error) => { @@ -170,29 +181,27 @@ function guessFileNameOnAllFilesFromArguments() { function readSubdirectories(baseDir) { const newGlob = baseDir; - let fileList = []; fs.readdir(baseDir, (err, files) => { if (err) throw err; - console.log('files', files) + console.log('readSubdirectories - files', files) files.forEach((subDirOrFile) => { - const newFullPath = path.resolve(baseDir, subDirOrFile); + const newFullPath = cwd +'/'+ subDirOrFile; if (fs.existsSync(newFullPath)) { const s = fs.statSync(newFullPath); if (s.isFile()) { - fileList.push(cwd+'/'+subDirOrFile) + expandedFileList.push(cwd+'/'+subDirOrFile) } } }); - return fileList }); - return fileList } function isFolderOrFile(fileName) { - const stat = fs.statSync(cwd + '/' + fileName); + // const stat = fs.statSync(cwd + '/' + fileName); + const stat = fs.statSync( fileName); if (stat.isDirectory()) { let fileList = readSubdirectories(fileName); diff --git a/testFiles/2020-06-21T14:27:19 2020-0 image.jpg b/testFiles/2020-06-21T14:27:19 image.jpg similarity index 100% rename from testFiles/2020-06-21T14:27:19 2020-0 image.jpg rename to testFiles/2020-06-21T14:27:19 image.jpg diff --git a/testFiles/meme/2023-06-14T13.29.22 FyB8cZnWIAc21rw -- meme.jpg b/testFiles/meme/ FyB8cZnWIAc21rw -- meme.jpg similarity index 100% rename from testFiles/meme/2023-06-14T13.29.22 FyB8cZnWIAc21rw -- meme.jpg rename to testFiles/meme/ FyB8cZnWIAc21rw -- meme.jpg diff --git a/testFiles/meme/2023-06-26T18.53.59 FzjSx2YWcAEqsde -- meme.jpg b/testFiles/meme/ FzjSx2YWcAEqsde -- meme.jpg similarity index 100% rename from testFiles/meme/2023-06-26T18.53.59 FzjSx2YWcAEqsde -- meme.jpg rename to testFiles/meme/ FzjSx2YWcAEqsde -- meme.jpg