/**--------------------- * @name tykayn Rangement * @description Rangement sorts and rename files depending on their exif data * @contact contact@cipherbliss.com --------------------- */ /** --------------------- libs --------------------- */ import fs from 'node-fs' import minimist from 'minimist' import log from 'loglevel'; import path from "node:path"; /** --------------------- custom utilities and configuration --------------------- */ import rangement_instance from './configs.mjs' import { TestFindFormattedDate, TestScreenShotIsFoundAndRenamed, TestTagsAreDetectedInFileName } from './testFunctions.mjs' import finder from './finder.mjs' import exiftool from "node-exiftool"; let mini_arguments log.setLevel(rangement_instance.log_level) log.info(' ') function parseArguments() { mini_arguments = minimist(process.argv.slice(2)) log.debug('arguments', mini_arguments) } 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) } function renameFile(originalFileName, fileMixedNewName) { fs.rename(originalFileName, fileMixedNewName, function (err) { log.info('name changed', fileMixedNewName) if (err) { log.info('rename ERROR: ' + err) } else { // otherRenames.push(originalFileName) otherRenames.push(fileMixedNewName) addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) // rangement_instance.statistics['filesModified']++ } }) } function appendFileName(fileProperties, newText) { fileProperties.freeText = finder.cleanSpaces(fileProperties.freeText + ' ' + newText) return fileProperties } function prependFileName(fileProperties, newText) { fileProperties.freeText = finder.cleanSpaces(newText + ' ' + fileProperties.freeText) return fileProperties } function makeFileNameFromProperties(fileProperties) { let tagPlace = '' log.info('fileProperties.tags',fileProperties.tags) if (fileProperties.tags.length && rangement_instance.keepTags) { tagPlace = ' ' + rangement_instance.tagSectionSeparator + ' '+ fileProperties.tags.join(rangement_instance.tagSeparator) } console.log('fileProperties.dateStampExif', fileProperties.dateStampExif) let newName = '' + fileProperties.dateStampExif + ' ' + (rangement_instance.keepFreeText? fileProperties.freeText : '') + tagPlace + fileProperties.extension; if(rangement_instance.replaceUnderscoreWithSpaces){ newName = newName.replace('_', ' ') } newName = newName.replace(' ', '') return newName } let otherRenames = []; function shouldWeChangeName(structureForFile) { log.info(' ______ shouldWeChangeName ', structureForFile.fileNameOriginal) let newName = makeFileNameFromProperties(structureForFile) log.debug('newName', newName) if (structureForFile.fileNameOriginal !== newName && !otherRenames.includes(newName)) { log.info('\n ancien nom :', structureForFile.fileNameOriginal) log.info(' nouveau nom:', newName) if (!mini_arguments['dry-run']) { renameFile(structureForFile.fullPath, structureForFile.folderPath + newName) } else { log.info('no renaming for real, this is a dry run') } } else { log.info(' rien à changer') } } /** * guess file name on one file which is not a directory * @param fullPath */ function guessFileNameOnOnefile(fullPath) { log.info('go guess file name on file: ', fullPath ) fs.stat(fullPath, (err, stats) => { if (err) { log.error('échec fichier', err) log.error('ce fichier n existe pas: ', fullPath) return; } else { let structureForFile = finder.destructurateFileName(fullPath) // examiner les infos exif de chaque fichier pour proposer un nouveau nom if (!structureForFile.dateStampInFileNameOriginal) { 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.info(' ... chercher la date de création : "'+structureForFile.freeText +'"') let foundDate = finder.findEarliestDateInExifData(data) log.info(' =>>>>>>> foundDate : ', foundDate) if (foundDate) { structureForFile.dateStampExif = foundDate } else { log.info('pas de date trouvée dans le nom') } shouldWeChangeName(structureForFile) } , (error) => { log.warn('/////////// Error in reading exif of file: ' + error.message) return '' }) } } }) } let expandedFileList = [] let cwd = path.dirname(process.cwd()) + '/' + path.basename(process.cwd()); console.log('cwd', cwd) function guessFileNameOnAllFilesFromArguments() { // parcourir les fichiers log.debug('liste des fichiers', mini_arguments._) let fileList = mini_arguments._ // test file exists fileList.forEach(fullPath => { // parcourir les dossiers isFolderOrFile(`${fullPath}`) } ) log.info('expanded file list :', expandedFileList) expandedFileList.forEach(filePath => guessFileNameOnOnefile(filePath)) } function readSubdirectories(baseDir) { const newGlob = baseDir; fs.readdir(baseDir, (err, files) => { if (err) throw err; console.log('readSubdirectories - files', files) files.forEach((subDirOrFile) => { const newFullPath = cwd +'/'+ subDirOrFile; if (fs.existsSync(newFullPath)) { const s = fs.statSync(newFullPath); if (s.isFile()) { expandedFileList.push(cwd+'/'+subDirOrFile) } } }); }); } function isFolderOrFile(fileName) { // const stat = fs.statSync(cwd + '/' + fileName); const stat = fs.statSync( fileName); if (stat.isDirectory()) { let fileList = readSubdirectories(fileName); console.log('fileList in directory ',fileName, '\n', fileList) if (fileList) { expandedFileList.push(...fileList) } } else if (stat.isFile()) { expandedFileList.push(cwd + '/' + fileName) } } parseArguments() guessFileNameOnAllFilesFromArguments() // run tests if (rangement_instance.enableTestsLocally) { TestTagsAreDetectedInFileName() TestFindFormattedDate() TestScreenShotIsFoundAndRenamed() } if (rangement_instance.reportStatistics || mini_arguments.stats) { finder.reportStatistics() }