2023-07-01 12:35:33 +02:00
|
|
|
/**---------------------
|
|
|
|
* @name tykayn Rangement
|
|
|
|
* @description Rangement sorts and rename files depending on their exif data
|
|
|
|
* @contact contact@cipherbliss.com
|
2023-07-04 15:26:27 +02:00
|
|
|
--------------------- */
|
2023-07-01 12:35:33 +02:00
|
|
|
/** ---------------------
|
2023-07-04 15:26:27 +02:00
|
|
|
libs
|
|
|
|
--------------------- */
|
2023-07-01 12:35:33 +02:00
|
|
|
import fs from 'node-fs'
|
|
|
|
import minimist from 'minimist'
|
2023-07-04 12:08:05 +02:00
|
|
|
import log from 'loglevel';
|
2023-07-04 15:26:27 +02:00
|
|
|
import path from "node:path";
|
2023-07-01 12:35:33 +02:00
|
|
|
/** ---------------------
|
2023-07-04 15:26:27 +02:00
|
|
|
custom utilities and configuration
|
2023-07-01 12:35:33 +02:00
|
|
|
--------------------- */
|
2023-07-04 15:26:27 +02:00
|
|
|
import rangement_instance from './configs.mjs'
|
2023-07-01 12:35:33 +02:00
|
|
|
import {
|
2023-07-04 15:26:27 +02:00
|
|
|
TestFindFormattedDate,
|
|
|
|
TestScreenShotIsFoundAndRenamed,
|
|
|
|
TestTagsAreDetectedInFileName
|
2023-07-01 12:35:33 +02:00
|
|
|
} from './testFunctions.mjs'
|
|
|
|
import finder from './finder.mjs'
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
import exiftool from "node-exiftool";
|
|
|
|
|
2023-07-01 12:35:33 +02:00
|
|
|
let mini_arguments
|
2023-07-04 15:26:27 +02:00
|
|
|
|
|
|
|
log.setLevel(rangement_instance.log_level)
|
2023-07-04 12:08:05 +02:00
|
|
|
log.info(' ')
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function parseArguments() {
|
|
|
|
mini_arguments = minimist(process.argv.slice(2))
|
|
|
|
log.debug('arguments', mini_arguments)
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function addOriginalFileNameIfMissing(originalFileName, fileMixedNewName) {
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:56:15 +02:00
|
|
|
// 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)
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function renameFile(originalFileName, fileMixedNewName) {
|
|
|
|
fs.rename(originalFileName, fileMixedNewName, function (err) {
|
|
|
|
log.info('name changed', fileMixedNewName)
|
|
|
|
if (err) {
|
|
|
|
log.info('rename ERROR: ' + err)
|
|
|
|
} else {
|
2023-07-04 16:14:25 +02:00
|
|
|
// otherRenames.push(originalFileName)
|
|
|
|
otherRenames.push(fileMixedNewName)
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
addOriginalFileNameIfMissing(originalFileName, fileMixedNewName)
|
2023-07-04 15:56:15 +02:00
|
|
|
// rangement_instance.statistics['filesModified']++
|
2023-07-04 15:26:27 +02:00
|
|
|
}
|
|
|
|
})
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function appendFileName(fileProperties, newText) {
|
|
|
|
fileProperties.freeText = finder.cleanSpaces(fileProperties.freeText + ' ' + newText)
|
|
|
|
return fileProperties
|
|
|
|
}
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function prependFileName(fileProperties, newText) {
|
|
|
|
fileProperties.freeText = finder.cleanSpaces(newText + ' ' + fileProperties.freeText)
|
|
|
|
return fileProperties
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function makeFileNameFromProperties(fileProperties) {
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
let tagPlace = ''
|
2023-07-04 16:14:25 +02:00
|
|
|
log.info('fileProperties.tags',fileProperties.tags)
|
2023-07-04 15:56:15 +02:00
|
|
|
if (fileProperties.tags.length && rangement_instance.keepTags) {
|
|
|
|
tagPlace = ' ' + rangement_instance.tagSectionSeparator + ' '+ fileProperties.tags.join(rangement_instance.tagSeparator)
|
2023-07-04 15:26:27 +02:00
|
|
|
}
|
2023-07-04 16:14:25 +02:00
|
|
|
console.log('fileProperties.dateStampExif', fileProperties.dateStampExif)
|
2023-07-04 15:56:15 +02:00
|
|
|
let newName = ''
|
|
|
|
+ fileProperties.dateStampExif
|
|
|
|
+ ' '
|
|
|
|
+ (rangement_instance.keepFreeText? fileProperties.freeText : '')
|
|
|
|
+ tagPlace
|
|
|
|
+ fileProperties.extension;
|
|
|
|
|
|
|
|
if(rangement_instance.replaceUnderscoreWithSpaces){
|
|
|
|
newName = newName.replace('_', ' ')
|
|
|
|
}
|
|
|
|
|
|
|
|
newName = newName.replace(' ', '')
|
|
|
|
|
|
|
|
return newName
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 16:14:25 +02:00
|
|
|
let otherRenames = [];
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function shouldWeChangeName(structureForFile) {
|
2023-07-04 15:56:15 +02:00
|
|
|
log.info(' ______ shouldWeChangeName ', structureForFile.fileNameOriginal)
|
2023-07-04 15:26:27 +02:00
|
|
|
let newName = makeFileNameFromProperties(structureForFile)
|
2023-07-04 15:56:15 +02:00
|
|
|
log.debug('newName', newName)
|
2023-07-04 16:14:25 +02:00
|
|
|
if (structureForFile.fileNameOriginal !== newName && !otherRenames.includes(newName)) {
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
log.info('\n ancien nom :', structureForFile.fileNameOriginal)
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
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')
|
|
|
|
}
|
|
|
|
}
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
/**
|
|
|
|
* guess file name on one file which is not a directory
|
|
|
|
* @param fullPath
|
|
|
|
*/
|
|
|
|
function guessFileNameOnOnefile(fullPath) {
|
|
|
|
|
2023-07-04 15:56:15 +02:00
|
|
|
log.info('go guess file name on file: ', fullPath )
|
2023-07-04 15:26:27 +02:00
|
|
|
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) {
|
2023-07-04 15:56:15 +02:00
|
|
|
log.info(' le nom de fichier "'+structureForFile.freeText +'" ne contient pas de date formatée au début')
|
2023-07-04 15:26:27 +02:00
|
|
|
|
|
|
|
finder.findExifCreationDate(structureForFile.fullPath)
|
|
|
|
.then(data => {
|
2023-07-04 15:56:15 +02:00
|
|
|
log.info(' ... chercher la date de création : "'+structureForFile.freeText +'"')
|
2023-07-04 15:26:27 +02:00
|
|
|
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')
|
|
|
|
}
|
2023-07-04 15:56:15 +02:00
|
|
|
shouldWeChangeName(structureForFile)
|
2023-07-04 15:26:27 +02:00
|
|
|
}
|
|
|
|
,
|
|
|
|
(error) => {
|
|
|
|
log.warn('/////////// Error in reading exif of file: ' + error.message)
|
|
|
|
return ''
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
let expandedFileList = []
|
|
|
|
let cwd = path.dirname(process.cwd()) + '/' + path.basename(process.cwd());
|
|
|
|
console.log('cwd', cwd)
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function guessFileNameOnAllFilesFromArguments() {
|
2023-07-01 12:35:33 +02:00
|
|
|
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
// parcourir les fichiers
|
|
|
|
log.debug('liste des fichiers', mini_arguments._)
|
|
|
|
let fileList = mini_arguments._
|
2023-07-01 12:35:33 +02:00
|
|
|
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
// test file exists
|
|
|
|
fileList.forEach(fullPath => {
|
|
|
|
// parcourir les dossiers
|
|
|
|
isFolderOrFile(`${fullPath}`)
|
|
|
|
}
|
|
|
|
)
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
log.info('expanded file list :', expandedFileList)
|
|
|
|
expandedFileList.forEach(filePath => guessFileNameOnOnefile(filePath))
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
}
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function readSubdirectories(baseDir) {
|
|
|
|
const newGlob = baseDir;
|
|
|
|
fs.readdir(baseDir, (err, files) => {
|
|
|
|
if (err) throw err;
|
|
|
|
|
2023-07-04 15:56:15 +02:00
|
|
|
console.log('readSubdirectories - files', files)
|
2023-07-04 15:26:27 +02:00
|
|
|
files.forEach((subDirOrFile) => {
|
2023-07-04 15:56:15 +02:00
|
|
|
const newFullPath = cwd +'/'+ subDirOrFile;
|
2023-07-04 15:26:27 +02:00
|
|
|
|
|
|
|
if (fs.existsSync(newFullPath)) {
|
|
|
|
const s = fs.statSync(newFullPath);
|
|
|
|
|
|
|
|
if (s.isFile()) {
|
2023-07-04 15:56:15 +02:00
|
|
|
expandedFileList.push(cwd+'/'+subDirOrFile)
|
2023-07-04 15:26:27 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
function isFolderOrFile(fileName) {
|
2023-07-04 15:56:15 +02:00
|
|
|
// const stat = fs.statSync(cwd + '/' + fileName);
|
|
|
|
const stat = fs.statSync( fileName);
|
2023-07-04 15:26:27 +02:00
|
|
|
|
|
|
|
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()
|
|
|
|
|
2023-07-01 12:35:33 +02:00
|
|
|
guessFileNameOnAllFilesFromArguments()
|
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
|
2023-07-01 12:35:33 +02:00
|
|
|
// run tests
|
2023-07-04 15:26:27 +02:00
|
|
|
if (rangement_instance.enableTestsLocally) {
|
2023-07-01 12:35:33 +02:00
|
|
|
|
2023-07-04 15:26:27 +02:00
|
|
|
TestTagsAreDetectedInFileName()
|
|
|
|
TestFindFormattedDate()
|
|
|
|
TestScreenShotIsFoundAndRenamed()
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|
2023-07-04 15:26:27 +02:00
|
|
|
if (rangement_instance.reportStatistics || mini_arguments.stats) {
|
|
|
|
finder.reportStatistics()
|
2023-07-01 12:35:33 +02:00
|
|
|
}
|