exiftool-vendored
Version:
Efficient, cross-platform access to ExifTool
171 lines • 5.75 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.ExifDate = void 0;
const luxon_1 = require("luxon");
const DateTime_1 = require("./DateTime");
const Maybe_1 = require("./Maybe");
const String_1 = require("./String");
const StrictExifRE = /^\d{1,4}:\d{1,2}:\d{1,2}|\d{1,4}-\d{1,2}-\d{1,2}$/;
const YearMonthRE = /^\d{1,4}[:-]\d{1,2}$/;
const YearOnlyRE = /^\d{1,4}$/;
const LooseExifRE = /^\S+\s+\S+\s+\S+$/;
/**
* Encodes an ExifDate
*/
class ExifDate {
year;
month;
day;
rawValue;
static from(exifOrIso) {
if (typeof exifOrIso === "number") {
return this.fromYear(exifOrIso);
}
return (
// in order of strictness:
this.fromExifStrict(exifOrIso) ??
this.fromYearMonth(exifOrIso) ??
this.fromYear(exifOrIso) ??
this.fromISO(exifOrIso) ??
this.fromExifLoose(exifOrIso));
}
static fromISO(text) {
return StrictExifRE.test((0, String_1.toS)(text).trim())
? this.fromDateTime(luxon_1.DateTime.fromISO(text), text)
: undefined;
}
static fromPatterns(text, fmts) {
if ((0, String_1.blank)(text))
return;
text = (0, String_1.toS)(text).trim();
for (const fmt of fmts) {
const dt = luxon_1.DateTime.fromFormat(text, fmt);
if ((0, DateTime_1.validDateTime)(dt)) {
return this.fromDateTime(dt, text);
}
}
return;
}
// These are all formats I've seen in the wild from exiftool's output.
// More iterations might make sense, like "d MMM, y" or "MMM d, y", but I
// want to be constrained in what I consider a valid date to lessen the
// chance of misinterpreting a given value.
static fromExifStrict(text) {
return StrictExifRE.test((0, String_1.toS)(text).trim())
? this.fromPatterns(text, ["y:MM:dd", "y-MM-dd", "y:M:d"])
: undefined;
}
static fromYearMonth(text) {
const textStr = (0, String_1.toS)(text).trim();
if (!YearMonthRE.test(textStr))
return undefined;
for (const fmt of ["y:MM", "y-MM", "y:M", "y-M"]) {
const dt = luxon_1.DateTime.fromFormat(textStr, fmt);
if ((0, DateTime_1.validDateTime)(dt)) {
return new ExifDate(dt.year, dt.month, undefined, textStr);
}
}
return undefined;
}
static fromYear(yearValue) {
const textStr = (0, String_1.toS)(yearValue).trim();
if (YearOnlyRE.test(textStr)) {
const year = parseInt(textStr, 10);
if (!isNaN(year) && year > 0 && year <= 9999) {
return new ExifDate(year, undefined, undefined, textStr);
}
}
return undefined;
}
static fromExifLoose(text) {
// Unfortunately, Luxon parses "00" and "01" as _today_. So if we don't
// three non-blank strings parts, reject.
return LooseExifRE.test((0, String_1.toS)(text).trim())
? this.fromPatterns(text, ["MMM d y", "MMMM d y"])
: undefined;
}
static fromEXIF(text) {
return (0, Maybe_1.firstDefinedThunk)([
() => this.fromExifStrict(text),
() => this.fromExifLoose(text),
]);
}
static fromDateTime(dt, rawValue) {
return (0, DateTime_1.validDateTime)(dt)
? new ExifDate(dt.year, dt.month, dt.day, rawValue)
: undefined;
}
constructor(year, // full year (probably 2019-ish, but maybe Japanese 30-ish). See https://ericasadun.com/2018/12/25/iso-8601-yyyy-yyyy-and-why-your-year-may-be-wrong/
month, // 1-12, (no crazy 0-11 nonsense from Date!)
day, // 1-31
rawValue) {
this.year = year;
this.month = month;
this.day = day;
this.rawValue = rawValue;
}
toDate() {
return new Date(this.year, (this.month ?? 1) - 1, this.day ?? 1);
}
/**
* @param deltaMs defaults to 12 hours, so toMillis() is in the middle of the day.
*
* @return the epoch milliseconds for this day in UTC, plus `deltaMs` milliseconds.
*/
toMillis(deltaMs = 12 * DateTime_1.HourMs) {
return this.toDate().getTime() + deltaMs;
}
toISOString() {
return this.toString("-");
}
toExifString() {
return this.toString(":");
}
toString(sep = "-") {
if (this.month == null) {
return `${this.year}`;
}
if (this.day == null) {
return `${this.year}${sep}${(0, String_1.pad2)(this.month).join("")}`;
}
return `${this.year}${sep}${(0, String_1.pad2)(this.month, this.day).join(sep)}`;
}
toJSON() {
return {
_ctor: "ExifDate",
year: this.year,
month: this.month,
day: this.day,
rawValue: this.rawValue,
};
}
static fromJSON(json) {
return new ExifDate(json.year, json.month, json.day, json.rawValue);
}
/**
* @returns true if this is a partial date (year-only or year-month)
*/
isPartial() {
return this.month == null || this.day == null;
}
/**
* @returns true if this is a year-only date
*/
isYearOnly() {
return this.month == null;
}
/**
* @returns true if this is a year-month date (no day)
*/
isYearMonth() {
return this.month != null && this.day == null;
}
/**
* @returns true if this is a full date (year, month, and day)
*/
isFullDate() {
return this.month != null && this.day != null;
}
}
exports.ExifDate = ExifDate;
//# sourceMappingURL=ExifDate.js.map