reelsort 0.1.2 → 0.2.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/dist/cli.js +203 -175
- package/dist/index.d.mts +16 -9
- package/dist/index.d.ts +16 -9
- package/dist/index.js +125 -104
- package/dist/index.mjs +119 -100
- package/package.json +2 -4
package/dist/index.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// src/actions/clean.ts
|
|
2
|
-
import cosmetic from "cosmetic";
|
|
3
2
|
import { existsSync as existsSync2, rmSync } from "fs";
|
|
3
|
+
import { Color } from "termkit";
|
|
4
4
|
|
|
5
5
|
// src/db.ts
|
|
6
6
|
import Database from "better-sqlite3";
|
|
@@ -131,28 +131,21 @@ var getHistory = (limit = 10) => {
|
|
|
131
131
|
};
|
|
132
132
|
|
|
133
133
|
// src/refs/spinner.ts
|
|
134
|
-
import { Spinner as TermSpinner } from "
|
|
134
|
+
import { Spinner as TermSpinner } from "termkit";
|
|
135
135
|
var Spinner = class {
|
|
136
136
|
spinner;
|
|
137
|
-
_isSpinning = false;
|
|
138
|
-
_text = "";
|
|
139
137
|
constructor() {
|
|
140
138
|
this.spinner = new TermSpinner();
|
|
141
139
|
}
|
|
142
140
|
get text() {
|
|
143
|
-
return this.
|
|
141
|
+
return this.spinner.text;
|
|
144
142
|
}
|
|
145
143
|
set text(t) {
|
|
146
|
-
this.
|
|
147
|
-
if (this._isSpinning) this.spinner.message(t);
|
|
148
|
-
}
|
|
149
|
-
get isSpinning() {
|
|
150
|
-
return this._isSpinning;
|
|
144
|
+
this.spinner.text = t;
|
|
151
145
|
}
|
|
152
146
|
start(s) {
|
|
153
|
-
if (s) this.
|
|
147
|
+
if (s) this.spinner.text = s;
|
|
154
148
|
this.spinner.start();
|
|
155
|
-
this._isSpinning = true;
|
|
156
149
|
return this;
|
|
157
150
|
}
|
|
158
151
|
info(s) {
|
|
@@ -173,8 +166,6 @@ var Spinner = class {
|
|
|
173
166
|
}
|
|
174
167
|
stop() {
|
|
175
168
|
this.spinner.stop();
|
|
176
|
-
this._isSpinning = false;
|
|
177
|
-
process.stdin.resume();
|
|
178
169
|
return this;
|
|
179
170
|
}
|
|
180
171
|
};
|
|
@@ -213,17 +204,17 @@ var clean = async ({ dryRun, olderThan }) => {
|
|
|
213
204
|
continue;
|
|
214
205
|
}
|
|
215
206
|
if (dryRun) {
|
|
216
|
-
spinner_default.succeed(`[dry] would remove ${
|
|
207
|
+
spinner_default.succeed(`[dry] would remove ${Color.blue.encoder(imp.sourcePath)}`);
|
|
217
208
|
cleaned++;
|
|
218
209
|
continue;
|
|
219
210
|
}
|
|
220
211
|
try {
|
|
221
212
|
rmSync(imp.sourcePath, { recursive: true, force: true });
|
|
222
213
|
deleteImport(imp.id);
|
|
223
|
-
spinner_default.succeed(`removed ${
|
|
214
|
+
spinner_default.succeed(`removed ${Color.blue.encoder(imp.sourcePath)}`);
|
|
224
215
|
cleaned++;
|
|
225
216
|
} catch {
|
|
226
|
-
spinner_default.warn(`locked or inaccessible, skipped: ${
|
|
217
|
+
spinner_default.warn(`locked or inaccessible, skipped: ${Color.blue.encoder(imp.sourcePath)}`);
|
|
227
218
|
skipped++;
|
|
228
219
|
}
|
|
229
220
|
}
|
|
@@ -234,8 +225,8 @@ var clean = async ({ dryRun, olderThan }) => {
|
|
|
234
225
|
var clean_default = clean;
|
|
235
226
|
|
|
236
227
|
// src/actions/config.ts
|
|
237
|
-
import cosmetic2 from "cosmetic";
|
|
238
228
|
import { resolve } from "path";
|
|
229
|
+
import { Color as Color2 } from "termkit";
|
|
239
230
|
|
|
240
231
|
// src/config.ts
|
|
241
232
|
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync, writeFileSync } from "fs";
|
|
@@ -283,37 +274,64 @@ var formatMovieName = (template, title, year, edition) => {
|
|
|
283
274
|
|
|
284
275
|
// src/actions/config.ts
|
|
285
276
|
var DEST_TYPES = ["movie", "tv", "ps3"];
|
|
286
|
-
var
|
|
287
|
-
|
|
288
|
-
const dir = resolve(value);
|
|
277
|
+
var sourceAdd = async ({ dir }) => {
|
|
278
|
+
const resolved = resolve(dir);
|
|
289
279
|
const config = getConfig();
|
|
290
|
-
if (config.sources.includes(
|
|
280
|
+
if (config.sources.includes(resolved)) {
|
|
291
281
|
spinner_default.start();
|
|
292
|
-
spinner_default.info(`source already configured: ${
|
|
282
|
+
spinner_default.info(`source already configured: ${Color2.blue.encoder(resolved)}`);
|
|
293
283
|
spinner_default.stop();
|
|
294
284
|
return;
|
|
295
285
|
}
|
|
296
|
-
config.sources.push(
|
|
286
|
+
config.sources.push(resolved);
|
|
297
287
|
saveConfig(config);
|
|
298
288
|
spinner_default.start();
|
|
299
|
-
spinner_default.succeed(`added source: ${
|
|
289
|
+
spinner_default.succeed(`added source: ${Color2.blue.encoder(resolved)}`);
|
|
300
290
|
spinner_default.stop();
|
|
301
291
|
};
|
|
302
|
-
var
|
|
303
|
-
|
|
304
|
-
const dir = resolve(value);
|
|
292
|
+
var sourceRemove = async ({ dir }) => {
|
|
293
|
+
const resolved = resolve(dir);
|
|
305
294
|
const config = getConfig();
|
|
306
|
-
const index = config.sources.indexOf(
|
|
295
|
+
const index = config.sources.indexOf(resolved);
|
|
307
296
|
if (index === -1) {
|
|
308
297
|
spinner_default.start();
|
|
309
|
-
spinner_default.warn(`source not found: ${
|
|
298
|
+
spinner_default.warn(`source not found: ${Color2.blue.encoder(resolved)}`);
|
|
310
299
|
spinner_default.stop();
|
|
311
300
|
return;
|
|
312
301
|
}
|
|
313
302
|
config.sources.splice(index, 1);
|
|
314
303
|
saveConfig(config);
|
|
315
304
|
spinner_default.start();
|
|
316
|
-
spinner_default.succeed(`removed source: ${
|
|
305
|
+
spinner_default.succeed(`removed source: ${Color2.blue.encoder(resolved)}`);
|
|
306
|
+
spinner_default.stop();
|
|
307
|
+
};
|
|
308
|
+
var destAdd = async ({ type, dir }) => {
|
|
309
|
+
if (!DEST_TYPES.includes(type)) {
|
|
310
|
+
throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
|
|
311
|
+
}
|
|
312
|
+
const resolved = resolve(dir);
|
|
313
|
+
const config = getConfig();
|
|
314
|
+
config.dest[type] = resolved;
|
|
315
|
+
saveConfig(config);
|
|
316
|
+
spinner_default.start();
|
|
317
|
+
spinner_default.succeed(`set ${type} destination: ${Color2.cyan.encoder(resolved)}`);
|
|
318
|
+
spinner_default.stop();
|
|
319
|
+
};
|
|
320
|
+
var destRemove = async ({ type }) => {
|
|
321
|
+
if (!DEST_TYPES.includes(type)) {
|
|
322
|
+
throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
|
|
323
|
+
}
|
|
324
|
+
const config = getConfig();
|
|
325
|
+
if (!config.dest[type]) {
|
|
326
|
+
spinner_default.start();
|
|
327
|
+
spinner_default.warn(`no ${type} destination configured`);
|
|
328
|
+
spinner_default.stop();
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
delete config.dest[type];
|
|
332
|
+
saveConfig(config);
|
|
333
|
+
spinner_default.start();
|
|
334
|
+
spinner_default.succeed(`removed ${type} destination`);
|
|
317
335
|
spinner_default.stop();
|
|
318
336
|
};
|
|
319
337
|
var configSet = async ({ key, subkey, value }) => {
|
|
@@ -322,7 +340,7 @@ var configSet = async ({ key, subkey, value }) => {
|
|
|
322
340
|
config.language = subkey;
|
|
323
341
|
saveConfig(config);
|
|
324
342
|
spinner_default.start();
|
|
325
|
-
spinner_default.succeed(`set subtitle language: ${
|
|
343
|
+
spinner_default.succeed(`set subtitle language: ${Color2.cyan.encoder(subkey)}`);
|
|
326
344
|
spinner_default.stop();
|
|
327
345
|
return;
|
|
328
346
|
}
|
|
@@ -352,21 +370,11 @@ var configSet = async ({ key, subkey, value }) => {
|
|
|
352
370
|
}
|
|
353
371
|
saveConfig(config);
|
|
354
372
|
spinner_default.start();
|
|
355
|
-
spinner_default.succeed(`set ${subkey} format: ${
|
|
373
|
+
spinner_default.succeed(`set ${subkey} format: ${Color2.cyan.encoder(value ?? subkey)}`);
|
|
356
374
|
spinner_default.stop();
|
|
357
375
|
return;
|
|
358
376
|
}
|
|
359
|
-
|
|
360
|
-
if (!DEST_TYPES.includes(subkey)) {
|
|
361
|
-
throw new Error(`unknown type '${subkey}', expected: ${DEST_TYPES.join(", ")}`);
|
|
362
|
-
}
|
|
363
|
-
if (!value) throw new Error(`missing path for dest ${subkey}`);
|
|
364
|
-
const dir = resolve(value);
|
|
365
|
-
config.dest[subkey] = dir;
|
|
366
|
-
saveConfig(config);
|
|
367
|
-
spinner_default.start();
|
|
368
|
-
spinner_default.succeed(`set ${subkey} destination: ${cosmetic2.cyan.encoder(dir)}`);
|
|
369
|
-
spinner_default.stop();
|
|
377
|
+
throw new Error(`unknown key '${key}', expected: language, tmdb-key, format`);
|
|
370
378
|
};
|
|
371
379
|
var configShow = async () => {
|
|
372
380
|
const config = getConfig();
|
|
@@ -374,7 +382,7 @@ var configShow = async () => {
|
|
|
374
382
|
if (config.sources.length === 0) {
|
|
375
383
|
console.log(" (none)");
|
|
376
384
|
} else {
|
|
377
|
-
for (const s of config.sources) console.log(` ${
|
|
385
|
+
for (const s of config.sources) console.log(` ${Color2.blue.encoder(s)}`);
|
|
378
386
|
}
|
|
379
387
|
console.log("\nDestinations:");
|
|
380
388
|
const entries = DEST_TYPES.map((t) => ({ type: t, path: config.dest[t] })).filter((e) => e.path);
|
|
@@ -382,26 +390,26 @@ var configShow = async () => {
|
|
|
382
390
|
console.log(" (none)");
|
|
383
391
|
} else {
|
|
384
392
|
for (const { type, path } of entries) {
|
|
385
|
-
console.log(` ${type.padEnd(6)} ${
|
|
393
|
+
console.log(` ${type.padEnd(6)} ${Color2.cyan.encoder(path)}`);
|
|
386
394
|
}
|
|
387
395
|
}
|
|
388
396
|
console.log(`
|
|
389
|
-
Subtitle language: ${
|
|
390
|
-
console.log(`TMDb API key: ${config.tmdbApiKey ?
|
|
391
|
-
console.log(`Movie format: ${
|
|
392
|
-
console.log(`Episode format: ${
|
|
393
|
-
console.log(`Season folder: ${
|
|
397
|
+
Subtitle language: ${Color2.cyan.encoder(config.language ?? "eng (default)")}`);
|
|
398
|
+
console.log(`TMDb API key: ${config.tmdbApiKey ? Color2.green.encoder("configured") : Color2.red.encoder("not set")}`);
|
|
399
|
+
console.log(`Movie format: ${Color2.cyan.encoder(config.format?.movie ?? DEFAULT_MOVIE_FORMAT + " (default)")}`);
|
|
400
|
+
console.log(`Episode format: ${Color2.cyan.encoder(config.format?.episode ?? DEFAULT_EPISODE_FORMAT + " (default)")}`);
|
|
401
|
+
console.log(`Season folder: ${Color2.cyan.encoder(config.format?.season ?? DEFAULT_SEASON_FORMAT + " (default)")}`);
|
|
394
402
|
console.log();
|
|
395
403
|
};
|
|
396
404
|
|
|
397
405
|
// src/actions/differences.ts
|
|
398
|
-
import cosmetic3 from "cosmetic";
|
|
399
406
|
import { existsSync as existsSync4, readdirSync } from "fs";
|
|
400
407
|
import { resolve as resolve2 } from "path";
|
|
408
|
+
import { Color as Color3 } from "termkit";
|
|
401
409
|
var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
|
|
402
410
|
let dir1 = rawDir1;
|
|
403
411
|
let dir2 = rawDir2;
|
|
404
|
-
spinner_default.text = `checking differences between ${
|
|
412
|
+
spinner_default.text = `checking differences between ${Color3.blue.encoder(dir1)} and ${Color3.blue.encoder(dir2)}`;
|
|
405
413
|
spinner_default.start();
|
|
406
414
|
dir1 = resolve2(dir1);
|
|
407
415
|
dir2 = resolve2(dir2);
|
|
@@ -437,18 +445,18 @@ var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
|
|
|
437
445
|
removed.push(l);
|
|
438
446
|
}
|
|
439
447
|
}
|
|
440
|
-
spinner_default.succeed(`checked differences between ${
|
|
448
|
+
spinner_default.succeed(`checked differences between ${Color3.blue.encoder(dir1)} and ${Color3.blue.encoder(dir2)}`);
|
|
441
449
|
spinner_default.succeed(`found ${added.length} added files`);
|
|
442
450
|
spinner_default.succeed(`found ${removed.length} removed files`);
|
|
443
451
|
spinner_default.stop();
|
|
444
|
-
for (const i of added) console.log(`${
|
|
445
|
-
for (const i of removed) console.log(`${
|
|
452
|
+
for (const i of added) console.log(`${Color3.green.encoder("added")} ${i}`);
|
|
453
|
+
for (const i of removed) console.log(`${Color3.red.encoder("removed")} ${i}`);
|
|
446
454
|
};
|
|
447
455
|
var differences_default = differences;
|
|
448
456
|
|
|
449
457
|
// src/actions/history.ts
|
|
450
|
-
import cosmetic4 from "cosmetic";
|
|
451
458
|
import { basename, extname } from "path";
|
|
459
|
+
import { Color as Color4 } from "termkit";
|
|
452
460
|
var history = async ({ limit, imports }) => {
|
|
453
461
|
if (imports) {
|
|
454
462
|
const sessions = getImportHistory(limit ?? 10);
|
|
@@ -460,11 +468,11 @@ var history = async ({ limit, imports }) => {
|
|
|
460
468
|
const date = new Date(session.sessionId);
|
|
461
469
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
462
470
|
console.log(`
|
|
463
|
-
${
|
|
471
|
+
${Color4.yellow.encoder(label)} (${session.records.length} item${session.records.length !== 1 ? "s" : ""})`);
|
|
464
472
|
for (const r of session.records) {
|
|
465
473
|
const src = basename(r.sourcePath);
|
|
466
|
-
const dest =
|
|
467
|
-
const mode = r.mode !== "move" ? ` ${
|
|
474
|
+
const dest = Color4.cyan.encoder(r.destinationPath);
|
|
475
|
+
const mode = r.mode !== "move" ? ` ${Color4.blue.encoder(`[${r.mode}]`)}` : "";
|
|
468
476
|
console.log(` ${src} \u2192 ${dest}${mode}`);
|
|
469
477
|
}
|
|
470
478
|
}
|
|
@@ -479,11 +487,11 @@ ${cosmetic4.yellow.encoder(label)} (${session.records.length} item${session.rec
|
|
|
479
487
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
480
488
|
const folders = session.records.filter((r) => extname(r.newPath) === "");
|
|
481
489
|
console.log(`
|
|
482
|
-
${
|
|
490
|
+
${Color4.yellow.encoder(label)} (${folders.length} item${folders.length !== 1 ? "s" : ""})`);
|
|
483
491
|
for (const r of folders) {
|
|
484
492
|
const oldName = basename(r.oldPath);
|
|
485
493
|
const newName = basename(r.newPath);
|
|
486
|
-
console.log(` ${
|
|
494
|
+
console.log(` ${Color4.blue.encoder(oldName)} \u2192 ${Color4.cyan.encoder(newName)}`);
|
|
487
495
|
}
|
|
488
496
|
}
|
|
489
497
|
}
|
|
@@ -492,9 +500,9 @@ ${cosmetic4.yellow.encoder(label)} (${folders.length} item${folders.length !==
|
|
|
492
500
|
var history_default = history;
|
|
493
501
|
|
|
494
502
|
// src/actions/list.ts
|
|
495
|
-
import cosmetic5 from "cosmetic";
|
|
496
503
|
import { existsSync as existsSync5, lstatSync, readdirSync as readdirSync3 } from "fs";
|
|
497
504
|
import { resolve as resolve4 } from "path";
|
|
505
|
+
import { Color as Color5, Table } from "termkit";
|
|
498
506
|
|
|
499
507
|
// src/helpers/dirSize.ts
|
|
500
508
|
import { readdirSync as readdirSync2, statSync } from "fs";
|
|
@@ -626,7 +634,6 @@ var parseLibraryFolder = (name) => {
|
|
|
626
634
|
if (match) return { title: match[1].trim(), year: parseInt(match[2]) };
|
|
627
635
|
return { title: name };
|
|
628
636
|
};
|
|
629
|
-
var col = (s, width) => s.padEnd(width).substring(0, width);
|
|
630
637
|
var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter, sort }) => {
|
|
631
638
|
const config = getConfig();
|
|
632
639
|
const types = (type ? [type] : DEST_TYPES2).filter((t) => config.dest[t]);
|
|
@@ -635,7 +642,7 @@ var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter
|
|
|
635
642
|
const destRoot = config.dest[t];
|
|
636
643
|
if (!existsSync5(destRoot)) {
|
|
637
644
|
console.log(`
|
|
638
|
-
${t.toUpperCase()} ${
|
|
645
|
+
${t.toUpperCase()} ${Color5.blue.encoder(destRoot)} (not found)`);
|
|
639
646
|
continue;
|
|
640
647
|
}
|
|
641
648
|
const folders = readdirSync3(destRoot).filter((f) => {
|
|
@@ -665,18 +672,29 @@ ${t.toUpperCase()} ${cosmetic5.blue.encoder(destRoot)} (not found)`);
|
|
|
665
672
|
const yearDiff = (b.year ?? 0) - (a.year ?? 0);
|
|
666
673
|
return yearDiff !== 0 ? yearDiff : a.title.localeCompare(b.title);
|
|
667
674
|
});
|
|
668
|
-
const titleW = Math.min(50, Math.max(10, ...filtered.map((e) => e.title.length)) + 2);
|
|
669
|
-
const divider = "\u2500".repeat(titleW + 44);
|
|
670
675
|
console.log(`
|
|
671
|
-
${
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
676
|
+
${Color5.yellow.encoder(t.toUpperCase())} ${Color5.blue.encoder(destRoot)}`);
|
|
677
|
+
new Table(
|
|
678
|
+
filtered.map((e) => ({
|
|
679
|
+
title: e.title,
|
|
680
|
+
year: e.year,
|
|
681
|
+
resolution: e.resolution,
|
|
682
|
+
codec: e.codec,
|
|
683
|
+
size: e.size,
|
|
684
|
+
sub: e.hasSub
|
|
685
|
+
})),
|
|
686
|
+
{
|
|
687
|
+
separator: " ",
|
|
688
|
+
columns: [
|
|
689
|
+
{ key: "title", title: "Title" },
|
|
690
|
+
{ key: "year", title: "Year", align: "right", value: (v) => v != null ? String(v) : "\u2014" },
|
|
691
|
+
{ key: "resolution", title: "Res", value: (v) => v ?? "\u2014" },
|
|
692
|
+
{ key: "codec", title: "Codec", value: (v) => v ?? "\u2014" },
|
|
693
|
+
{ key: "size", title: "Size" },
|
|
694
|
+
{ key: "sub", title: "Sub", value: (v) => v ? Color5.green.encoder("\u2713") : Color5.red.encoder("\u2717") }
|
|
695
|
+
]
|
|
696
|
+
}
|
|
697
|
+
).print();
|
|
680
698
|
console.log(`${filtered.length} of ${entries.length} item${entries.length !== 1 ? "s" : ""}`);
|
|
681
699
|
}
|
|
682
700
|
console.log();
|
|
@@ -685,9 +703,9 @@ var list_default = list;
|
|
|
685
703
|
|
|
686
704
|
// src/actions/probe.ts
|
|
687
705
|
import { spawnSync } from "child_process";
|
|
688
|
-
import cosmetic6 from "cosmetic";
|
|
689
706
|
import { existsSync as existsSync6, lstatSync as lstatSync2, readdirSync as readdirSync4 } from "fs";
|
|
690
707
|
import { resolve as resolve5 } from "path";
|
|
708
|
+
import { Color as Color6 } from "termkit";
|
|
691
709
|
var DEST_TYPES3 = ["movie", "tv", "ps3"];
|
|
692
710
|
var CODEC_MAP2 = {
|
|
693
711
|
hevc: "x265",
|
|
@@ -763,7 +781,7 @@ var probe = async ({ type, force, verbose }) => {
|
|
|
763
781
|
for (const t of types) {
|
|
764
782
|
const destRoot = config.dest[t];
|
|
765
783
|
if (!existsSync6(destRoot)) continue;
|
|
766
|
-
spinner_default.text = `scanning ${
|
|
784
|
+
spinner_default.text = `scanning ${Color6.blue.encoder(destRoot)}`;
|
|
767
785
|
const files = walkVideoFiles(destRoot);
|
|
768
786
|
for (const filePath of files) {
|
|
769
787
|
if (!force && getMediaInfo(filePath)) {
|
|
@@ -771,7 +789,7 @@ var probe = async ({ type, force, verbose }) => {
|
|
|
771
789
|
skipped++;
|
|
772
790
|
continue;
|
|
773
791
|
}
|
|
774
|
-
spinner_default.text = `probing ${
|
|
792
|
+
spinner_default.text = `probing ${Color6.blue.encoder(filePath)}`;
|
|
775
793
|
const result = runFfprobe(filePath);
|
|
776
794
|
if (!result) {
|
|
777
795
|
if (verbose) spinner_default.warn(`ffprobe failed: ${filePath}`);
|
|
@@ -791,10 +809,10 @@ var probe = async ({ type, force, verbose }) => {
|
|
|
791
809
|
var probe_default = probe;
|
|
792
810
|
|
|
793
811
|
// src/actions/rename.ts
|
|
794
|
-
import cosmetic7 from "cosmetic";
|
|
795
812
|
import { existsSync as existsSync7, lstatSync as lstatSync3, readdirSync as readdirSync5, renameSync } from "fs";
|
|
796
813
|
import { resolve as resolve6 } from "path";
|
|
797
814
|
import { rimraf } from "rimraf";
|
|
815
|
+
import { Color as Color7 } from "termkit";
|
|
798
816
|
|
|
799
817
|
// src/helpers/findSubtitle.ts
|
|
800
818
|
var LANGUAGE_ALIASES = {
|
|
@@ -855,13 +873,13 @@ var rename = async ({ dir: inputDir, type, verbose }) => {
|
|
|
855
873
|
const config = getConfig();
|
|
856
874
|
const language = config.language ?? "eng";
|
|
857
875
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
858
|
-
spinner_default.text = `renaming in ${
|
|
876
|
+
spinner_default.text = `renaming in ${Color7.blue.encoder(dir)}`;
|
|
859
877
|
spinner_default.start();
|
|
860
878
|
if (!existsSync7(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
861
879
|
const list2 = readdirSync5(dir);
|
|
862
880
|
let renamed = 0, removed = 0, skipped = 0;
|
|
863
881
|
for (const [index, entry] of list2.entries()) {
|
|
864
|
-
spinner_default.text = `renaming in ${
|
|
882
|
+
spinner_default.text = `renaming in ${Color7.blue.encoder(dir)} ${index + 1}/${list2.length}`;
|
|
865
883
|
if (!lstatSync3(resolve6(dir, entry)).isDirectory()) {
|
|
866
884
|
if (verbose) spinner_default.info(`skipped ${entry}`);
|
|
867
885
|
skipped++;
|
|
@@ -946,18 +964,18 @@ var rename = async ({ dir: inputDir, type, verbose }) => {
|
|
|
946
964
|
spinner_default.succeed(`renamed ${renamed} files`);
|
|
947
965
|
if (removed) spinner_default.info(`removed ${removed} files`);
|
|
948
966
|
spinner_default.info(`skipped ${skipped} files`);
|
|
949
|
-
spinner_default.succeed(`done in ${
|
|
967
|
+
spinner_default.succeed(`done in ${Color7.cyan.encoder(dir)}`);
|
|
950
968
|
spinner_default.stop();
|
|
951
969
|
};
|
|
952
970
|
var rename_default = rename;
|
|
953
971
|
|
|
954
972
|
// src/actions/reset.ts
|
|
955
|
-
import cosmetic8 from "cosmetic";
|
|
956
973
|
import { existsSync as existsSync8, readdirSync as readdirSync6, renameSync as renameSync2 } from "fs";
|
|
957
974
|
import { basename as basename2, dirname, resolve as resolve7, sep } from "path";
|
|
975
|
+
import { Color as Color8 } from "termkit";
|
|
958
976
|
var reset = async ({ dir: inputDir, double }) => {
|
|
959
977
|
let dir = inputDir;
|
|
960
|
-
spinner_default.text = `resetting episodes in ${
|
|
978
|
+
spinner_default.text = `resetting episodes in ${Color8.blue.encoder(dir)}`;
|
|
961
979
|
spinner_default.start();
|
|
962
980
|
dir = resolve7(dir);
|
|
963
981
|
if (!existsSync8(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
@@ -986,7 +1004,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
986
1004
|
const episodeFormat = getConfig().format?.episode;
|
|
987
1005
|
let renamed = 0, skipped = other.length;
|
|
988
1006
|
for (const [index, i] of sublist.entries()) {
|
|
989
|
-
spinner_default.text = `resetting episodes in ${
|
|
1007
|
+
spinner_default.text = `resetting episodes in ${Color8.blue.encoder(dir)} ${index}/${list2.length}`;
|
|
990
1008
|
const ext = i.match(/([^.]+$)/)?.[0];
|
|
991
1009
|
const episode = double ? index * 2 + 1 : index + 1;
|
|
992
1010
|
const name = `${formatEpisode(seasonNum, episode, episodeFormat, double, showTitle)}.${ext}`;
|
|
@@ -999,16 +1017,15 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
999
1017
|
}
|
|
1000
1018
|
spinner_default.succeed(`renamed ${renamed} files`);
|
|
1001
1019
|
spinner_default.info(`skipped ${skipped} files`);
|
|
1002
|
-
spinner_default.succeed(`done in ${
|
|
1020
|
+
spinner_default.succeed(`done in ${Color8.cyan.encoder(dir)}`);
|
|
1003
1021
|
spinner_default.stop();
|
|
1004
1022
|
};
|
|
1005
1023
|
var reset_default = reset;
|
|
1006
1024
|
|
|
1007
1025
|
// src/actions/scan.ts
|
|
1008
|
-
import cosmetic9 from "cosmetic";
|
|
1009
1026
|
import { cpSync, existsSync as existsSync9, linkSync, lstatSync as lstatSync4, mkdirSync as mkdirSync3, readdirSync as readdirSync7, renameSync as renameSync3, rmSync as rmSync2, statSync as statSync2 } from "fs";
|
|
1010
1027
|
import { dirname as dirname2, resolve as resolve8 } from "path";
|
|
1011
|
-
import { Select } from "
|
|
1028
|
+
import { Color as Color9, Select } from "termkit";
|
|
1012
1029
|
|
|
1013
1030
|
// src/helpers/detectEdition.ts
|
|
1014
1031
|
var EDITIONS = [
|
|
@@ -1174,10 +1191,10 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto }) => {
|
|
|
1174
1191
|
let imported = 0, skipped = 0;
|
|
1175
1192
|
for (const source of config.sources) {
|
|
1176
1193
|
if (!existsSync9(source)) {
|
|
1177
|
-
spinner_default.warn(`source not found: ${
|
|
1194
|
+
spinner_default.warn(`source not found: ${Color9.blue.encoder(source)}`);
|
|
1178
1195
|
continue;
|
|
1179
1196
|
}
|
|
1180
|
-
spinner_default.text = `scanning ${
|
|
1197
|
+
spinner_default.text = `scanning ${Color9.blue.encoder(source)}`;
|
|
1181
1198
|
for (const entry of readdirSync7(source)) {
|
|
1182
1199
|
const entryPath = resolve8(source, entry);
|
|
1183
1200
|
const isDir = lstatSync4(entryPath).isDirectory();
|
|
@@ -1411,8 +1428,8 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto }) => {
|
|
|
1411
1428
|
var scan_default = scan;
|
|
1412
1429
|
|
|
1413
1430
|
// src/actions/undo.ts
|
|
1414
|
-
import cosmetic10 from "cosmetic";
|
|
1415
1431
|
import { renameSync as renameSync4 } from "fs";
|
|
1432
|
+
import { Color as Color10 } from "termkit";
|
|
1416
1433
|
var undo = async () => {
|
|
1417
1434
|
spinner_default.start();
|
|
1418
1435
|
const records = getLastSession();
|
|
@@ -1424,7 +1441,7 @@ var undo = async () => {
|
|
|
1424
1441
|
let undone = 0;
|
|
1425
1442
|
for (const record of records) {
|
|
1426
1443
|
renameSync4(record.newPath, record.oldPath);
|
|
1427
|
-
spinner_default.succeed(`${
|
|
1444
|
+
spinner_default.succeed(`${Color10.cyan.encoder(record.newPath)} \u2192 ${Color10.blue.encoder(record.oldPath)}`);
|
|
1428
1445
|
undone++;
|
|
1429
1446
|
}
|
|
1430
1447
|
deleteSession(records[0].sessionId);
|
|
@@ -1435,9 +1452,9 @@ var undo_default = undo;
|
|
|
1435
1452
|
|
|
1436
1453
|
// src/actions/watch.ts
|
|
1437
1454
|
import chokidar from "chokidar";
|
|
1438
|
-
import cosmetic11 from "cosmetic";
|
|
1439
1455
|
import { cpSync as cpSync2, existsSync as existsSync10, linkSync as linkSync2, lstatSync as lstatSync5, mkdirSync as mkdirSync4, readdirSync as readdirSync8, renameSync as renameSync5, rmSync as rmSync3, statSync as statSync3 } from "fs";
|
|
1440
1456
|
import { basename as basename3, dirname as dirname3, resolve as resolve9 } from "path";
|
|
1457
|
+
import { Color as Color11 } from "termkit";
|
|
1441
1458
|
var sameDev2 = (a, b) => {
|
|
1442
1459
|
try {
|
|
1443
1460
|
let bExisting = b;
|
|
@@ -1508,7 +1525,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
|
|
|
1508
1525
|
}
|
|
1509
1526
|
moveItem(entryPath, destPath);
|
|
1510
1527
|
recordImport(sessionId, entryPath, destPath, "move");
|
|
1511
|
-
spinner_default.succeed(`imported ${
|
|
1528
|
+
spinner_default.succeed(`imported ${Color11.cyan.encoder(destName)}`);
|
|
1512
1529
|
return;
|
|
1513
1530
|
}
|
|
1514
1531
|
const parsed = parseDownloadName(entry);
|
|
@@ -1581,7 +1598,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
|
|
|
1581
1598
|
if (isDir) rmSync3(entryPath, { recursive: true, force: true });
|
|
1582
1599
|
}
|
|
1583
1600
|
recordImport(sessionId, entryPath, seasonPath, mode);
|
|
1584
|
-
spinner_default.succeed(`imported ${
|
|
1601
|
+
spinner_default.succeed(`imported ${Color11.cyan.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
|
|
1585
1602
|
return;
|
|
1586
1603
|
}
|
|
1587
1604
|
const edition = detectEdition(entry);
|
|
@@ -1638,7 +1655,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
|
|
|
1638
1655
|
}
|
|
1639
1656
|
recordImport(sessionId, entryPath, destFolder, "move");
|
|
1640
1657
|
}
|
|
1641
|
-
spinner_default.succeed(`imported ${
|
|
1658
|
+
spinner_default.succeed(`imported ${Color11.cyan.encoder(folderName)}`);
|
|
1642
1659
|
};
|
|
1643
1660
|
var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
1644
1661
|
const config = getConfig();
|
|
@@ -1669,7 +1686,7 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
|
1669
1686
|
watcher.on("add", handle);
|
|
1670
1687
|
spinner_default.start();
|
|
1671
1688
|
spinner_default.succeed(`watching ${config.sources.length} source${config.sources.length !== 1 ? "s" : ""}`);
|
|
1672
|
-
for (const s of config.sources) spinner_default.info(` ${
|
|
1689
|
+
for (const s of config.sources) spinner_default.info(` ${Color11.blue.encoder(s)}`);
|
|
1673
1690
|
spinner_default.stop();
|
|
1674
1691
|
process.stdin.resume();
|
|
1675
1692
|
};
|
|
@@ -1679,12 +1696,12 @@ export {
|
|
|
1679
1696
|
DEFAULT_MOVIE_FORMAT,
|
|
1680
1697
|
DEFAULT_SEASON_FORMAT,
|
|
1681
1698
|
clean_default as clean,
|
|
1682
|
-
configAdd,
|
|
1683
|
-
configRemove,
|
|
1684
1699
|
configSet,
|
|
1685
1700
|
configShow,
|
|
1686
1701
|
deleteImport,
|
|
1687
1702
|
deleteSession,
|
|
1703
|
+
destAdd,
|
|
1704
|
+
destRemove,
|
|
1688
1705
|
detectEdition,
|
|
1689
1706
|
differences_default as differences,
|
|
1690
1707
|
formatEpisode,
|
|
@@ -1709,6 +1726,8 @@ export {
|
|
|
1709
1726
|
reset_default as reset,
|
|
1710
1727
|
saveConfig,
|
|
1711
1728
|
scan_default as scan,
|
|
1729
|
+
sourceAdd,
|
|
1730
|
+
sourceRemove,
|
|
1712
1731
|
titleCase_default as titleCase,
|
|
1713
1732
|
undo_default as undo,
|
|
1714
1733
|
upsertMediaInfo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "reelsort",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI to rename, organize, and manage your movie and TV library — Plex-compatible naming, hardlink support, and automated watch mode.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"media",
|
|
@@ -71,11 +71,9 @@
|
|
|
71
71
|
"dependencies": {
|
|
72
72
|
"better-sqlite3": "^12.10.0",
|
|
73
73
|
"chokidar": "^5.0.0",
|
|
74
|
-
"cosmetic": "^1.4.0",
|
|
75
74
|
"rimraf": "^6.1.3",
|
|
76
75
|
"roman-numeral": "^0.2.6",
|
|
77
|
-
"termkit": "^2.0
|
|
78
|
-
"termpulse": "^1.1.3",
|
|
76
|
+
"termkit": "^2.2.0",
|
|
79
77
|
"to-title-case": "^1.0.0"
|
|
80
78
|
},
|
|
81
79
|
"devDependencies": {
|