diff --git a/index.ts b/index.ts index 447b697..87075aa 100644 --- a/index.ts +++ b/index.ts @@ -17,17 +17,14 @@ import rangement_instance from './conf/configs' import finder from './utils/finder' let mini_arguments +let expandedFileList = [] log.setLevel(rangement_instance.log_level) log.info(' ') -function parseArguments () { - mini_arguments = minimist(process.argv.slice(2)) - log.debug('arguments', mini_arguments) -} -parseArguments() +finder.parseArguments() console.log('hello ts', finder) \ No newline at end of file diff --git a/old_index.mjs b/old_index.mjs index 5ccaf3e..c6bec89 100644 --- a/old_index.mjs +++ b/old_index.mjs @@ -21,197 +21,9 @@ 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) -} -/** - * if there is no original file name free text into the new name, append it to the free text part - * @param originalFileName - * @param fileMixedNewName - */ -function addOriginalFileNameIfMissing (originalFileName, fileMixedNewName) { - if (!fileMixedNewName.includes(originalFileName)) { - let properties = finder.destructurateFileName(fileMixedNewName) - return properties.freeText + ' ' + originalFileName - } else { - return fileMixedNewName - } -} -function renameFile (originalFileName, fileMixedNewName) { - if (rangement_instance.keepOriginalNameInRename) { - fileMixedNewName = addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) - } +finder.parseArguments() - 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) - - finder.statistics['filesModified']++ - } - }) -} - -export 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) - } - log.debug('fileProperties.dateStampExif', fileProperties.dateStampExif) - let newName = '' - + fileProperties.dateStampExif - + ' ' - + (rangement_instance.keepFreeText ? fileProperties.freeText : '') - + tagPlace - + fileProperties.extension - - if (rangement_instance.replaceUnderscoreWithSpaces) { - newName = newName.replace('_', ' ') - } - - newName = finder.cleanSpaces(newName) - - 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') - finder.statistics['filesNotModified']++ - } - } 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()) -log.debug('cwd', cwd) - -function guessFileNameOnAllFilesFromArguments () { - - // parcourir les fichiers - log.debug('liste des fichiers', mini_arguments._) - let fileList = mini_arguments._ - - // test file exists - fileList.forEach(fullPath => { - log.debug('file list element: ', fullPath) - // parcourir les dossiers - isFolderOrFile(`${fullPath}`) - } - ) - - log.info('expanded file list :', expandedFileList) - expandedFileList.forEach(filePath => guessFileNameOnOnefile(filePath)) - - if (rangement_instance.reportStatistics || mini_arguments.stats) { - finder.reportStatistics() - } - -} - -function readSubdirectories (baseDir) { - const newGlob = baseDir - fs.readdir(baseDir, (err, files) => { - if (err) throw err - - log.debug('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(fileName) - - if (stat.isDirectory()) { - let fileList = readSubdirectories(fileName) - log.debug('fileList in directory ', fileName, '\n', fileList) - if (fileList) { - expandedFileList.push(...fileList) - } - } else if (stat.isFile()) { - expandedFileList.push(fileName) - } -} - -parseArguments() - -guessFileNameOnAllFilesFromArguments() +finder.guessFileNameOnAllFilesFromArguments() diff --git a/package-lock.json b/package-lock.json index f1c2cfc..1105536 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "@babel/preset-env": "^7.22.5", "@babel/preset-typescript": "^7.22.5", "@jest/globals": "^29.5.0", + "@types/minimist": "^1.2.2", "@types/node": "^20.4.2", "babel-jest": "^29.5.0", "jest": "^29.5.0", @@ -2367,6 +2368,12 @@ "@types/istanbul-lib-report": "*" } }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, "node_modules/@types/node": { "version": "20.4.2", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.4.2.tgz", diff --git a/package.json b/package.json index 611c1db..27e973f 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "@babel/preset-env": "^7.22.5", "@babel/preset-typescript": "^7.22.5", "@jest/globals": "^29.5.0", + "@types/minimist": "^1.2.2", "@types/node": "^20.4.2", "babel-jest": "^29.5.0", "jest": "^29.5.0", diff --git a/tests/finder.test.js b/tests/finder.test.js index eb3814f..83bab6f 100644 --- a/tests/finder.test.js +++ b/tests/finder.test.js @@ -1,4 +1,4 @@ -import finder from '../utils/finder.js' +import finder from '../utils/finder' import { makeFileNameFromProperties } from '../old_index' import { expect } from '@jest/globals' diff --git a/tests/main.test.js b/tests/main.test.js index 03e5919..12b6fd8 100644 --- a/tests/main.test.js +++ b/tests/main.test.js @@ -1,4 +1,4 @@ -import finder from "../utils/finder.js"; +import finder from "../utils/finder.ts"; import { Jest as mockUpload } from '@jest/environment' xdescribe('rangement file detection', () => { diff --git a/utils/finder.ts b/utils/finder.ts index 42f5eb3..afaf6e5 100644 --- a/utils/finder.ts +++ b/utils/finder.ts @@ -5,6 +5,9 @@ import exifr from 'exifr' import moment from 'moment' import log from 'loglevel' import rangement_instance from '../conf/configs' +import * as fs from "fs"; +import path from "node:path"; +import minimist from 'minimist'; log.setLevel(rangement_instance.log_level) @@ -19,6 +22,8 @@ interface fileDestructuration { extension: string, } +let cwd = path.dirname(process.cwd()) + '/' + path.basename(process.cwd()) + /** * finds patterns for file name */ @@ -28,12 +33,208 @@ export default class finder { filesModified: 0, filesNotModified: 0, } + private static otherRenames: any = []; + private static fileList: any = []; + private static expandedFileList: any = []; + private static mini_arguments: any; + + + static readSubdirectories(baseDir: string) { + fs.readdir(baseDir, (err, filesList) => { + if (err) throw err + + log.debug('readSubdirectories - files', filesList) + + filesList.forEach((subDirOrFile) => { + const newFullPath = cwd + '/' + subDirOrFile + + if (fs.existsSync(newFullPath)) { + const s = fs.statSync(newFullPath) + + if (s.isFile()) { + this.expandedFileList.push(cwd + '/' + subDirOrFile) + } + } + }) + + return filesList; + }) + } + + static isFolderOrFile(filePathName: string) { + const stat = fs.statSync(filePathName) + + if (stat.isDirectory()) { + this.fileList = this.readSubdirectories(filePathName) + log.debug('fileList in directory ', filePathName, '\n', this.fileList) + if (this.fileList.length) { + this.expandedFileList.push(...this.fileList) + } + } else if (stat.isFile()) { + this.expandedFileList.push(filePathName) + } + } + + + /** + * guess file name on one file which is not a directory + * @param fullPath + */ + + static guessFileNameOnOnefile(fullPath: string):void { + + 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 = this.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') + + this.findExifCreationDate(structureForFile.fullPath) + .then(data => { + log.info(' ... chercher la date de création : "' + structureForFile.freeText + '"') + let foundDate = this.findEarliestDateInExifData(data) + + log.info(' =>>>>>>> foundDate : ', foundDate) + if (foundDate) { + structureForFile.dateStampExif = foundDate + } else { + log.info('pas de date trouvée dans le nom') + } + this.shouldWeChangeName(structureForFile) + } + , + (error) => { + log.warn('/////////// Error in reading exif of file: ' + error.message) + return '' + }) + } + + } + }) + } + + + /** + * if there is no original file name free text into the new name, append it to the free text part + * @param originalFileName + * @param fileMixedNewName + */ + static addOriginalFileNameIfMissing(originalFileName: string, fileMixedNewName: string) { + + if (!fileMixedNewName.includes(originalFileName)) { + let properties = finder.destructurateFileName(fileMixedNewName) + return properties.freeText + ' ' + originalFileName + } else { + return fileMixedNewName + } + } static reportStatistics() { log.info('\n --------- statistics', this.statistics) } + static renameFile(originalFileName: string, fileMixedNewName: string) { + if (rangement_instance.keepOriginalNameInRename) { + fileMixedNewName = this.addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) + } + + let self = this; + fs.rename(originalFileName, fileMixedNewName, function (err) { + log.info('name changed', fileMixedNewName) + if (err) { + log.info('rename ERROR: ' + err) + } else { + self.otherRenames.push(fileMixedNewName) + + finder.statistics['filesModified']++ + } + }) + } + + static guessFileNameOnAllFilesFromArguments():void { + + // parcourir les fichiers + log.debug('liste des fichiers', this.mini_arguments._) + let fileList = this.mini_arguments._ + + // test file exists + fileList.forEach((fullPath: string) => { + log.debug('file list element: ', fullPath) + // parcourir les dossiers + this.isFolderOrFile(`${fullPath}`) + } + ) + + log.info('expanded file list :', this.expandedFileList) + this.expandedFileList.forEach((filePath: string) => this.guessFileNameOnOnefile(filePath)) + + if (rangement_instance.reportStatistics || this.mini_arguments.stats) { + finder.reportStatistics() + } + + } + + + static makeFileNameFromProperties(fileProperties: fileDestructuration) { + + 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) + } + log.debug('fileProperties.dateStampExif', fileProperties.dateStampExif) + let newName = '' + + fileProperties.dateStampExif + + ' ' + + (rangement_instance.keepFreeText ? fileProperties.freeText : '') + + tagPlace + + fileProperties.extension + + if (rangement_instance.replaceUnderscoreWithSpaces) { + newName = newName.replace('_', ' ') + } + + newName = finder.cleanSpaces(newName) + + return newName + } + + static parseArguments() { + this.mini_arguments = minimist(process.argv.slice(2)) + log.debug('arguments', this.mini_arguments) + } + + static shouldWeChangeName(structureForFile: fileDestructuration) { + log.info(' ______ shouldWeChangeName ', structureForFile.fileNameOriginal) + let newName = this.makeFileNameFromProperties(structureForFile) + log.debug('newName', newName) + if (structureForFile.fileNameOriginal !== newName && !this.otherRenames.includes(newName)) { + + log.info('\n ancien nom :', structureForFile.fileNameOriginal) + + log.info(' nouveau nom:', newName) + if (!this.mini_arguments['dry-run']) { + + this.renameFile(structureForFile.fullPath, structureForFile.folderPath + newName) + } else { + log.info('no renaming for real, this is a dry run') + finder.statistics['filesNotModified']++ + } + } else { + log.info(' rien à changer') + } + } + static findScreenshot(inputString: string) { return inputString.match(/screenshot/i) || inputString.match(/capture d'écran/i) } @@ -191,9 +392,9 @@ export default class finder { * @param fileName * @returns {*} */ - static addTagInFileName(tagName:string, fileName:string) { + static addTagInFileName(tagName: string, fileName: string) { - let tags:any = this.findTagSectionInString(fileName) + let tags: any = this.findTagSectionInString(fileName) let firstPart = this.findFileNameFreeTextPart(fileName) tags.push(tagName) @@ -210,7 +411,7 @@ export default class finder { * @param fullPath * @returns {{extension: *, dateStamp: string, freeText: (*|string), tags: *[]}} */ - static destructurateFileName(fullPath:string) { + static destructurateFileName(fullPath: string): fileDestructuration { let [folderPath, fileNameOriginal] = this.findFolderPath(fullPath) let dateStampInFileNameOriginal = this.findFormattedDate(fileNameOriginal) return { @@ -222,7 +423,7 @@ export default class finder { freeText: this.findFileNameFreeTextPart(fileNameOriginal), tags: this.findTagSectionInString(fileNameOriginal), extension: this.findFileExtension(fileNameOriginal), - } + } as fileDestructuration } @@ -231,7 +432,7 @@ export default class finder { * @param exifData * @returns {string} */ - static findEarliestDateInExifData(exifData:any) { + static findEarliestDateInExifData(exifData: any) { log.debug(' finder - findEarliestDateInExifData') if (exifData) { @@ -282,12 +483,12 @@ export default class finder { } - static appendFileName(fileProperties:fileDestructuration, newText:string) { + static appendFileName(fileProperties: fileDestructuration, newText: string) { fileProperties.freeText = finder.cleanSpaces(fileProperties.freeText + ' ' + newText) return fileProperties } - static prependFileName(fileProperties:fileDestructuration, newText:string) { + static prependFileName(fileProperties: fileDestructuration, newText: string) { fileProperties.freeText = finder.cleanSpaces(newText + ' ' + fileProperties.freeText) return fileProperties } @@ -296,7 +497,7 @@ export default class finder { * examine plusieurs propriétés exif de date et retourne la plus ancienne * @param filepath */ - static async findExifCreationDate(filepath:string) { + static async findExifCreationDate(filepath: string) { log.debug(' finder - filepath', filepath) let dateAlreadyInFileName = finder.findFormattedDate(filepath) @@ -309,9 +510,9 @@ export default class finder { } - static findFolderPath(filePath:string) { - let folders:any = filePath.split('/') - let fileName:any = folders.pop() + static findFolderPath(filePath: string) { + let folders: any = filePath.split('/') + let fileName: any = folders.pop() folders = filePath.replace(fileName, '') log.debug(' finder - \n - folders', folders)