foldnize 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +159 -0
- package/dist/bin/foldnize.d.ts +3 -0
- package/dist/bin/foldnize.d.ts.map +1 -0
- package/dist/bin/foldnize.js +226 -0
- package/dist/bin/foldnize.js.map +1 -0
- package/dist/src/index.d.ts +6 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +14 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/metadata.d.ts +23 -0
- package/dist/src/metadata.d.ts.map +1 -0
- package/dist/src/metadata.js +138 -0
- package/dist/src/metadata.js.map +1 -0
- package/dist/src/naming.d.ts +19 -0
- package/dist/src/naming.d.ts.map +1 -0
- package/dist/src/naming.js +96 -0
- package/dist/src/naming.js.map +1 -0
- package/dist/src/organize.d.ts +49 -0
- package/dist/src/organize.d.ts.map +1 -0
- package/dist/src/organize.js +124 -0
- package/dist/src/organize.js.map +1 -0
- package/dist/src/walk.d.ts +7 -0
- package/dist/src/walk.d.ts.map +1 -0
- package/dist/src/walk.js +37 -0
- package/dist/src/walk.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/package.json +63 -0
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# foldnize
|
|
2
|
+
|
|
3
|
+
Organize photos and videos by their embedded EXIF/QuickTime **original date**, programmatically or from the command line.
|
|
4
|
+
|
|
5
|
+
- Three renaming modes: **prefix** · **replace** · **custom**
|
|
6
|
+
- Optional **Year/Month folder sorting** (`<root>/YYYY/MM/`)
|
|
7
|
+
- **Dry-run** preview before touching disk
|
|
8
|
+
- Streamed log of every action via callback
|
|
9
|
+
- 100% local — no network, no telemetry
|
|
10
|
+
- Written in **TypeScript**, ships compiled JS + `.d.ts` types, **zero runtime dependencies**
|
|
11
|
+
- Powers the [Foldnize desktop app](https://github.com/matheuschignolli/foldnize)
|
|
12
|
+
|
|
13
|
+
## Install
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install foldnize
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
### System tools (optional but recommended)
|
|
20
|
+
|
|
21
|
+
`foldnize` shells out to read embedded metadata. Install one or both:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
brew install exiftool # photos + most formats — best coverage
|
|
25
|
+
brew install ffmpeg # ffprobe — fallback for .mp4
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Files without parseable date metadata are silently skipped — never crash.
|
|
29
|
+
|
|
30
|
+
## Library usage
|
|
31
|
+
|
|
32
|
+
```ts
|
|
33
|
+
import {
|
|
34
|
+
organizeFolder,
|
|
35
|
+
type OrganizeOptions,
|
|
36
|
+
type OrganizeSummary,
|
|
37
|
+
type Mode,
|
|
38
|
+
} from "foldnize";
|
|
39
|
+
// CommonJS works too: const { organizeFolder } = require("foldnize");
|
|
40
|
+
|
|
41
|
+
const summary: OrganizeSummary = organizeFolder({
|
|
42
|
+
root: "/Users/you/Pictures/2023",
|
|
43
|
+
mode: Mode.CUSTOM, // Mode.PREFIX | Mode.REPLACE | Mode.CUSTOM
|
|
44
|
+
customName: "vacation", // required when mode === Mode.CUSTOM
|
|
45
|
+
organizeIntoYearMonth: true, // move files into <root>/YYYY/MM/
|
|
46
|
+
scanSubfolders: true, // recurse (default); false = top-level only
|
|
47
|
+
dryRun: true, // preview only — no disk writes
|
|
48
|
+
onLog: ({ level, message }) => console.log(`[${level}] ${message}`),
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
console.log(summary);
|
|
52
|
+
// {
|
|
53
|
+
// found: 12,
|
|
54
|
+
// renamed: 8,
|
|
55
|
+
// moved: 4,
|
|
56
|
+
// skipped: 4,
|
|
57
|
+
// }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
A file can appear in **both** `renamed` and `moved` counts if it changes name AND directory.
|
|
61
|
+
|
|
62
|
+
### Modes
|
|
63
|
+
|
|
64
|
+
| Mode | Result | Example |
|
|
65
|
+
| --------- | --------------------------------------------- | ----------------------------------------------- |
|
|
66
|
+
| `prefix` | Keep original name, add `YYYYMMDD-` in front. | `IMG_1234.jpg` → `20230715-IMG_1234.jpg` |
|
|
67
|
+
| `replace` | Fully rename to `YYYYMMDD-HHMMSS.ext`. | `IMG_1234.jpg` → `20230715-142310.jpg` |
|
|
68
|
+
| `custom` | Fully rename to `{name}-YYYYMMDD-HHMMSS.ext`. | `IMG_1234.jpg` → `vacation-20230715-142310.jpg` |
|
|
69
|
+
|
|
70
|
+
### Log levels
|
|
71
|
+
|
|
72
|
+
`onLog` receives `{ level, message }` for every step:
|
|
73
|
+
|
|
74
|
+
| Level | Meaning |
|
|
75
|
+
| --------- | ------------------------------------------------------- |
|
|
76
|
+
| `info` | Configuration banner before scanning starts. |
|
|
77
|
+
| `renamed` | File was renamed in place (same directory). |
|
|
78
|
+
| `moved` | File was moved (possibly renamed too). |
|
|
79
|
+
| `dry` | Dry-run preview line. |
|
|
80
|
+
| `skip` | File was untouched (no metadata, already formatted, …). |
|
|
81
|
+
| `error` | Something went wrong with a specific file. |
|
|
82
|
+
| `done` | Final summary line. |
|
|
83
|
+
|
|
84
|
+
### Other exports
|
|
85
|
+
|
|
86
|
+
```ts
|
|
87
|
+
import {
|
|
88
|
+
organizeFolder,
|
|
89
|
+
sanitizeCustomName, // (unknown) => string — same rules as in CLI
|
|
90
|
+
getOriginalFileDateParts, // (filePath: string) => DateParts | null
|
|
91
|
+
formatDateToParts, // (dateString: string | null) => DateParts | null
|
|
92
|
+
VALID_EXTENSIONS, // ReadonlySet<".mp4" | ".jpg" | ".jpeg" | ".png">
|
|
93
|
+
type DateParts,
|
|
94
|
+
type Mode,
|
|
95
|
+
type LogEntry,
|
|
96
|
+
type LogLevel,
|
|
97
|
+
type OrganizeOptions,
|
|
98
|
+
type OrganizeSummary,
|
|
99
|
+
} from "foldnize";
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## CLI usage
|
|
103
|
+
|
|
104
|
+
The package ships a CLI you can run without installing globally:
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npx foldnize --root=./photos --mode=prefix --dry-run
|
|
108
|
+
npx foldnize --root=./photos --mode=replace --year-month
|
|
109
|
+
npx foldnize --root=./photos --mode=custom --custom-name=vacation
|
|
110
|
+
npx foldnize --root=./photos --year-month --no-subfolders
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Options
|
|
114
|
+
|
|
115
|
+
```
|
|
116
|
+
--root=PATH Folder to scan (default: current directory)
|
|
117
|
+
--mode=prefix|replace|custom
|
|
118
|
+
--custom-name=NAME Required when --mode=custom
|
|
119
|
+
--year-month Move files into <root>/YYYY/MM/
|
|
120
|
+
--no-subfolders Don't recurse — only top-level files
|
|
121
|
+
--dry-run Preview without touching disk
|
|
122
|
+
--help, -h
|
|
123
|
+
--version, -v
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### Behaviour notes
|
|
127
|
+
|
|
128
|
+
- **macOS junk files** (`._*`) are always skipped.
|
|
129
|
+
- **Collisions** are handled by appending `-1`, `-2`, … to the target name.
|
|
130
|
+
- **Already-formatted files** are detected and skipped for renames; they still get moved if `--year-month` is on and their date metadata points to a different folder than where they currently sit.
|
|
131
|
+
- **Empty source folders** left behind after moves are NOT deleted. That's intentionally non-destructive.
|
|
132
|
+
|
|
133
|
+
## Requirements
|
|
134
|
+
|
|
135
|
+
- Node.js **18+**
|
|
136
|
+
|
|
137
|
+
## Publishing
|
|
138
|
+
|
|
139
|
+
Releases to npm are automated via GitHub Actions when you publish a GitHub Release. See [`.github/PUBLISHING.md`](../.github/PUBLISHING.md) for the `NPM_TOKEN` secret, environment setup, and release tags like `foldnize-v1.0.0`.
|
|
140
|
+
|
|
141
|
+
## Development
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
git clone https://github.com/matheuschignolli/foldnize.git
|
|
145
|
+
cd foldnize/library
|
|
146
|
+
npm install
|
|
147
|
+
|
|
148
|
+
npm run build # compile TypeScript → dist/
|
|
149
|
+
npm run build:watch # incremental rebuilds
|
|
150
|
+
npm run typecheck # type-check tests too (no emit)
|
|
151
|
+
npm test # run the test suite (via tsx, no separate compile step)
|
|
152
|
+
npm run clean # remove dist/
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Source lives in `src/` (TypeScript). Compiled output lands in `dist/` and is the only thing that ships to npm.
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foldnize.d.ts","sourceRoot":"","sources":["../../bin/foldnize.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
4
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
5
|
+
};
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const src_1 = require("../src");
|
|
10
|
+
function parseMode(value) {
|
|
11
|
+
switch (value) {
|
|
12
|
+
case "prefix":
|
|
13
|
+
return src_1.Mode.PREFIX;
|
|
14
|
+
case "replace":
|
|
15
|
+
return src_1.Mode.REPLACE;
|
|
16
|
+
case "custom":
|
|
17
|
+
return src_1.Mode.CUSTOM;
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Invalid --mode value: "${value ?? ""}". Use --mode=prefix | replace | custom.`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
23
|
+
// argv parsing
|
|
24
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
25
|
+
function parseArgs(argv) {
|
|
26
|
+
const args = {
|
|
27
|
+
root: process.cwd(),
|
|
28
|
+
mode: src_1.Mode.PREFIX,
|
|
29
|
+
customName: undefined,
|
|
30
|
+
dryRun: false,
|
|
31
|
+
organizeIntoYearMonth: false,
|
|
32
|
+
scanSubfolders: true,
|
|
33
|
+
help: false,
|
|
34
|
+
version: false,
|
|
35
|
+
};
|
|
36
|
+
for (const arg of argv) {
|
|
37
|
+
if (arg === "--help" || arg === "-h") {
|
|
38
|
+
args.help = true;
|
|
39
|
+
}
|
|
40
|
+
else if (arg === "--version" || arg === "-v") {
|
|
41
|
+
args.version = true;
|
|
42
|
+
}
|
|
43
|
+
else if (arg === "--dry-run") {
|
|
44
|
+
args.dryRun = true;
|
|
45
|
+
}
|
|
46
|
+
else if (arg === "--organize-year-month" || arg === "--year-month") {
|
|
47
|
+
args.organizeIntoYearMonth = true;
|
|
48
|
+
}
|
|
49
|
+
else if (arg === "--no-subfolders" || arg === "--top-level") {
|
|
50
|
+
args.scanSubfolders = false;
|
|
51
|
+
}
|
|
52
|
+
else if (arg.startsWith("--mode=")) {
|
|
53
|
+
const rawValue = arg.split("=")[1];
|
|
54
|
+
const value = rawValue?.trim().toLowerCase();
|
|
55
|
+
args.mode = parseMode(value);
|
|
56
|
+
}
|
|
57
|
+
else if (arg.startsWith("--custom-name=") || arg.startsWith("--name=")) {
|
|
58
|
+
const value = arg.split("=").slice(1).join("=").trim();
|
|
59
|
+
if (!value) {
|
|
60
|
+
throw new Error("--custom-name requires a non-empty value.");
|
|
61
|
+
}
|
|
62
|
+
args.customName = value;
|
|
63
|
+
}
|
|
64
|
+
else if (arg.startsWith("--root=") || arg.startsWith("--dir=")) {
|
|
65
|
+
const value = arg.split("=").slice(1).join("=").trim();
|
|
66
|
+
if (!value) {
|
|
67
|
+
throw new Error("--root requires a non-empty value.");
|
|
68
|
+
}
|
|
69
|
+
args.root = node_path_1.default.resolve(value);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
throw new Error(`Unknown argument: ${arg}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return args;
|
|
76
|
+
}
|
|
77
|
+
function printHelp() {
|
|
78
|
+
console.log(`
|
|
79
|
+
foldnize — Organize media files by their embedded original date.
|
|
80
|
+
|
|
81
|
+
Usage:
|
|
82
|
+
foldnize [options]
|
|
83
|
+
|
|
84
|
+
Options:
|
|
85
|
+
--root=PATH Folder to scan (default: current directory)
|
|
86
|
+
--mode=MODE prefix | replace | custom (default: prefix)
|
|
87
|
+
--custom-name=NAME Required when --mode=custom
|
|
88
|
+
--year-month Also move files into <root>/YYYY/MM/ subfolders
|
|
89
|
+
--no-subfolders Don't recurse — only top-level files
|
|
90
|
+
--dry-run Preview changes without touching disk
|
|
91
|
+
--help, -h Show this help
|
|
92
|
+
--version, -v Show version
|
|
93
|
+
|
|
94
|
+
Modes:
|
|
95
|
+
prefix Keeps the original name, adds YYYYMMDD- in front.
|
|
96
|
+
replace Renames to YYYYMMDD-HHMMSS.ext.
|
|
97
|
+
custom Renames to {customName}-YYYYMMDD-HHMMSS.ext.
|
|
98
|
+
|
|
99
|
+
Examples:
|
|
100
|
+
foldnize --root=./photos --mode=prefix --dry-run
|
|
101
|
+
foldnize --root=./photos --mode=replace --year-month
|
|
102
|
+
foldnize --root=./photos --mode=custom --custom-name=vacation
|
|
103
|
+
foldnize --root=./photos --year-month --no-subfolders
|
|
104
|
+
|
|
105
|
+
Requirements:
|
|
106
|
+
• Node.js 18+
|
|
107
|
+
• exiftool (brew install exiftool) — required for photo metadata
|
|
108
|
+
• ffprobe (brew install ffmpeg) — fallback for .mp4 files
|
|
109
|
+
|
|
110
|
+
Files without parseable date metadata are silently skipped.
|
|
111
|
+
`.trim());
|
|
112
|
+
}
|
|
113
|
+
function readPackageVersion() {
|
|
114
|
+
// When compiled, __dirname is .../dist/bin → ../../package.json
|
|
115
|
+
// When running source via tsx, __dirname is .../bin → ../package.json
|
|
116
|
+
const candidates = [
|
|
117
|
+
node_path_1.default.join(__dirname, "..", "..", "package.json"),
|
|
118
|
+
node_path_1.default.join(__dirname, "..", "package.json"),
|
|
119
|
+
];
|
|
120
|
+
for (const candidate of candidates) {
|
|
121
|
+
try {
|
|
122
|
+
const pkg = JSON.parse(node_fs_1.default.readFileSync(candidate, "utf8"));
|
|
123
|
+
if (pkg.name === "foldnize" && typeof pkg.version === "string") {
|
|
124
|
+
return pkg.version;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// try next candidate
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return "unknown";
|
|
132
|
+
}
|
|
133
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
134
|
+
// Pretty console logging
|
|
135
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
136
|
+
const COLORS = {
|
|
137
|
+
reset: "\x1b[0m",
|
|
138
|
+
dim: "\x1b[2m",
|
|
139
|
+
green: "\x1b[32m",
|
|
140
|
+
cyan: "\x1b[36m",
|
|
141
|
+
blue: "\x1b[34m",
|
|
142
|
+
yellow: "\x1b[33m",
|
|
143
|
+
red: "\x1b[31m",
|
|
144
|
+
bold: "\x1b[1m",
|
|
145
|
+
};
|
|
146
|
+
const supportsColor = Boolean(process.stdout.isTTY && process.env.TERM !== "dumb" && !process.env.NO_COLOR);
|
|
147
|
+
function paint(color, text) {
|
|
148
|
+
if (!supportsColor)
|
|
149
|
+
return text;
|
|
150
|
+
return `${COLORS[color]}${text}${COLORS.reset}`;
|
|
151
|
+
}
|
|
152
|
+
function logEntry({ level, message }) {
|
|
153
|
+
switch (level) {
|
|
154
|
+
case src_1.LogLevel.INFO:
|
|
155
|
+
console.log(paint("dim", message));
|
|
156
|
+
break;
|
|
157
|
+
case src_1.LogLevel.RENAMED:
|
|
158
|
+
console.log(paint("green", "✓ ") + message);
|
|
159
|
+
break;
|
|
160
|
+
case src_1.LogLevel.MOVED:
|
|
161
|
+
console.log(paint("cyan", "→ ") + message);
|
|
162
|
+
break;
|
|
163
|
+
case src_1.LogLevel.DRY:
|
|
164
|
+
console.log(paint("blue", "· ") + message);
|
|
165
|
+
break;
|
|
166
|
+
case src_1.LogLevel.SKIP:
|
|
167
|
+
console.log(paint("yellow", "↷ ") + paint("dim", message));
|
|
168
|
+
break;
|
|
169
|
+
case src_1.LogLevel.ERROR:
|
|
170
|
+
console.error(paint("red", "✗ ") + message);
|
|
171
|
+
break;
|
|
172
|
+
case src_1.LogLevel.DONE:
|
|
173
|
+
console.log("\n" + paint("bold", paint("green", message)));
|
|
174
|
+
break;
|
|
175
|
+
default: {
|
|
176
|
+
const exhaustive = level;
|
|
177
|
+
void exhaustive;
|
|
178
|
+
console.log(message);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
183
|
+
// main
|
|
184
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
185
|
+
function main() {
|
|
186
|
+
let options;
|
|
187
|
+
try {
|
|
188
|
+
options = parseArgs(process.argv.slice(2));
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
192
|
+
console.error(paint("red", message));
|
|
193
|
+
console.log("");
|
|
194
|
+
printHelp();
|
|
195
|
+
process.exit(1);
|
|
196
|
+
}
|
|
197
|
+
if (options.help) {
|
|
198
|
+
printHelp();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
if (options.version) {
|
|
202
|
+
console.log(readPackageVersion());
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
try {
|
|
206
|
+
const summary = (0, src_1.organizeFolder)({
|
|
207
|
+
root: options.root,
|
|
208
|
+
mode: options.mode,
|
|
209
|
+
dryRun: options.dryRun,
|
|
210
|
+
customName: options.customName,
|
|
211
|
+
organizeIntoYearMonth: options.organizeIntoYearMonth,
|
|
212
|
+
scanSubfolders: options.scanSubfolders,
|
|
213
|
+
onLog: logEntry,
|
|
214
|
+
});
|
|
215
|
+
if (summary.found === 0) {
|
|
216
|
+
console.log(paint("yellow", "No supported files found."));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
catch (error) {
|
|
220
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
221
|
+
console.error(paint("red", `Error: ${message}`));
|
|
222
|
+
process.exit(1);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
main();
|
|
226
|
+
//# sourceMappingURL=foldnize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"foldnize.js","sourceRoot":"","sources":["../../bin/foldnize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { organizeFolder, LogLevel } from "./organize";
|
|
2
|
+
export type { LogEntry, LogFn, OrganizeOptions, OrganizeSummary, } from "./organize";
|
|
3
|
+
export { sanitizeCustomName, VALID_EXTENSIONS, Mode } from "./naming";
|
|
4
|
+
export type { DateParts } from "./naming";
|
|
5
|
+
export { formatDateToParts, getOriginalFileDateParts } from "./metadata";
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AACtD,YAAY,EACV,QAAQ,EACR,KAAK,EACL,eAAe,EACf,eAAe,GAChB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,IAAI,EAAE,MAAM,UAAU,CAAC;AACtE,YAAY,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAC1C,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getOriginalFileDateParts = exports.formatDateToParts = exports.Mode = exports.VALID_EXTENSIONS = exports.sanitizeCustomName = exports.LogLevel = exports.organizeFolder = void 0;
|
|
4
|
+
var organize_1 = require("./organize");
|
|
5
|
+
Object.defineProperty(exports, "organizeFolder", { enumerable: true, get: function () { return organize_1.organizeFolder; } });
|
|
6
|
+
Object.defineProperty(exports, "LogLevel", { enumerable: true, get: function () { return organize_1.LogLevel; } });
|
|
7
|
+
var naming_1 = require("./naming");
|
|
8
|
+
Object.defineProperty(exports, "sanitizeCustomName", { enumerable: true, get: function () { return naming_1.sanitizeCustomName; } });
|
|
9
|
+
Object.defineProperty(exports, "VALID_EXTENSIONS", { enumerable: true, get: function () { return naming_1.VALID_EXTENSIONS; } });
|
|
10
|
+
Object.defineProperty(exports, "Mode", { enumerable: true, get: function () { return naming_1.Mode; } });
|
|
11
|
+
var metadata_1 = require("./metadata");
|
|
12
|
+
Object.defineProperty(exports, "formatDateToParts", { enumerable: true, get: function () { return metadata_1.formatDateToParts; } });
|
|
13
|
+
Object.defineProperty(exports, "getOriginalFileDateParts", { enumerable: true, get: function () { return metadata_1.getOriginalFileDateParts; } });
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":";;;AAAA,uCAAsD;AAA7C,0GAAA,cAAc,OAAA;AAAE,oGAAA,QAAQ,OAAA;AAOjC,mCAAsE;AAA7D,4GAAA,kBAAkB,OAAA;AAAE,0GAAA,gBAAgB,OAAA;AAAE,8FAAA,IAAI,OAAA;AAEnD,uCAAyE;AAAhE,6GAAA,iBAAiB,OAAA;AAAE,oHAAA,wBAAwB,OAAA"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { DateParts } from "./naming";
|
|
2
|
+
type DateReader = (filePath: string) => DateParts | null;
|
|
3
|
+
export declare function formatDateToParts(dateString: string | null | undefined): DateParts | null;
|
|
4
|
+
/**
|
|
5
|
+
* Read the embedded original date from a file's metadata.
|
|
6
|
+
*
|
|
7
|
+
* Tries `exiftool` first (works for JPG/PNG/MP4/HEIC and more), then falls
|
|
8
|
+
* back to `ffprobe` for MP4 files. If neither tool is installed, or no
|
|
9
|
+
* recognisable date tag is found, returns `null`.
|
|
10
|
+
*/
|
|
11
|
+
export declare function getOriginalFileDateParts(filePath: string): DateParts | null;
|
|
12
|
+
/**
|
|
13
|
+
* @internal Replace the metadata reader. Used by the test suite to inject
|
|
14
|
+
* deterministic dates without depending on `exiftool` / `ffprobe`.
|
|
15
|
+
* Not exposed via the public `foldnize` entrypoint.
|
|
16
|
+
*/
|
|
17
|
+
export declare function __setDateReaderForTests(reader: DateReader): void;
|
|
18
|
+
/**
|
|
19
|
+
* @internal Restore the real metadata reader after a test override.
|
|
20
|
+
*/
|
|
21
|
+
export declare function __resetDateReaderForTests(): void;
|
|
22
|
+
export {};
|
|
23
|
+
//# sourceMappingURL=metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.d.ts","sourceRoot":"","sources":["../../src/metadata.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAE1C,KAAK,UAAU,GAAG,CAAC,QAAQ,EAAE,MAAM,KAAK,SAAS,GAAG,IAAI,CAAC;AAWzD,wBAAgB,iBAAiB,CAC/B,UAAU,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACpC,SAAS,GAAG,IAAI,CAoClB;AAgFD;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,IAAI,CAE3E;AAED;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,UAAU,GAAG,IAAI,CAEhE;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.formatDateToParts = formatDateToParts;
|
|
7
|
+
exports.getOriginalFileDateParts = getOriginalFileDateParts;
|
|
8
|
+
exports.__setDateReaderForTests = __setDateReaderForTests;
|
|
9
|
+
exports.__resetDateReaderForTests = __resetDateReaderForTests;
|
|
10
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
11
|
+
const node_child_process_1 = require("node:child_process");
|
|
12
|
+
function hasCommand(command) {
|
|
13
|
+
try {
|
|
14
|
+
(0, node_child_process_1.execFileSync)("which", [command], { stdio: "ignore" });
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
function formatDateToParts(dateString) {
|
|
22
|
+
if (!dateString)
|
|
23
|
+
return null;
|
|
24
|
+
const cleaned = String(dateString).trim();
|
|
25
|
+
// exiftool style: 2023:07:15 14:23:10
|
|
26
|
+
let match = cleaned.match(/^(\d{4}):(\d{2}):(\d{2})(?:\s+(\d{2}):(\d{2}):(\d{2}))?/);
|
|
27
|
+
if (match) {
|
|
28
|
+
return {
|
|
29
|
+
year: match[1],
|
|
30
|
+
month: match[2],
|
|
31
|
+
day: match[3],
|
|
32
|
+
hour: match[4] || "00",
|
|
33
|
+
minute: match[5] || "00",
|
|
34
|
+
second: match[6] || "00",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
// ISO style: 2023-07-15T14:23:10.000000Z
|
|
38
|
+
match = cleaned.match(/^(\d{4})-(\d{2})-(\d{2})(?:[T\s](\d{2}):(\d{2}):(\d{2}))?/);
|
|
39
|
+
if (match) {
|
|
40
|
+
return {
|
|
41
|
+
year: match[1],
|
|
42
|
+
month: match[2],
|
|
43
|
+
day: match[3],
|
|
44
|
+
hour: match[4] || "00",
|
|
45
|
+
minute: match[5] || "00",
|
|
46
|
+
second: match[6] || "00",
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
function getDateFromExiftool(filePath) {
|
|
52
|
+
try {
|
|
53
|
+
const output = (0, node_child_process_1.execFileSync)("exiftool", [
|
|
54
|
+
"-s3",
|
|
55
|
+
"-DateTimeOriginal",
|
|
56
|
+
"-CreateDate",
|
|
57
|
+
"-MediaCreateDate",
|
|
58
|
+
"-TrackCreateDate",
|
|
59
|
+
"-CreationDate",
|
|
60
|
+
filePath,
|
|
61
|
+
], { encoding: "utf8" })
|
|
62
|
+
.trim()
|
|
63
|
+
.split("\n")
|
|
64
|
+
.map((line) => line.trim())
|
|
65
|
+
.find(Boolean);
|
|
66
|
+
return formatDateToParts(output);
|
|
67
|
+
}
|
|
68
|
+
catch {
|
|
69
|
+
return null;
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
function getDateFromFfprobe(filePath) {
|
|
73
|
+
const tagNames = [
|
|
74
|
+
"creation_time",
|
|
75
|
+
"com.apple.quicktime.creationdate",
|
|
76
|
+
"date",
|
|
77
|
+
];
|
|
78
|
+
for (const tag of tagNames) {
|
|
79
|
+
try {
|
|
80
|
+
const output = (0, node_child_process_1.execFileSync)("ffprobe", [
|
|
81
|
+
"-v",
|
|
82
|
+
"error",
|
|
83
|
+
"-show_entries",
|
|
84
|
+
`format_tags=${tag}`,
|
|
85
|
+
"-of",
|
|
86
|
+
"default=noprint_wrappers=1:nokey=1",
|
|
87
|
+
filePath,
|
|
88
|
+
], { encoding: "utf8" }).trim();
|
|
89
|
+
const parts = formatDateToParts(output);
|
|
90
|
+
if (parts)
|
|
91
|
+
return parts;
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ignore and try next tag
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return null;
|
|
98
|
+
}
|
|
99
|
+
function realReader(filePath) {
|
|
100
|
+
if (hasCommand("exiftool")) {
|
|
101
|
+
const fromExiftool = getDateFromExiftool(filePath);
|
|
102
|
+
if (fromExiftool)
|
|
103
|
+
return fromExiftool;
|
|
104
|
+
}
|
|
105
|
+
if (node_path_1.default.extname(filePath).toLowerCase() === ".mp4" &&
|
|
106
|
+
hasCommand("ffprobe")) {
|
|
107
|
+
const fromFfprobe = getDateFromFfprobe(filePath);
|
|
108
|
+
if (fromFfprobe)
|
|
109
|
+
return fromFfprobe;
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
let activeReader = realReader;
|
|
114
|
+
/**
|
|
115
|
+
* Read the embedded original date from a file's metadata.
|
|
116
|
+
*
|
|
117
|
+
* Tries `exiftool` first (works for JPG/PNG/MP4/HEIC and more), then falls
|
|
118
|
+
* back to `ffprobe` for MP4 files. If neither tool is installed, or no
|
|
119
|
+
* recognisable date tag is found, returns `null`.
|
|
120
|
+
*/
|
|
121
|
+
function getOriginalFileDateParts(filePath) {
|
|
122
|
+
return activeReader(filePath);
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* @internal Replace the metadata reader. Used by the test suite to inject
|
|
126
|
+
* deterministic dates without depending on `exiftool` / `ffprobe`.
|
|
127
|
+
* Not exposed via the public `foldnize` entrypoint.
|
|
128
|
+
*/
|
|
129
|
+
function __setDateReaderForTests(reader) {
|
|
130
|
+
activeReader = reader;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* @internal Restore the real metadata reader after a test override.
|
|
134
|
+
*/
|
|
135
|
+
function __resetDateReaderForTests() {
|
|
136
|
+
activeReader = realReader;
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=metadata.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/metadata.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export declare enum Mode {
|
|
2
|
+
PREFIX = "prefix",
|
|
3
|
+
REPLACE = "replace",
|
|
4
|
+
CUSTOM = "custom"
|
|
5
|
+
}
|
|
6
|
+
export interface DateParts {
|
|
7
|
+
year: string;
|
|
8
|
+
month: string;
|
|
9
|
+
day: string;
|
|
10
|
+
hour: string | null;
|
|
11
|
+
minute: string | null;
|
|
12
|
+
second: string | null;
|
|
13
|
+
}
|
|
14
|
+
export declare const VALID_EXTENSIONS: ReadonlySet<string>;
|
|
15
|
+
export declare function sanitizeCustomName(rawName: unknown): string;
|
|
16
|
+
export declare function buildNewName(oldName: string, mode: Mode, dateParts: DateParts, customName?: string): string;
|
|
17
|
+
export declare function shouldSkipAlreadyFormatted(oldName: string, mode: Mode, customName?: string): boolean;
|
|
18
|
+
export declare function ensureUniquePath(targetPath: string): string;
|
|
19
|
+
//# sourceMappingURL=naming.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.d.ts","sourceRoot":"","sources":["../../src/naming.ts"],"names":[],"mappings":"AAGA,oBAAY,IAAI;IACd,MAAM,WAAW;IACjB,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACtB,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;CACvB;AAED,eAAO,MAAM,gBAAgB,EAAE,WAAW,CAAC,MAAM,CAO/C,CAAC;AAMH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,GAAG,MAAM,CAQ3D;AA6BD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,SAAS,EAAE,SAAS,EACpB,UAAU,CAAC,EAAE,MAAM,GAClB,MAAM,CAMR;AAqBD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,IAAI,EACV,UAAU,CAAC,EAAE,MAAM,GAClB,OAAO,CAIT;AAED,wBAAgB,gBAAgB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAY3D"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.VALID_EXTENSIONS = exports.Mode = void 0;
|
|
7
|
+
exports.sanitizeCustomName = sanitizeCustomName;
|
|
8
|
+
exports.buildNewName = buildNewName;
|
|
9
|
+
exports.shouldSkipAlreadyFormatted = shouldSkipAlreadyFormatted;
|
|
10
|
+
exports.ensureUniquePath = ensureUniquePath;
|
|
11
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
12
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
13
|
+
var Mode;
|
|
14
|
+
(function (Mode) {
|
|
15
|
+
Mode["PREFIX"] = "prefix";
|
|
16
|
+
Mode["REPLACE"] = "replace";
|
|
17
|
+
Mode["CUSTOM"] = "custom";
|
|
18
|
+
})(Mode || (exports.Mode = Mode = {}));
|
|
19
|
+
exports.VALID_EXTENSIONS = new Set([
|
|
20
|
+
".mov",
|
|
21
|
+
".mp3",
|
|
22
|
+
".mp4",
|
|
23
|
+
".jpg",
|
|
24
|
+
".jpeg",
|
|
25
|
+
".png",
|
|
26
|
+
]);
|
|
27
|
+
function escapeRegex(value) {
|
|
28
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
29
|
+
}
|
|
30
|
+
function sanitizeCustomName(rawName) {
|
|
31
|
+
if (typeof rawName !== "string")
|
|
32
|
+
return "";
|
|
33
|
+
return rawName
|
|
34
|
+
.replace(/[\\/:*?"<>|\x00-\x1f]/g, "")
|
|
35
|
+
.replace(/\s+/g, " ")
|
|
36
|
+
.trim()
|
|
37
|
+
.replace(/^[.\-\s]+|[.\-\s]+$/g, "");
|
|
38
|
+
}
|
|
39
|
+
function buildPrefixName(oldName, dateParts) {
|
|
40
|
+
const date = `${dateParts.year}${dateParts.month}${dateParts.day}`;
|
|
41
|
+
return `${date}-${oldName}`;
|
|
42
|
+
}
|
|
43
|
+
function buildReplaceName(oldName, dateParts) {
|
|
44
|
+
const ext = node_path_1.default.extname(oldName);
|
|
45
|
+
const timestamp = `${dateParts.year}${dateParts.month}${dateParts.day}` +
|
|
46
|
+
`-${dateParts.hour}${dateParts.minute}${dateParts.second}`;
|
|
47
|
+
return `${timestamp}${ext}`;
|
|
48
|
+
}
|
|
49
|
+
function buildCustomName(oldName, dateParts, customName) {
|
|
50
|
+
const ext = node_path_1.default.extname(oldName);
|
|
51
|
+
const timestamp = `${dateParts.year}${dateParts.month}${dateParts.day}` +
|
|
52
|
+
`-${dateParts.hour}${dateParts.minute}${dateParts.second}`;
|
|
53
|
+
return `${customName}-${timestamp}${ext}`;
|
|
54
|
+
}
|
|
55
|
+
function buildNewName(oldName, mode, dateParts, customName) {
|
|
56
|
+
if (mode === Mode.REPLACE)
|
|
57
|
+
return buildReplaceName(oldName, dateParts);
|
|
58
|
+
if (mode === Mode.CUSTOM) {
|
|
59
|
+
return buildCustomName(oldName, dateParts, customName ?? "");
|
|
60
|
+
}
|
|
61
|
+
return buildPrefixName(oldName, dateParts);
|
|
62
|
+
}
|
|
63
|
+
function isAlreadyPrefixed(fileName) {
|
|
64
|
+
const parsed = node_path_1.default.parse(fileName);
|
|
65
|
+
return /^\d{8}-.+$/i.test(parsed.name);
|
|
66
|
+
}
|
|
67
|
+
function isAlreadyReplaced(fileName) {
|
|
68
|
+
const parsed = node_path_1.default.parse(fileName);
|
|
69
|
+
return /^\d{8}-\d{6}(?:-\d+)?$/i.test(parsed.name);
|
|
70
|
+
}
|
|
71
|
+
function isAlreadyCustom(fileName, customName) {
|
|
72
|
+
const parsed = node_path_1.default.parse(fileName);
|
|
73
|
+
const pattern = new RegExp(`^${escapeRegex(customName)}-\\d{8}-\\d{6}(?:-\\d+)?$`, "i");
|
|
74
|
+
return pattern.test(parsed.name);
|
|
75
|
+
}
|
|
76
|
+
function shouldSkipAlreadyFormatted(oldName, mode, customName) {
|
|
77
|
+
if (mode === Mode.REPLACE)
|
|
78
|
+
return isAlreadyReplaced(oldName);
|
|
79
|
+
if (mode === Mode.CUSTOM)
|
|
80
|
+
return isAlreadyCustom(oldName, customName ?? "");
|
|
81
|
+
return isAlreadyPrefixed(oldName);
|
|
82
|
+
}
|
|
83
|
+
function ensureUniquePath(targetPath) {
|
|
84
|
+
if (!node_fs_1.default.existsSync(targetPath))
|
|
85
|
+
return targetPath;
|
|
86
|
+
const dir = node_path_1.default.dirname(targetPath);
|
|
87
|
+
const parsed = node_path_1.default.parse(targetPath);
|
|
88
|
+
let counter = 1;
|
|
89
|
+
while (true) {
|
|
90
|
+
const candidate = node_path_1.default.join(dir, `${parsed.name}-${counter}${parsed.ext}`);
|
|
91
|
+
if (!node_fs_1.default.existsSync(candidate))
|
|
92
|
+
return candidate;
|
|
93
|
+
counter += 1;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
//# sourceMappingURL=naming.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"naming.js","sourceRoot":"","sources":["../../src/naming.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Mode } from "./naming";
|
|
2
|
+
export declare enum LogLevel {
|
|
3
|
+
INFO = "info",
|
|
4
|
+
RENAMED = "renamed",
|
|
5
|
+
MOVED = "moved",
|
|
6
|
+
DRY = "dry",
|
|
7
|
+
SKIP = "skip",
|
|
8
|
+
ERROR = "error",
|
|
9
|
+
DONE = "done"
|
|
10
|
+
}
|
|
11
|
+
export interface LogEntry {
|
|
12
|
+
level: LogLevel;
|
|
13
|
+
message: string;
|
|
14
|
+
}
|
|
15
|
+
export type LogFn = (entry: LogEntry) => void;
|
|
16
|
+
export interface OrganizeOptions {
|
|
17
|
+
/** Absolute path to the folder to scan. */
|
|
18
|
+
root: string;
|
|
19
|
+
/** Renaming strategy. Defaults to `"prefix"`. */
|
|
20
|
+
mode?: Mode;
|
|
21
|
+
/** Preview without touching files. Defaults to `false`. */
|
|
22
|
+
dryRun?: boolean;
|
|
23
|
+
/** Required when `mode === "custom"`. */
|
|
24
|
+
customName?: string;
|
|
25
|
+
/**
|
|
26
|
+
* When `true`, each file is moved into `<root>/YYYY/MM/` based on its date.
|
|
27
|
+
* Existing folders are reused; missing ones are created. Defaults to `false`.
|
|
28
|
+
*/
|
|
29
|
+
organizeIntoYearMonth?: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* When `false`, only files directly inside `root` are processed.
|
|
32
|
+
* Defaults to `true`.
|
|
33
|
+
*/
|
|
34
|
+
scanSubfolders?: boolean;
|
|
35
|
+
/** Streamed log callback. */
|
|
36
|
+
onLog?: LogFn;
|
|
37
|
+
}
|
|
38
|
+
export interface OrganizeSummary {
|
|
39
|
+
found: number;
|
|
40
|
+
renamed: number;
|
|
41
|
+
moved: number;
|
|
42
|
+
skipped: number;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Organize a folder by renaming media files (and optionally moving them
|
|
46
|
+
* into Year/Month subfolders).
|
|
47
|
+
*/
|
|
48
|
+
export declare function organizeFolder({ root, mode, dryRun, customName, organizeIntoYearMonth, scanSubfolders, onLog, }: OrganizeOptions): OrganizeSummary;
|
|
49
|
+
//# sourceMappingURL=organize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organize.d.ts","sourceRoot":"","sources":["../../src/organize.ts"],"names":[],"mappings":"AAIA,OAAO,EAKL,IAAI,EACL,MAAM,UAAU,CAAC;AAElB,oBAAY,QAAQ;IAClB,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,KAAK,UAAU;IACf,GAAG,QAAQ;IACX,IAAI,SAAS;IACb,KAAK,UAAU;IACf,IAAI,SAAS;CACd;AAED,MAAM,WAAW,QAAQ;IACvB,KAAK,EAAE,QAAQ,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,KAAK,GAAG,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,CAAC;AAE9C,MAAM,WAAW,eAAe;IAC9B,2CAA2C;IAC3C,IAAI,EAAE,MAAM,CAAC;IACb,iDAAiD;IACjD,IAAI,CAAC,EAAE,IAAI,CAAC;IACZ,2DAA2D;IAC3D,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;OAGG;IACH,qBAAqB,CAAC,EAAE,OAAO,CAAC;IAChC;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6BAA6B;IAC7B,KAAK,CAAC,EAAE,KAAK,CAAC;CACf;AAED,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;CACjB;AAyFD;;;GAGG;AACH,wBAAgB,cAAc,CAAC,EAC7B,IAAI,EACJ,IAAkB,EAClB,MAAc,EACd,UAAU,EACV,qBAA6B,EAC7B,cAAqB,EACrB,KAAK,GACN,EAAE,eAAe,GAAG,eAAe,CA+DnC"}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.LogLevel = void 0;
|
|
7
|
+
exports.organizeFolder = organizeFolder;
|
|
8
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
9
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
10
|
+
const walk_1 = require("./walk");
|
|
11
|
+
const metadata_1 = require("./metadata");
|
|
12
|
+
const naming_1 = require("./naming");
|
|
13
|
+
var LogLevel;
|
|
14
|
+
(function (LogLevel) {
|
|
15
|
+
LogLevel["INFO"] = "info";
|
|
16
|
+
LogLevel["RENAMED"] = "renamed";
|
|
17
|
+
LogLevel["MOVED"] = "moved";
|
|
18
|
+
LogLevel["DRY"] = "dry";
|
|
19
|
+
LogLevel["SKIP"] = "skip";
|
|
20
|
+
LogLevel["ERROR"] = "error";
|
|
21
|
+
LogLevel["DONE"] = "done";
|
|
22
|
+
})(LogLevel || (exports.LogLevel = LogLevel = {}));
|
|
23
|
+
function processFile({ filePath, root, mode, dryRun, customName, organizeIntoYearMonth, onLog, }) {
|
|
24
|
+
const oldName = node_path_1.default.basename(filePath);
|
|
25
|
+
const log = (level, message) => {
|
|
26
|
+
onLog?.({ level, message });
|
|
27
|
+
};
|
|
28
|
+
// Always read metadata first — needed both for naming AND for the
|
|
29
|
+
// target directory when sorting into year/month is on.
|
|
30
|
+
const dateParts = (0, metadata_1.getOriginalFileDateParts)(filePath);
|
|
31
|
+
if (!dateParts) {
|
|
32
|
+
log(LogLevel.SKIP, `Skipping (no embedded original date): ${oldName}`);
|
|
33
|
+
return { renamed: false, moved: false, skipped: true };
|
|
34
|
+
}
|
|
35
|
+
const alreadyFormatted = (0, naming_1.shouldSkipAlreadyFormatted)(oldName, mode, customName);
|
|
36
|
+
const desiredName = alreadyFormatted
|
|
37
|
+
? oldName
|
|
38
|
+
: (0, naming_1.buildNewName)(oldName, mode, dateParts, customName);
|
|
39
|
+
const currentDir = node_path_1.default.dirname(filePath);
|
|
40
|
+
const targetDir = organizeIntoYearMonth
|
|
41
|
+
? node_path_1.default.join(root, dateParts.year, dateParts.month)
|
|
42
|
+
: currentDir;
|
|
43
|
+
if (desiredName === oldName && targetDir === currentDir) {
|
|
44
|
+
log(LogLevel.SKIP, `Skipping (already organized): ${oldName}`);
|
|
45
|
+
return { renamed: false, moved: false, skipped: true };
|
|
46
|
+
}
|
|
47
|
+
const finalPath = (0, naming_1.ensureUniquePath)(node_path_1.default.join(targetDir, desiredName));
|
|
48
|
+
const finalName = node_path_1.default.basename(finalPath);
|
|
49
|
+
const willMove = node_path_1.default.dirname(finalPath) !== currentDir;
|
|
50
|
+
const willRename = finalName !== oldName;
|
|
51
|
+
const relTarget = node_path_1.default.relative(root, finalPath);
|
|
52
|
+
if (dryRun) {
|
|
53
|
+
const verb = willMove && willRename
|
|
54
|
+
? "[DRY] Move + rename"
|
|
55
|
+
: willMove
|
|
56
|
+
? "[DRY] Move"
|
|
57
|
+
: "[DRY] Rename";
|
|
58
|
+
log(LogLevel.DRY, `${verb}: ${oldName} → ${relTarget}`);
|
|
59
|
+
return { renamed: willRename, moved: willMove, skipped: false };
|
|
60
|
+
}
|
|
61
|
+
if (willMove) {
|
|
62
|
+
node_fs_1.default.mkdirSync(node_path_1.default.dirname(finalPath), { recursive: true });
|
|
63
|
+
}
|
|
64
|
+
node_fs_1.default.renameSync(filePath, finalPath);
|
|
65
|
+
const verb = willMove && willRename ? "Moved + renamed" : willMove ? "Moved" : "Renamed";
|
|
66
|
+
const level = willMove ? LogLevel.MOVED : LogLevel.RENAMED;
|
|
67
|
+
log(level, `${verb}: ${oldName} → ${relTarget}`);
|
|
68
|
+
return { renamed: willRename, moved: willMove, skipped: false };
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Organize a folder by renaming media files (and optionally moving them
|
|
72
|
+
* into Year/Month subfolders).
|
|
73
|
+
*/
|
|
74
|
+
function organizeFolder({ root, mode = naming_1.Mode.PREFIX, dryRun = false, customName, organizeIntoYearMonth = false, scanSubfolders = true, onLog, }) {
|
|
75
|
+
if (!root) {
|
|
76
|
+
throw new Error("A target folder is required.");
|
|
77
|
+
}
|
|
78
|
+
if (!node_fs_1.default.existsSync(root) || !node_fs_1.default.statSync(root).isDirectory()) {
|
|
79
|
+
throw new Error(`Invalid folder: ${root}`);
|
|
80
|
+
}
|
|
81
|
+
let safeCustomName = "";
|
|
82
|
+
if (mode === naming_1.Mode.CUSTOM) {
|
|
83
|
+
safeCustomName = (0, naming_1.sanitizeCustomName)(customName);
|
|
84
|
+
if (!safeCustomName) {
|
|
85
|
+
throw new Error("Custom mode requires a non-empty name (letters, numbers, spaces, dashes, underscores).");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const log = (level, message) => {
|
|
89
|
+
onLog?.({ level, message });
|
|
90
|
+
};
|
|
91
|
+
log(LogLevel.INFO, `Mode: ${mode}`);
|
|
92
|
+
if (mode === naming_1.Mode.CUSTOM) {
|
|
93
|
+
log(LogLevel.INFO, `Custom name: ${safeCustomName}`);
|
|
94
|
+
}
|
|
95
|
+
log(LogLevel.INFO, `Root: ${root}`);
|
|
96
|
+
log(LogLevel.INFO, `Sort into Year/Month folders: ${organizeIntoYearMonth ? "yes" : "no"}`);
|
|
97
|
+
log(LogLevel.INFO, `Scan subfolders: ${scanSubfolders ? "yes" : "no"}`);
|
|
98
|
+
log(LogLevel.INFO, `Dry run: ${dryRun ? "yes" : "no"}`);
|
|
99
|
+
const files = (0, walk_1.walk)(root, scanSubfolders);
|
|
100
|
+
log(LogLevel.INFO, `Found ${files.length} supported file(s).`);
|
|
101
|
+
let renamed = 0;
|
|
102
|
+
let moved = 0;
|
|
103
|
+
let skipped = 0;
|
|
104
|
+
for (const filePath of files) {
|
|
105
|
+
const result = processFile({
|
|
106
|
+
filePath,
|
|
107
|
+
root,
|
|
108
|
+
mode,
|
|
109
|
+
dryRun,
|
|
110
|
+
customName: safeCustomName,
|
|
111
|
+
organizeIntoYearMonth,
|
|
112
|
+
onLog,
|
|
113
|
+
});
|
|
114
|
+
if (result.renamed)
|
|
115
|
+
renamed += 1;
|
|
116
|
+
if (result.moved)
|
|
117
|
+
moved += 1;
|
|
118
|
+
if (result.skipped)
|
|
119
|
+
skipped += 1;
|
|
120
|
+
}
|
|
121
|
+
log(LogLevel.DONE, `Done. Renamed: ${renamed} · Moved: ${moved} · Skipped: ${skipped}`);
|
|
122
|
+
return { found: files.length, renamed, moved, skipped };
|
|
123
|
+
}
|
|
124
|
+
//# sourceMappingURL=organize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"organize.js","sourceRoot":"","sources":["../../src/organize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recursively list all supported media files inside `dir`.
|
|
3
|
+
* When `scanSubfolders` is `false`, only files directly inside `dir` are
|
|
4
|
+
* returned (no recursion into any subfolder).
|
|
5
|
+
*/
|
|
6
|
+
export declare function walk(dir: string, scanSubfolders: boolean): string[];
|
|
7
|
+
//# sourceMappingURL=walk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.d.ts","sourceRoot":"","sources":["../../src/walk.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,MAAM,EAAE,CAuBnE"}
|
package/dist/src/walk.js
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.walk = walk;
|
|
7
|
+
const node_fs_1 = __importDefault(require("node:fs"));
|
|
8
|
+
const node_path_1 = __importDefault(require("node:path"));
|
|
9
|
+
const naming_1 = require("./naming");
|
|
10
|
+
/**
|
|
11
|
+
* Recursively list all supported media files inside `dir`.
|
|
12
|
+
* When `scanSubfolders` is `false`, only files directly inside `dir` are
|
|
13
|
+
* returned (no recursion into any subfolder).
|
|
14
|
+
*/
|
|
15
|
+
function walk(dir, scanSubfolders) {
|
|
16
|
+
const entries = node_fs_1.default.readdirSync(dir, { withFileTypes: true });
|
|
17
|
+
let files = [];
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const fullPath = node_path_1.default.join(dir, entry.name);
|
|
20
|
+
if (entry.isDirectory()) {
|
|
21
|
+
if (!scanSubfolders)
|
|
22
|
+
continue;
|
|
23
|
+
files = files.concat(walk(fullPath, scanSubfolders));
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
if (!entry.isFile())
|
|
27
|
+
continue;
|
|
28
|
+
if (entry.name.startsWith("._"))
|
|
29
|
+
continue;
|
|
30
|
+
const ext = node_path_1.default.extname(entry.name).toLowerCase();
|
|
31
|
+
if (naming_1.VALID_EXTENSIONS.has(ext)) {
|
|
32
|
+
files.push(fullPath);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return files;
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=walk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"walk.js","sourceRoot":"","sources":["../../src/walk.ts"],"names":[],"mappings":";;;;;AASA,oBAuBC;AAhCD,sDAAyB;AACzB,0DAA6B;AAC7B,qCAA4C;AAE5C;;;;GAIG;AACH,SAAgB,IAAI,CAAC,GAAW,EAAE,cAAuB;IACvD,MAAM,OAAO,GAAG,iBAAE,CAAC,WAAW,CAAC,GAAG,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC7D,IAAI,KAAK,GAAa,EAAE,CAAC;IAEzB,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,mBAAI,CAAC,IAAI,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAE5C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc;gBAAE,SAAS;YAC9B,KAAK,GAAG,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC;YACrD,SAAS;QACX,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE;YAAE,SAAS;QAC9B,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;YAAE,SAAS;QAE1C,MAAM,GAAG,GAAG,mBAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,WAAW,EAAE,CAAC;QACnD,IAAI,yBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;YAC9B,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"fileNames":["../node_modules/typescript/lib/lib.es5.d.ts","../node_modules/typescript/lib/lib.es2015.d.ts","../node_modules/typescript/lib/lib.es2016.d.ts","../node_modules/typescript/lib/lib.es2017.d.ts","../node_modules/typescript/lib/lib.es2018.d.ts","../node_modules/typescript/lib/lib.es2019.d.ts","../node_modules/typescript/lib/lib.es2020.d.ts","../node_modules/typescript/lib/lib.es2021.d.ts","../node_modules/typescript/lib/lib.es2022.d.ts","../node_modules/typescript/lib/lib.es2015.core.d.ts","../node_modules/typescript/lib/lib.es2015.collection.d.ts","../node_modules/typescript/lib/lib.es2015.generator.d.ts","../node_modules/typescript/lib/lib.es2015.iterable.d.ts","../node_modules/typescript/lib/lib.es2015.promise.d.ts","../node_modules/typescript/lib/lib.es2015.proxy.d.ts","../node_modules/typescript/lib/lib.es2015.reflect.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.d.ts","../node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2016.array.include.d.ts","../node_modules/typescript/lib/lib.es2016.intl.d.ts","../node_modules/typescript/lib/lib.es2017.arraybuffer.d.ts","../node_modules/typescript/lib/lib.es2017.date.d.ts","../node_modules/typescript/lib/lib.es2017.object.d.ts","../node_modules/typescript/lib/lib.es2017.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2017.string.d.ts","../node_modules/typescript/lib/lib.es2017.intl.d.ts","../node_modules/typescript/lib/lib.es2017.typedarrays.d.ts","../node_modules/typescript/lib/lib.es2018.asyncgenerator.d.ts","../node_modules/typescript/lib/lib.es2018.asynciterable.d.ts","../node_modules/typescript/lib/lib.es2018.intl.d.ts","../node_modules/typescript/lib/lib.es2018.promise.d.ts","../node_modules/typescript/lib/lib.es2018.regexp.d.ts","../node_modules/typescript/lib/lib.es2019.array.d.ts","../node_modules/typescript/lib/lib.es2019.object.d.ts","../node_modules/typescript/lib/lib.es2019.string.d.ts","../node_modules/typescript/lib/lib.es2019.symbol.d.ts","../node_modules/typescript/lib/lib.es2019.intl.d.ts","../node_modules/typescript/lib/lib.es2020.bigint.d.ts","../node_modules/typescript/lib/lib.es2020.date.d.ts","../node_modules/typescript/lib/lib.es2020.promise.d.ts","../node_modules/typescript/lib/lib.es2020.sharedmemory.d.ts","../node_modules/typescript/lib/lib.es2020.string.d.ts","../node_modules/typescript/lib/lib.es2020.symbol.wellknown.d.ts","../node_modules/typescript/lib/lib.es2020.intl.d.ts","../node_modules/typescript/lib/lib.es2020.number.d.ts","../node_modules/typescript/lib/lib.es2021.promise.d.ts","../node_modules/typescript/lib/lib.es2021.string.d.ts","../node_modules/typescript/lib/lib.es2021.weakref.d.ts","../node_modules/typescript/lib/lib.es2021.intl.d.ts","../node_modules/typescript/lib/lib.es2022.array.d.ts","../node_modules/typescript/lib/lib.es2022.error.d.ts","../node_modules/typescript/lib/lib.es2022.intl.d.ts","../node_modules/typescript/lib/lib.es2022.object.d.ts","../node_modules/typescript/lib/lib.es2022.string.d.ts","../node_modules/typescript/lib/lib.es2022.regexp.d.ts","../node_modules/typescript/lib/lib.es2025.float16.d.ts","../node_modules/typescript/lib/lib.esnext.disposable.d.ts","../node_modules/typescript/lib/lib.decorators.d.ts","../node_modules/typescript/lib/lib.decorators.legacy.d.ts","../src/naming.ts","../src/walk.ts","../src/metadata.ts","../src/organize.ts","../src/index.ts","../bin/foldnize.ts","../node_modules/@types/node/compatibility/iterators.d.ts","../node_modules/@types/node/globals.typedarray.d.ts","../node_modules/@types/node/buffer.buffer.d.ts","../node_modules/@types/node/globals.d.ts","../node_modules/@types/node/web-globals/abortcontroller.d.ts","../node_modules/@types/node/web-globals/blob.d.ts","../node_modules/@types/node/web-globals/console.d.ts","../node_modules/@types/node/web-globals/crypto.d.ts","../node_modules/@types/node/web-globals/domexception.d.ts","../node_modules/@types/node/web-globals/encoding.d.ts","../node_modules/@types/node/web-globals/events.d.ts","../node_modules/undici-types/utility.d.ts","../node_modules/undici-types/header.d.ts","../node_modules/undici-types/readable.d.ts","../node_modules/undici-types/fetch.d.ts","../node_modules/undici-types/formdata.d.ts","../node_modules/undici-types/connector.d.ts","../node_modules/undici-types/client-stats.d.ts","../node_modules/undici-types/client.d.ts","../node_modules/undici-types/errors.d.ts","../node_modules/undici-types/dispatcher.d.ts","../node_modules/undici-types/global-dispatcher.d.ts","../node_modules/undici-types/global-origin.d.ts","../node_modules/undici-types/pool-stats.d.ts","../node_modules/undici-types/pool.d.ts","../node_modules/undici-types/handlers.d.ts","../node_modules/undici-types/balanced-pool.d.ts","../node_modules/undici-types/round-robin-pool.d.ts","../node_modules/undici-types/h2c-client.d.ts","../node_modules/undici-types/agent.d.ts","../node_modules/undici-types/mock-interceptor.d.ts","../node_modules/undici-types/mock-call-history.d.ts","../node_modules/undici-types/mock-agent.d.ts","../node_modules/undici-types/mock-client.d.ts","../node_modules/undici-types/mock-pool.d.ts","../node_modules/undici-types/snapshot-agent.d.ts","../node_modules/undici-types/mock-errors.d.ts","../node_modules/undici-types/proxy-agent.d.ts","../node_modules/undici-types/socks5-proxy-agent.d.ts","../node_modules/undici-types/env-http-proxy-agent.d.ts","../node_modules/undici-types/retry-handler.d.ts","../node_modules/undici-types/retry-agent.d.ts","../node_modules/undici-types/api.d.ts","../node_modules/undici-types/cache-interceptor.d.ts","../node_modules/undici-types/interceptors.d.ts","../node_modules/undici-types/util.d.ts","../node_modules/undici-types/cookies.d.ts","../node_modules/undici-types/patch.d.ts","../node_modules/undici-types/websocket.d.ts","../node_modules/undici-types/eventsource.d.ts","../node_modules/undici-types/diagnostics-channel.d.ts","../node_modules/undici-types/content-type.d.ts","../node_modules/undici-types/cache.d.ts","../node_modules/undici-types/index.d.ts","../node_modules/@types/node/web-globals/fetch.d.ts","../node_modules/@types/node/web-globals/importmeta.d.ts","../node_modules/@types/node/web-globals/messaging.d.ts","../node_modules/@types/node/web-globals/navigator.d.ts","../node_modules/@types/node/web-globals/performance.d.ts","../node_modules/@types/node/web-globals/storage.d.ts","../node_modules/@types/node/web-globals/streams.d.ts","../node_modules/@types/node/web-globals/timers.d.ts","../node_modules/@types/node/web-globals/url.d.ts","../node_modules/@types/node/assert.d.ts","../node_modules/@types/node/assert/strict.d.ts","../node_modules/@types/node/async_hooks.d.ts","../node_modules/@types/node/buffer.d.ts","../node_modules/@types/node/child_process.d.ts","../node_modules/@types/node/cluster.d.ts","../node_modules/@types/node/console.d.ts","../node_modules/@types/node/constants.d.ts","../node_modules/@types/node/crypto.d.ts","../node_modules/@types/node/dgram.d.ts","../node_modules/@types/node/diagnostics_channel.d.ts","../node_modules/@types/node/dns.d.ts","../node_modules/@types/node/dns/promises.d.ts","../node_modules/@types/node/domain.d.ts","../node_modules/@types/node/events.d.ts","../node_modules/@types/node/fs.d.ts","../node_modules/@types/node/fs/promises.d.ts","../node_modules/@types/node/http.d.ts","../node_modules/@types/node/http2.d.ts","../node_modules/@types/node/https.d.ts","../node_modules/@types/node/inspector.d.ts","../node_modules/@types/node/inspector.generated.d.ts","../node_modules/@types/node/inspector/promises.d.ts","../node_modules/@types/node/module.d.ts","../node_modules/@types/node/net.d.ts","../node_modules/@types/node/os.d.ts","../node_modules/@types/node/path.d.ts","../node_modules/@types/node/path/posix.d.ts","../node_modules/@types/node/path/win32.d.ts","../node_modules/@types/node/perf_hooks.d.ts","../node_modules/@types/node/process.d.ts","../node_modules/@types/node/punycode.d.ts","../node_modules/@types/node/querystring.d.ts","../node_modules/@types/node/quic.d.ts","../node_modules/@types/node/readline.d.ts","../node_modules/@types/node/readline/promises.d.ts","../node_modules/@types/node/repl.d.ts","../node_modules/@types/node/sea.d.ts","../node_modules/@types/node/sqlite.d.ts","../node_modules/@types/node/stream.d.ts","../node_modules/@types/node/stream/consumers.d.ts","../node_modules/@types/node/stream/iter.d.ts","../node_modules/@types/node/stream/promises.d.ts","../node_modules/@types/node/stream/web.d.ts","../node_modules/@types/node/string_decoder.d.ts","../node_modules/@types/node/test.d.ts","../node_modules/@types/node/test/reporters.d.ts","../node_modules/@types/node/timers.d.ts","../node_modules/@types/node/timers/promises.d.ts","../node_modules/@types/node/tls.d.ts","../node_modules/@types/node/trace_events.d.ts","../node_modules/@types/node/tty.d.ts","../node_modules/@types/node/url.d.ts","../node_modules/@types/node/util.d.ts","../node_modules/@types/node/util/types.d.ts","../node_modules/@types/node/v8.d.ts","../node_modules/@types/node/vm.d.ts","../node_modules/@types/node/wasi.d.ts","../node_modules/@types/node/worker_threads.d.ts","../node_modules/@types/node/zlib.d.ts","../node_modules/@types/node/zlib/iter.d.ts","../node_modules/@types/node/index.d.ts"],"fileIdsList":[[64,68,132,140,144,147,149,150,151,155,163],[68,129,130,132,140,144,147,149,150,151,163],[68,131,132,140,144,147,149,150,151,163],[132,140,144,147,149,150,151,163],[68,132,140,144,147,149,150,151,163,172],[68,132,133,138,140,143,144,147,149,150,151,153,163,168,181],[68,132,133,134,140,143,144,147,149,150,151,163],[68,132,140,144,147,149,150,151,163],[68,132,135,140,144,147,149,150,151,163,182],[68,132,136,137,140,144,147,149,150,151,154,163],[68,132,137,140,144,147,149,150,151,163,168,178],[68,132,138,140,143,144,147,149,150,151,153,163],[68,131,132,139,140,144,147,149,150,151,163],[68,132,140,141,144,147,149,150,151,163],[68,132,140,142,143,144,147,149,150,151,163],[68,131,132,140,143,144,147,149,150,151,163],[68,132,140,143,144,145,147,149,150,151,163,168,181],[68,132,140,143,144,145,147,149,150,151,163,168,170,172],[68,119,132,140,143,144,146,147,149,150,151,153,163,168,181],[68,132,140,143,144,146,147,149,150,151,153,163,168,178,181],[68,132,140,144,146,147,148,149,150,151,163,168,178,181],[66,67,68,69,70,71,72,73,74,75,76,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189],[68,132,140,143,144,147,149,150,151,163],[68,132,140,144,147,149,151,163],[68,132,140,144,147,149,150,151,152,163,181],[68,132,140,143,144,147,149,150,151,153,163,168],[68,132,140,144,147,149,150,151,154,163],[68,132,140,144,147,149,150,151,155,163],[68,132,140,143,144,147,149,150,151,158,163],[68,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188],[68,132,140,144,147,149,150,151,160,163],[68,132,140,144,147,149,150,151,161,163],[68,132,137,140,144,147,149,150,151,153,163,172],[68,132,140,143,144,147,149,150,151,163,164],[68,132,140,144,147,149,150,151,163,165,182,185],[68,132,140,143,144,147,149,150,151,163,168,171,172],[68,132,140,144,147,149,150,151,163,169,172],[68,132,140,144,147,149,150,151,163,170],[68,132,140,144,147,149,150,151,163,172,182],[68,132,140,144,147,149,150,151,163,173],[68,129,132,140,144,147,149,150,151,163,168,175,181],[68,132,140,144,147,149,150,151,163,168,174],[68,132,140,143,144,147,149,150,151,163,176,177],[68,132,140,144,147,149,150,151,163,176,177],[68,132,137,140,144,147,149,150,151,153,163,168,178],[68,132,140,144,147,149,150,151,163,179],[68,132,140,144,147,149,150,151,153,163,180],[68,132,140,144,146,147,149,150,151,161,163,181],[68,132,140,144,147,149,150,151,163,182,183],[68,132,137,140,144,147,149,150,151,163,183],[68,132,140,144,147,149,150,151,163,168,184],[68,132,140,144,147,149,150,151,152,163,185],[68,132,140,144,147,149,150,151,163,186],[68,132,135,140,144,147,149,150,151,163],[68,132,137,140,144,147,149,150,151,163],[68,132,140,144,147,149,150,151,163,182],[68,119,132,140,144,147,149,150,151,163],[68,132,140,144,147,149,150,151,163,181],[68,132,140,144,147,149,150,151,163,187],[68,132,140,144,147,149,150,151,158,163],[68,132,140,144,147,149,150,151,163,177],[68,119,132,140,143,144,145,147,149,150,151,158,163,168,172,181,184,185,187],[68,132,140,144,147,149,150,151,163,168,188],[68,132,140,144,147,149,150,151,163,170,189],[68,83,86,89,90,132,140,144,147,149,150,151,163,181],[68,86,132,140,144,147,149,150,151,163,168,181],[68,86,90,132,140,144,147,149,150,151,163,181],[68,132,140,144,147,149,150,151,163,168],[68,80,132,140,144,147,149,150,151,163],[68,84,132,140,144,147,149,150,151,163],[68,82,83,86,132,140,144,147,149,150,151,163,181],[68,132,140,144,147,149,150,151,153,163,178],[68,132,140,144,147,149,150,151,163,190],[68,80,132,140,144,147,149,150,151,163,190],[68,82,86,132,140,144,147,149,150,151,153,163,181],[68,77,78,79,81,85,132,140,143,144,147,149,150,151,163,168,181],[68,86,95,103,132,140,144,147,149,150,151,163],[68,78,84,132,140,144,147,149,150,151,163],[68,86,113,114,132,140,144,147,149,150,151,163],[68,78,81,86,132,140,144,147,149,150,151,163,172,181,190],[68,86,132,140,144,147,149,150,151,163],[68,82,86,132,140,144,147,149,150,151,163,181],[68,77,132,140,144,147,149,150,151,163],[68,80,81,82,84,85,86,87,88,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,114,115,116,117,118,132,140,144,147,149,150,151,163],[68,86,106,109,132,140,144,147,149,150,151,163],[68,86,95,96,97,132,140,144,147,149,150,151,163],[68,84,86,96,98,132,140,144,147,149,150,151,163],[68,85,132,140,144,147,149,150,151,163],[68,78,80,86,132,140,144,147,149,150,151,163],[68,86,90,96,98,132,140,144,147,149,150,151,163],[68,90,132,140,144,147,149,150,151,163],[68,84,86,89,132,140,144,147,149,150,151,163,181],[68,78,82,86,95,132,140,144,147,149,150,151,163],[68,86,106,132,140,144,147,149,150,151,163],[68,98,132,140,144,147,149,150,151,163],[68,78,82,86,90,132,140,144,147,149,150,151,163],[68,80,86,113,132,140,144,147,149,150,151,163,172,187,190],[60,62,63,68,132,140,144,147,149,150,151,163],[60,68,132,133,140,144,147,149,150,151,155,163],[60,61,62,68,132,140,144,147,149,150,151,155,163],[60,68,132,140,144,147,149,150,151,155,163]],"fileInfos":[{"version":"bcd24271a113971ba9eb71ff8cb01bc6b0f872a85c23fdbe5d93065b375933cd","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f88bedbeb09c6f5a6645cb24c7c55f1aa22d19ae96c8e6959cbd8b85a707bc6","impliedFormat":1},{"version":"7fe93b39b810eadd916be8db880dd7f0f7012a5cc6ffb62de8f62a2117fa6f1f","impliedFormat":1},{"version":"bb0074cc08b84a2374af33d8bf044b80851ccc9e719a5e202eacf40db2c31600","impliedFormat":1},{"version":"1a7daebe4f45fb03d9ec53d60008fbf9ac45a697fdc89e4ce218bc94b94f94d6","impliedFormat":1},{"version":"f94b133a3cb14a288803be545ac2683e0d0ff6661bcd37e31aaaec54fc382aed","impliedFormat":1},{"version":"f59d0650799f8782fd74cf73c19223730c6d1b9198671b1c5b3a38e1188b5953","impliedFormat":1},{"version":"8a15b4607d9a499e2dbeed9ec0d3c0d7372c850b2d5f1fb259e8f6d41d468a84","impliedFormat":1},{"version":"26e0fe14baee4e127f4365d1ae0b276f400562e45e19e35fd2d4c296684715e6","impliedFormat":1},{"version":"eadcffda2aa84802c73938e589b9e58248d74c59cb7fcbca6474e3435ac15504","affectsGlobalScope":true,"impliedFormat":1},{"version":"105ba8ff7ba746404fe1a2e189d1d3d2e0eb29a08c18dded791af02f29fb4711","affectsGlobalScope":true,"impliedFormat":1},{"version":"00343ca5b2e3d48fa5df1db6e32ea2a59afab09590274a6cccb1dbae82e60c7c","affectsGlobalScope":true,"impliedFormat":1},{"version":"ebd9f816d4002697cb2864bea1f0b70a103124e18a8cd9645eeccc09bdf80ab4","affectsGlobalScope":true,"impliedFormat":1},{"version":"2c1afac30a01772cd2a9a298a7ce7706b5892e447bb46bdbeef720f7b5da77ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"7b0225f483e4fa685625ebe43dd584bb7973bbd84e66a6ba7bbe175ee1048b4f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c0a4b8ac6ce74679c1da2b3795296f5896e31c38e888469a8e0f99dc3305de60","affectsGlobalScope":true,"impliedFormat":1},{"version":"3084a7b5f569088e0146533a00830e206565de65cae2239509168b11434cd84f","affectsGlobalScope":true,"impliedFormat":1},{"version":"c5079c53f0f141a0698faa903e76cb41cd664e3efb01cc17a5c46ec2eb0bef42","affectsGlobalScope":true,"impliedFormat":1},{"version":"32cafbc484dea6b0ab62cf8473182bbcb23020d70845b406f80b7526f38ae862","affectsGlobalScope":true,"impliedFormat":1},{"version":"fca4cdcb6d6c5ef18a869003d02c9f0fd95df8cfaf6eb431cd3376bc034cad36","affectsGlobalScope":true,"impliedFormat":1},{"version":"b93ec88115de9a9dc1b602291b85baf825c85666bf25985cc5f698073892b467","affectsGlobalScope":true,"impliedFormat":1},{"version":"f5c06dcc3fe849fcb297c247865a161f995cc29de7aa823afdd75aaaddc1419b","affectsGlobalScope":true,"impliedFormat":1},{"version":"b77e16112127a4b169ef0b8c3a4d730edf459c5f25fe52d5e436a6919206c4d7","affectsGlobalScope":true,"impliedFormat":1},{"version":"fbffd9337146eff822c7c00acbb78b01ea7ea23987f6c961eba689349e744f8c","affectsGlobalScope":true,"impliedFormat":1},{"version":"a995c0e49b721312f74fdfb89e4ba29bd9824c770bbb4021d74d2bf560e4c6bd","affectsGlobalScope":true,"impliedFormat":1},{"version":"c7b3542146734342e440a84b213384bfa188835537ddbda50d30766f0593aff9","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce6180fa19b1cccd07ee7f7dbb9a367ac19c0ed160573e4686425060b6df7f57","affectsGlobalScope":true,"impliedFormat":1},{"version":"3f02e2476bccb9dbe21280d6090f0df17d2f66b74711489415a8aa4df73c9675","affectsGlobalScope":true,"impliedFormat":1},{"version":"45e3ab34c1c013c8ab2dc1ba4c80c780744b13b5676800ae2e3be27ae862c40c","affectsGlobalScope":true,"impliedFormat":1},{"version":"805c86f6cca8d7702a62a844856dbaa2a3fd2abef0536e65d48732441dde5b5b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e42e397f1a5a77994f0185fd1466520691456c772d06bf843e5084ceb879a0ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"f4c2b41f90c95b1c532ecc874bd3c111865793b23aebcc1c3cbbabcd5d76ffb0","affectsGlobalScope":true,"impliedFormat":1},{"version":"ab26191cfad5b66afa11b8bf935ef1cd88fabfcb28d30b2dfa6fad877d050332","affectsGlobalScope":true,"impliedFormat":1},{"version":"2088bc26531e38fb05eedac2951480db5309f6be3fa4a08d2221abb0f5b4200d","affectsGlobalScope":true,"impliedFormat":1},{"version":"cb9d366c425fea79716a8fb3af0d78e6b22ebbab3bd64d25063b42dc9f531c1e","affectsGlobalScope":true,"impliedFormat":1},{"version":"500934a8089c26d57ebdb688fc9757389bb6207a3c8f0674d68efa900d2abb34","affectsGlobalScope":true,"impliedFormat":1},{"version":"689da16f46e647cef0d64b0def88910e818a5877ca5379ede156ca3afb780ac3","affectsGlobalScope":true,"impliedFormat":1},{"version":"bc21cc8b6fee4f4c2440d08035b7ea3c06b3511314c8bab6bef7a92de58a2593","affectsGlobalScope":true,"impliedFormat":1},{"version":"7ca53d13d2957003abb47922a71866ba7cb2068f8d154877c596d63c359fed25","affectsGlobalScope":true,"impliedFormat":1},{"version":"54725f8c4df3d900cb4dac84b64689ce29548da0b4e9b7c2de61d41c79293611","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5594bc3076ac29e6c1ebda77939bc4c8833de72f654b6e376862c0473199323","affectsGlobalScope":true,"impliedFormat":1},{"version":"2f3eb332c2d73e729f3364fcc0c2b375e72a121e8157d25a82d67a138c83a95c","affectsGlobalScope":true,"impliedFormat":1},{"version":"6f4427f9642ce8d500970e4e69d1397f64072ab73b97e476b4002a646ac743b1","affectsGlobalScope":true,"impliedFormat":1},{"version":"48915f327cd1dea4d7bd358d9dc7732f58f9e1626a29cc0c05c8c692419d9bb7","affectsGlobalScope":true,"impliedFormat":1},{"version":"b7bf9377723203b5a6a4b920164df22d56a43f593269ba6ae1fdc97774b68855","affectsGlobalScope":true,"impliedFormat":1},{"version":"db9709688f82c9e5f65a119c64d835f906efe5f559d08b11642d56eb85b79357","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b25b8c874acd1a4cf8444c3617e037d444d19080ac9f634b405583fd10ce1f7","affectsGlobalScope":true,"impliedFormat":1},{"version":"37be57d7c90cf1f8112ee2636a068d8fd181289f82b744160ec56a7dc158a9f5","affectsGlobalScope":true,"impliedFormat":1},{"version":"a917a49ac94cd26b754ab84e113369a75d1a47a710661d7cd25e961cc797065f","affectsGlobalScope":true,"impliedFormat":1},{"version":"6d3261badeb7843d157ef3e6f5d1427d0eeb0af0cf9df84a62cfd29fd47ac86e","affectsGlobalScope":true,"impliedFormat":1},{"version":"195daca651dde22f2167ac0d0a05e215308119a3100f5e6268e8317d05a92526","affectsGlobalScope":true,"impliedFormat":1},{"version":"8b11e4285cd2bb164a4dc09248bdec69e9842517db4ca47c1ba913011e44ff2f","affectsGlobalScope":true,"impliedFormat":1},{"version":"0508571a52475e245b02bc50fa1394065a0a3d05277fbf5120c3784b85651799","affectsGlobalScope":true,"impliedFormat":1},{"version":"8f9af488f510c3015af3cc8c267a9e9d96c4dd38a1fdff0e11dc5a544711415b","affectsGlobalScope":true,"impliedFormat":1},{"version":"fc611fea8d30ea72c6bbfb599c9b4d393ce22e2f5bfef2172534781e7d138104","affectsGlobalScope":true,"impliedFormat":1},{"version":"f128dae7c44d8f35ee42e0a437000a57c9f06cc04f8b4fb42eebf44954d53dc8","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ecb8e347cb6b2a8927c09b86263663289418df375f5e68e11a0ae683776978f","affectsGlobalScope":true,"impliedFormat":1},{"version":"1ce14b81c5cc821994aa8ec1d42b220dd41b27fcc06373bce3958af7421b77d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3a048b3e9302ef9a34ef4ebb9aecfb28b66abb3bce577206a79fee559c230da","affectsGlobalScope":true,"impliedFormat":1},{"version":"7393ceda945e861df36614bba98ddf016d61ed24ecfe8a87db36c3e4bc25bd9a","signature":"70e49b961a8b9254ad9298bc101899fd521a050fbdca447d7139c5d1dde336d3","impliedFormat":1},{"version":"cde933fc3069fde479a059ace0f1e55d9ba76944caea29e6bd83e1dc41263d4f","signature":"49f3b4ec5a1cb6b7b004ca2d2b743b8a1babc24a4d2ead1125668d40f91af825","impliedFormat":1},{"version":"468cb816465c13eef209a7d0c044abba4fd74263ac497bde7cf24ffe1a234ba3","signature":"907b4f9e464a64d464429bc6351fd910a5b2a05a16f9f10fdb7d46978e3c1199","impliedFormat":1},{"version":"b1f808c6463cc39daa15d317f121a2dc0d1de2e0f30e4c86001244f4056e2b5a","signature":"26522a565973612f576379f5b349dcddb2d74842fa29bb0e17174d00f616b267","impliedFormat":1},{"version":"346eb8ef330d7fbf80ba1400b93c7b21aeeff8874124ff46ddb5efbbb8caf700","signature":"b8e0351fff4ac90d176ae0203c72b1ffe811f5074caeee14e2c133e151bf1ad6","impliedFormat":1},{"version":"dbafafbeb6292f1dcec1d4fbc371cea3f567be1a7084ce5c6887cfc7d6b02a88","signature":"43e818adf60173644896298637f47b01d5819b17eda46eaa32d0c7d64724d012","impliedFormat":1},{"version":"d153a11543fd884b596587ccd97aebbeed950b26933ee000f94009f1ab142848","affectsGlobalScope":true,"impliedFormat":1},{"version":"0ccdaa19852d25ecd84eec365c3bfa16e7859cadecf6e9ca6d0dbbbee439743f","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc2110f7decca6bfb9392e30421cfa1436479e4a6756e8fec6cbc22625d4f881","affectsGlobalScope":true,"impliedFormat":1},{"version":"096116f8fedc1765d5bd6ef360c257b4a9048e5415054b3bf3c41b07f8951b0b","affectsGlobalScope":true,"impliedFormat":1},{"version":"e5e01375c9e124a83b52ee4b3244ed1a4d214a6cfb54ac73e164a823a4a7860a","affectsGlobalScope":true,"impliedFormat":1},{"version":"f90ae2bbce1505e67f2f6502392e318f5714bae82d2d969185c4a6cecc8af2fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"4b58e207b93a8f1c88bbf2a95ddc686ac83962b13830fe8ad3f404ffc7051fb4","affectsGlobalScope":true,"impliedFormat":1},{"version":"1fefabcb2b06736a66d2904074d56268753654805e829989a46a0161cd8412c5","affectsGlobalScope":true,"impliedFormat":1},{"version":"9798340ffb0d067d69b1ae5b32faa17ab31b82466a3fc00d8f2f2df0c8554aaa","affectsGlobalScope":true,"impliedFormat":1},{"version":"c18a99f01eb788d849ad032b31cafd49de0b19e083fe775370834c5675d7df8e","affectsGlobalScope":true,"impliedFormat":1},{"version":"5247874c2a23b9a62d178ae84f2db6a1d54e6c9a2e7e057e178cc5eea13757fc","affectsGlobalScope":true,"impliedFormat":1},{"version":"cdcf9ea426ad970f96ac930cd176d5c69c6c24eebd9fc580e1572d6c6a88f62c","impliedFormat":1},{"version":"23cd712e2ce083d68afe69224587438e5914b457b8acf87073c22494d706a3d0","impliedFormat":1},{"version":"156a859e21ef3244d13afeeba4e49760a6afa035c149dda52f0c45ea8903b338","impliedFormat":1},{"version":"10ec5e82144dfac6f04fa5d1d6c11763b3e4dbbac6d99101427219ab3e2ae887","impliedFormat":1},{"version":"615754924717c0b1e293e083b83503c0a872717ad5aa60ed7f1a699eb1b4ea5c","impliedFormat":1},{"version":"14e9acf826baba0ef4b5665704084896e7bcc06f65a9ab13af7e93d27d6b7069","impliedFormat":1},{"version":"68834d631c8838c715f225509cfc3927913b9cc7a4870460b5b60c8dbdb99baf","impliedFormat":1},{"version":"21adf13435b9b748529c8cedf80f884e5130b9684188120a686cd2b26a2059c7","impliedFormat":1},{"version":"eec76bf6b9346f3f95fa402621b889489e96930e72295b0369022f332e9b4a6a","impliedFormat":1},{"version":"0ecd58f413f9bc3b7d4383eae31b0c8fc576985cd7404d6f99f8c643543ade74","impliedFormat":1},{"version":"ea6bc8de8b59f90a7a3960005fd01988f98fd0784e14bc6922dde2e93305ec7d","impliedFormat":1},{"version":"36107995674b29284a115e21a0618c4c2751b32a8766dd4cb3ba740308b16d59","impliedFormat":1},{"version":"914a0ae30d96d71915fc519ccb4efbf2b62c0ddfb3a3fc6129151076bc01dc60","impliedFormat":1},{"version":"9c32412007b5662fd34a8eb04292fb5314ec370d7016d1c2fb8aa193c807fe22","impliedFormat":1},{"version":"7fd1b31fd35876b0aa650811c25ec2c97a3c6387e5473eb18004bed86cdd76b6","impliedFormat":1},{"version":"4d327f7d72ad0918275cea3eee49a6a8dc8114ae1d5b7f3f5d0774de75f7439a","impliedFormat":1},{"version":"6ebe8ebb8659aaa9d1acbf3710d7dae3e923e97610238b9511c25dc39023a166","impliedFormat":1},{"version":"e85d7f8068f6a26710bff0cc8c0fc5e47f71089c3780fbede05857331d2ddec9","impliedFormat":1},{"version":"7befaf0e76b5671be1d47b77fcc65f2b0aad91cc26529df1904f4a7c46d216e9","impliedFormat":1},{"version":"0a60a292b89ca7218b8616f78e5bbd1c96b87e048849469cccb4355e98af959a","impliedFormat":1},{"version":"0b6e25234b4eec6ed96ab138d96eb70b135690d7dd01f3dd8a8ab291c35a683a","impliedFormat":1},{"version":"9666f2f84b985b62400d2e5ab0adae9ff44de9b2a34803c2c5bd3c8325b17dc0","impliedFormat":1},{"version":"40cd35c95e9cf22cfa5bd84e96408b6fcbca55295f4ff822390abb11afbc3dca","impliedFormat":1},{"version":"b1616b8959bf557feb16369c6124a97a0e74ed6f49d1df73bb4b9ddf68acf3f3","impliedFormat":1},{"version":"5b03a034c72146b61573aab280f295b015b9168470f2df05f6080a2122f9b4df","impliedFormat":1},{"version":"40b463c6766ca1b689bfcc46d26b5e295954f32ad43e37ee6953c0a677e4ae2b","impliedFormat":1},{"version":"249b9cab7f5d628b71308c7d9bb0a808b50b091e640ba3ed6e2d0516f4a8d91d","impliedFormat":1},{"version":"d33ce35e3f9cfcc1d94eca415bdd3bde94d5b153ffdd33e6c4455c029986c630","impliedFormat":1},{"version":"80aae6afc67faa5ac0b32b5b8bc8cc9f7fa299cff15cf09cc2e11fd28c6ae29e","impliedFormat":1},{"version":"f473cd2288991ff3221165dcf73cd5d24da30391f87e85b3dd4d0450c787a391","impliedFormat":1},{"version":"499e5b055a5aba1e1998f7311a6c441a369831c70905cc565ceac93c28083d53","impliedFormat":1},{"version":"8aee8b6d4f9f62cf3776cda1305fb18763e2aade7e13cea5bbe699112df85214","impliedFormat":1},{"version":"98498b101803bb3dde9f76a56e65c14b75db1cc8bec5f4db72be541570f74fc5","impliedFormat":1},{"version":"4dc59f6e1dbf3d5f66660fceabe6c174d3261b37b696ae1854f0dbaf255fc753","impliedFormat":1},{"version":"5d0375ca7310efb77e3ef18d068d53784faf62705e0ad04569597ae0e755c401","impliedFormat":1},{"version":"59af37caec41ecf7b2e76059c9672a49e682c1a2aa6f9d7dc78878f53aa284d6","impliedFormat":1},{"version":"addf417b9eb3f938fddf8d81e96393a165e4be0d4a8b6402292f9c634b1cb00d","impliedFormat":1},{"version":"436d7b4543b340b0f3eef4310d524242e41369b9652aa9c70428767c4dcac455","impliedFormat":1},{"version":"adf27937dba6af9f08a68c5b1d3fce0ca7d4b960c57e6d6c844e7d1a8e53adae","impliedFormat":1},{"version":"12950411eeab8563b349cb7959543d92d8d02c289ed893d78499a19becb5a8cc","impliedFormat":1},{"version":"2e85db9e6fd73cfa3d7f28e0ab6b55417ea18931423bd47b409a96e4a169e8e6","impliedFormat":1},{"version":"c46e079fe54c76f95c67fb89081b3e399da2c7d109e7dca8e4b58d83e332e605","impliedFormat":1},{"version":"114f493b30f364255290472111b5a4791d5902c308645670cd0401429cbc6930","impliedFormat":1},{"version":"c3f5289820990ab66b70c7fb5b63cb674001009ff84b13de40619619a9c8175f","affectsGlobalScope":true,"impliedFormat":1},{"version":"b3275d55fac10b799c9546804126239baf020d220136163f763b55a74e50e750","affectsGlobalScope":true,"impliedFormat":1},{"version":"fa68a0a3b7cb32c00e39ee3cd31f8f15b80cac97dce51b6ee7fc14a1e8deb30b","affectsGlobalScope":true,"impliedFormat":1},{"version":"1cf059eaf468efcc649f8cf6075d3cb98e9a35a0fe9c44419ec3d2f5428d7123","affectsGlobalScope":true,"impliedFormat":1},{"version":"6c36e755bced82df7fb6ce8169265d0a7bb046ab4e2cb6d0da0cb72b22033e89","affectsGlobalScope":true,"impliedFormat":1},{"version":"e7721c4f69f93c91360c26a0a84ee885997d748237ef78ef665b153e622b36c1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7a93de4ff8a63bafe62ba86b89af1df0ccb5e40bb85b0c67d6bbcfdcf96bf3d4","affectsGlobalScope":true,"impliedFormat":1},{"version":"90e85f9bc549dfe2b5749b45fe734144e96cd5d04b38eae244028794e142a77e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e0a5deeb610b2a50a6350bd23df6490036a1773a8a71d70f2f9549ab009e67ee","affectsGlobalScope":true,"impliedFormat":1},{"version":"d2ae155afe8a01cc0ae612d99117cf8ef16692ba7c4366590156fdec1bcf2d8c","impliedFormat":1},{"version":"3f5e5d9be35913db9fea42a63f3df0b7e3c8703b97670a2125587b4dbbd56d7c","impliedFormat":1},{"version":"c8b8968311ec4e5e97b7b5fb8a65efaba455db9bdcfd7fff7fb15f6e317bfba0","impliedFormat":1},{"version":"57c23df0b5f7a8e26363a3849b0bc7763f6b241207157c8e40089d1df4116f35","affectsGlobalScope":true,"impliedFormat":1},{"version":"3b8bc0c17b54081b0878673989216229e575d67a10874e84566a21025a2461ee","impliedFormat":1},{"version":"5b0db5a58b73498792a29bfebc333438e61906fef75da898b410e24e52229e6f","impliedFormat":1},{"version":"dbe055b2b29a7bab2c1ca8f259436306adb43f469dca7e639a02cd3695d3f621","impliedFormat":1},{"version":"1678b04557dca52feab73cc67610918a7f5e25bfdba3e7fa081acd625d93106d","impliedFormat":1},{"version":"aecbf1d9e6a18dab7d92ef8a89a1444b47e1eb6134cb2bb776a26d55ff58c29a","impliedFormat":1},{"version":"2ea729503db9793f2691162fec3dd1118cab62e96d025f8eeb376d43ec293395","impliedFormat":1},{"version":"9ec87fea42b92894b0f209931a880789d43c3397d09dd99c631ae40a2f7071d1","impliedFormat":1},{"version":"c68e88cdfadfb6c8ba5fc38e58a3a166b0beae77b1f05b7d921150a32a5ffb8d","impliedFormat":1},{"version":"2bc7aa4fba46df0bd495425a7c8201437a7d465f83854fac859df2d67f664df3","impliedFormat":1},{"version":"41d17e1ad9a002feb11c8cdd2777e5bbc0cdb1e3f595d237e4dded0b6949983b","impliedFormat":1},{"version":"1fede9296beac11ce8e6b425396a1791f64341f2be85deebb6286faf6e16306e","affectsGlobalScope":true,"impliedFormat":1},{"version":"ce697b6a251d9cad53998c7fd3098072df883b525ec45d83530e434dc6d80dc6","impliedFormat":1},{"version":"719412f054e6ecc35489462c9a21bab0323d173a7d04e55b0ace4b5d86fbeb07","impliedFormat":1},{"version":"0eb5d0cbf09de5d34542b977fd6a933bb2e0817bffe8e1a541b2f1ad1b9af1ff","impliedFormat":1},{"version":"fac3e88881b35d3a757ed891ac912b2674792c25e2a1a74e1f5fbc72d19a9792","impliedFormat":1},{"version":"2c2bdaa1d8ead9f68628d6d9d250e46ee8e81aa4898b4769a36956ae15e060fe","impliedFormat":1},{"version":"c32c840c62d8bd7aeb3147aa6754cd2d922b990a6b6634530cb2ebdce5adc8e9","impliedFormat":1},{"version":"5ff4433a2deae4f85ab1377e90a7554ce6b47ae51c69a84ca30a6e22fae85834","impliedFormat":1},{"version":"82b91e4e42e6c41bc7fc1b6c2dc5eba6a2ba98375eb1f210e6ff6bba2d54177e","impliedFormat":1},{"version":"c1fa52b3d014001e8662fa2669d90ea15373958a288e3b83a3b621733d25292a","affectsGlobalScope":true,"impliedFormat":1},{"version":"cbed824fec91efefc7bbdcb8b43d1a531fdbebd0e2ef19481501ff365a93cb70","impliedFormat":1},{"version":"d0716593b3f2b0451bcf0c24cfa86dec2235c325c89f201934248b7c742715fc","impliedFormat":1},{"version":"ec501101c2a96133a6c695f934c8f6642149cc728571b29cbb7b770984c1088e","impliedFormat":1},{"version":"b214ebcf76c51b115453f69729ee8aa7b7f8eccdae2a922b568a45c2d7ff52f7","impliedFormat":1},{"version":"429c9cdfa7d126255779efd7e6d9057ced2d69c81859bbab32073bad52e9ba76","impliedFormat":1},{"version":"2991bca2cc0f0628a278df2a2ccdb8d6cbcb700f3761abbed62bba137d5b1790","impliedFormat":1},{"version":"5e66972e83eb4dc7123939bf816e6cbd9ad81af5552db1cab84e6bd9c64d2ecc","affectsGlobalScope":true,"impliedFormat":1},{"version":"230763250f20449fa7b3c9273e1967adb0023dc890d4be1553faca658ee65971","impliedFormat":1},{"version":"c3e9078b60cb329d1221f5878e88cecfa3e74460550e605a58fcfb41a66029ff","impliedFormat":1},{"version":"8413d0641f293aed551c7464615b770d34a02dedede889b9591172287d68e773","impliedFormat":1},{"version":"0ea59f7d3e51440baa64f429253759b106cfcbaf51e474cae606e02265b37cf8","impliedFormat":1},{"version":"bc18a1991ba681f03e13285fa1d7b99b03b67ee671b7bc936254467177543890","impliedFormat":1},{"version":"1b241e24f3227d078c06aeda6e050187ad59a4e591f4467abed44d92b084e08d","impliedFormat":1},{"version":"fa94bbf532b7af8f394b95fa310980d6e20bd2d4c871c6a6cb9f70f03750a44b","impliedFormat":1},{"version":"7fde0e1be5c8be204ffbf428abfcf01da2eb0f130e1bc3f539eb7275f4fd1f58","impliedFormat":1},{"version":"e284328553df5f425a5d33d36a0c3fa66b46af9d097cad6f4d2e8696dfdeb0f1","affectsGlobalScope":true,"impliedFormat":1},{"version":"7fa2214bb0d64701bc6f9ce8cde2fd2ff8c571e0b23065fa04a8a5a6beb91511","impliedFormat":1},{"version":"f36b3fbe2be150a9ca140da48593f21e6a8172004f92ddc549b43efec39f3e54","impliedFormat":1},{"version":"f1c93e046fb3d9b7f8249629f4b63dc068dd839b824dd0aa39a5e68476dc9420","impliedFormat":1},{"version":"016b29bf4926b80255a108c53a1451717350059da04fcae64d1075f5e93bbb39","impliedFormat":1},{"version":"841983e39bd4cbb463be385e92fda11057cab368bf27100a801c492f1d86cbaa","impliedFormat":1},{"version":"1c4f139ade4f6ebf45463505f8155173e5d7a5305e50e0aae0a5e712d6ff3b48","impliedFormat":1},{"version":"e16b319e5aca1031168de823c4946ff8e29629c4c8cc0ec0fcfe2a8ab2155043","impliedFormat":1},{"version":"e4156ddb25aa0e3b5303d372f26957b36778f0f6bbd4326359269873295e3058","affectsGlobalScope":true,"impliedFormat":1},{"version":"cc1b433a84cae05ddc5672d4823170af78606ad21ecef60dbc4570190cbf1357","impliedFormat":1},{"version":"9d3821bc75c59577e52643324cec92fc2145642e8d17cf7ee07a3181f21d985d","impliedFormat":1},{"version":"7f78cfb2b343838612c192cb251746e3a7c62ac7675726a47e130d9b213f6580","impliedFormat":1},{"version":"201db9cf1687fab1adf5282fcba861f382b32303dc4f67c89d59655e78a25461","impliedFormat":1},{"version":"2c3c5c0f54055e87640f5d233716fd889f3034fc7911d603b642369b0dbeb2a7","impliedFormat":1},{"version":"0a20eaf2e4b1e3c1e1f87f7bccb0c936375b23b022baeea750519b7c9bc6ce83","impliedFormat":1},{"version":"b484ec11ba00e3a2235562a41898d55372ccabe607986c6fa4f4aba72093749f","impliedFormat":1},{"version":"a16b91b27bd6b706c687c88cbc8a7d4ee98e5ed6043026d6b84bda923c0aed67","impliedFormat":1},{"version":"1c9e5b1a17b1fc9b3711fb36e0690421261ab2880f15b145155b5b2ba2ab6c2d","impliedFormat":1},{"version":"99ab6d0d660ce4d21efb52288a39fd35bb3f556980ec5463b1ae8f304a3bbc85","impliedFormat":1},{"version":"6eeded8c7e352be6e0efb83f4935ec752513c4d22043b52522b90849a49a3a11","impliedFormat":1},{"version":"6c1ad90050ffbb151cacc68e2d06ea1a26a945659391e32651f5d42b86fd7f2c","impliedFormat":1},{"version":"afa1c49f8e559e413d57343339db857d2a8159435cf9cf7d4deb41718fff1b88","impliedFormat":1},{"version":"6953d7597831d0860c7034cf4f0419687d263b6b98a4b32e37ce6d49615c36e2","impliedFormat":1}],"root":[[60,65]],"options":{"composite":true,"declaration":true,"declarationMap":true,"esModuleInterop":true,"module":100,"noFallthroughCasesInSwitch":true,"noImplicitOverride":true,"outDir":"./","rootDir":"..","skipLibCheck":true,"sourceMap":true,"strict":true,"target":9},"referencedMap":[[65,1],[129,2],[130,2],[131,3],[68,4],[132,5],[133,6],[134,7],[66,8],[135,9],[136,10],[137,11],[138,12],[139,13],[140,14],[141,14],[142,15],[143,16],[144,17],[145,18],[69,8],[67,8],[146,19],[147,20],[148,21],[190,22],[149,23],[150,24],[151,23],[152,25],[153,26],[154,27],[155,28],[156,28],[157,28],[158,29],[159,30],[160,31],[161,32],[162,33],[163,34],[164,34],[165,35],[166,8],[167,8],[168,36],[169,37],[170,38],[171,36],[172,39],[173,40],[174,41],[175,42],[176,43],[177,44],[178,45],[179,46],[180,47],[181,48],[182,49],[183,50],[184,51],[185,52],[186,53],[70,23],[71,8],[72,54],[73,55],[74,8],[75,56],[76,8],[120,57],[121,58],[122,59],[123,59],[124,60],[125,8],[126,5],[127,61],[128,58],[187,62],[188,63],[189,64],[58,8],[59,8],[11,8],[10,8],[2,8],[12,8],[13,8],[14,8],[15,8],[16,8],[17,8],[18,8],[19,8],[3,8],[20,8],[21,8],[4,8],[22,8],[26,8],[23,8],[24,8],[25,8],[27,8],[28,8],[29,8],[5,8],[30,8],[31,8],[32,8],[33,8],[6,8],[37,8],[34,8],[35,8],[36,8],[38,8],[7,8],[39,8],[44,8],[45,8],[40,8],[41,8],[42,8],[43,8],[8,8],[49,8],[46,8],[47,8],[48,8],[50,8],[9,8],[51,8],[52,8],[53,8],[55,8],[54,8],[56,8],[1,8],[57,8],[95,65],[108,66],[92,67],[109,68],[118,69],[83,70],[84,71],[82,72],[117,73],[112,74],[116,75],[86,76],[105,77],[85,78],[115,79],[80,80],[81,74],[87,81],[88,8],[94,82],[91,81],[78,83],[119,84],[110,85],[98,86],[97,81],[99,87],[102,88],[96,89],[100,90],[113,73],[89,91],[90,92],[103,93],[79,68],[107,94],[106,81],[93,92],[101,95],[104,96],[111,8],[77,8],[114,97],[64,98],[62,99],[60,28],[63,100],[61,101]],"latestChangedDtsFile":"./bin/foldnize.d.ts","version":"6.0.3"}
|
package/package.json
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "foldnize",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Organize photos and videos by their embedded EXIF/QuickTime original date — three renaming modes, optional Year/Month folder sorting, dry-run preview.",
|
|
5
|
+
"main": "dist/src/index.js",
|
|
6
|
+
"types": "dist/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./dist/src/index.d.ts",
|
|
10
|
+
"default": "./dist/src/index.js"
|
|
11
|
+
}
|
|
12
|
+
},
|
|
13
|
+
"bin": {
|
|
14
|
+
"foldnize": "./dist/bin/foldnize.js"
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc -p tsconfig.build.json",
|
|
22
|
+
"build:watch": "tsc -p tsconfig.build.json --watch",
|
|
23
|
+
"typecheck": "tsc -p tsconfig.json",
|
|
24
|
+
"test": "tsx --test \"test/*.test.ts\"",
|
|
25
|
+
"clean": "rm -rf dist",
|
|
26
|
+
"prepublishOnly": "npm run clean && npm run build && chmod +x dist/bin/foldnize.js"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"files",
|
|
30
|
+
"rename",
|
|
31
|
+
"organize",
|
|
32
|
+
"media",
|
|
33
|
+
"photos",
|
|
34
|
+
"videos",
|
|
35
|
+
"exif",
|
|
36
|
+
"metadata",
|
|
37
|
+
"exiftool",
|
|
38
|
+
"ffprobe"
|
|
39
|
+
],
|
|
40
|
+
"author": "Matheus Chignolli",
|
|
41
|
+
"license": "MIT",
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "https://github.com/MatheusChignolli/foldnize",
|
|
45
|
+
"directory": "library"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/MatheusChignolli/foldnize/tree/main/library#readme",
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/MatheusChignolli/foldnize/issues"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=22"
|
|
53
|
+
},
|
|
54
|
+
"publishConfig": {
|
|
55
|
+
"access": "public",
|
|
56
|
+
"provenance": true
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^25.9.1",
|
|
60
|
+
"tsx": "^4.22.4",
|
|
61
|
+
"typescript": "^6.0.3"
|
|
62
|
+
}
|
|
63
|
+
}
|