import fs from "fs/promises"; import ExifReader from "exifreader"; import path from "path"; if (process.argv.length === 2) { console.error("Expected exactly one argument"); process.exit(1); } const dir = process.argv[2]; let fileNames; try { fileNames = await fs.readdir(dir); } catch (error) { console.error("Error reading directory.", error); process.exit(2); } /** * @param fileName {string} * @return {Date|null} */ function getDateFromFileName(fileName) { const r = /(\d{4})-?(\d{2})-?(\d{2})[_\-](\d{2})-?(\d{2})-?(\d{2})/.exec( fileName, ); if (!r) throw new Error("The file name did not match the pattern."); return new Date(`${r[1]}-${r[2]}-${r[3]}T${r[4]}:${r[5]}:${r[6]}`); } /** * @param filePath {string} * @param fileName {string} * @return {Promise} */ async function getDate(filePath, fileName) { if (/\.mp4$/.test(fileName)) { return getDateFromFileName(fileName); } const tags = await ExifReader.load(filePath); let timeString = tags.DateTime?.value[0]; if (timeString === undefined) { return getDateFromFileName(fileName); } const exifDate = new Date( timeString.replace( /(\d{4}):(\d{2}):(\d{2}) (\d{2}):(\d{2}):(\d{2})/, "$1-$2-$3T$4:$5:$6", ), ); if (isNaN(exifDate.getTime()) || exifDate.getFullYear() < 2000) { return getDateFromFileName(fileName); } return exifDate; } for (const fileName of fileNames) { const filePath = path.resolve(dir, fileName); let date; try { date = await getDate(filePath, fileName); } catch (error) { console.error(filePath, error.message); continue; } if (date === null) { console.error(filePath, "Could not get a date."); continue; } console.log(filePath, date); await fs.utimes(filePath, date, date); }