reelsort 0.2.7 → 0.2.8
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 +320 -326
- package/dist/index.js +247 -259
- package/dist/index.mjs +214 -226
- package/package.json +2 -2
package/dist/cli.js
CHANGED
|
@@ -23,13 +23,16 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
|
|
|
23
23
|
mod
|
|
24
24
|
));
|
|
25
25
|
|
|
26
|
-
// src/
|
|
26
|
+
// src/cli.ts
|
|
27
27
|
var import_termkit19 = require("termkit");
|
|
28
28
|
|
|
29
|
+
// src/program.ts
|
|
30
|
+
var import_termkit18 = require("termkit");
|
|
31
|
+
|
|
29
32
|
// src/actions/add.ts
|
|
30
33
|
var import_fs3 = require("fs");
|
|
31
34
|
var import_path3 = require("path");
|
|
32
|
-
var
|
|
35
|
+
var import_termkit = require("termkit");
|
|
33
36
|
|
|
34
37
|
// src/config.ts
|
|
35
38
|
var import_fs = require("fs");
|
|
@@ -286,60 +289,20 @@ var searchTv = async (title, apiKey) => {
|
|
|
286
289
|
}
|
|
287
290
|
};
|
|
288
291
|
|
|
289
|
-
// src/refs/spinner.ts
|
|
290
|
-
var import_termkit = require("termkit");
|
|
291
|
-
var Spinner = class {
|
|
292
|
-
spinner;
|
|
293
|
-
constructor() {
|
|
294
|
-
this.spinner = new import_termkit.Spinner();
|
|
295
|
-
}
|
|
296
|
-
get text() {
|
|
297
|
-
return this.spinner.text;
|
|
298
|
-
}
|
|
299
|
-
set text(t) {
|
|
300
|
-
this.spinner.text = t;
|
|
301
|
-
}
|
|
302
|
-
start(s) {
|
|
303
|
-
if (s) this.spinner.text = s;
|
|
304
|
-
this.spinner.start();
|
|
305
|
-
return this;
|
|
306
|
-
}
|
|
307
|
-
info(s) {
|
|
308
|
-
this.spinner.info(s);
|
|
309
|
-
return this;
|
|
310
|
-
}
|
|
311
|
-
warn(s) {
|
|
312
|
-
this.spinner.warn(s);
|
|
313
|
-
return this;
|
|
314
|
-
}
|
|
315
|
-
fail(s) {
|
|
316
|
-
this.spinner.fail(s);
|
|
317
|
-
return this;
|
|
318
|
-
}
|
|
319
|
-
succeed(s) {
|
|
320
|
-
this.spinner.succeed(s);
|
|
321
|
-
return this;
|
|
322
|
-
}
|
|
323
|
-
stop() {
|
|
324
|
-
this.spinner.stop();
|
|
325
|
-
return this;
|
|
326
|
-
}
|
|
327
|
-
};
|
|
328
|
-
var spinner_default = new Spinner();
|
|
329
|
-
|
|
330
292
|
// src/actions/add.ts
|
|
293
|
+
var spinner = new import_termkit.Spinner();
|
|
331
294
|
var add = async ({ name }) => {
|
|
332
295
|
const config = getConfig();
|
|
333
296
|
if (!config.tmdbApiKey) throw new Error("TMDb API key required \u2014 run: reelsort config set tmdb-key <key>");
|
|
334
297
|
const destRoot = config.dest.tv;
|
|
335
298
|
if (!destRoot) throw new Error("no TV destination configured \u2014 run: reelsort config set dest tv <dir>");
|
|
336
|
-
|
|
299
|
+
spinner.update(`searching TMDb for "${name}"`).start();
|
|
337
300
|
const results = await searchTv(name, config.tmdbApiKey);
|
|
338
|
-
|
|
301
|
+
spinner.stop();
|
|
339
302
|
if (results.length === 0) throw new Error(`no TMDb results for "${name}"`);
|
|
340
303
|
let picked = results.length === 1 ? results[0] : null;
|
|
341
304
|
if (!picked) {
|
|
342
|
-
const select = new
|
|
305
|
+
const select = new import_termkit.Select();
|
|
343
306
|
const items = results.map((r) => ({
|
|
344
307
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
345
308
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
@@ -353,15 +316,16 @@ var add = async ({ name }) => {
|
|
|
353
316
|
const showPath = (0, import_path3.resolve)(destRoot, folderName);
|
|
354
317
|
(0, import_fs3.mkdirSync)(showPath, { recursive: true });
|
|
355
318
|
upsertShow(showPath, picked.id, picked.title);
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
319
|
+
spinner.start();
|
|
320
|
+
spinner.succeed(`added ${import_termkit.Color.green.encoder(folderName)}`);
|
|
321
|
+
spinner.stop();
|
|
359
322
|
};
|
|
360
323
|
var add_default = add;
|
|
361
324
|
|
|
362
325
|
// src/actions/clean.ts
|
|
363
326
|
var import_fs4 = require("fs");
|
|
364
|
-
var
|
|
327
|
+
var import_termkit2 = require("termkit");
|
|
328
|
+
var spinner2 = new import_termkit2.Spinner();
|
|
365
329
|
var parseOlderThan = (s) => {
|
|
366
330
|
const match = s.match(/^(\d+)([dhm])$/);
|
|
367
331
|
if (!match) return null;
|
|
@@ -371,11 +335,11 @@ var parseOlderThan = (s) => {
|
|
|
371
335
|
return ms;
|
|
372
336
|
};
|
|
373
337
|
var clean = async ({ dryRun, olderThan }) => {
|
|
374
|
-
|
|
338
|
+
spinner2.start();
|
|
375
339
|
const imports = getCleanableImports();
|
|
376
340
|
if (imports.length === 0) {
|
|
377
|
-
|
|
378
|
-
|
|
341
|
+
spinner2.info("nothing to clean");
|
|
342
|
+
spinner2.stop();
|
|
379
343
|
return;
|
|
380
344
|
}
|
|
381
345
|
const cutoffMs = olderThan ? parseOlderThan(olderThan) : null;
|
|
@@ -394,30 +358,30 @@ var clean = async ({ dryRun, olderThan }) => {
|
|
|
394
358
|
continue;
|
|
395
359
|
}
|
|
396
360
|
if (dryRun) {
|
|
397
|
-
|
|
361
|
+
spinner2.succeed(`[dry] would remove ${import_termkit2.Color.white.encoder(imp.sourcePath)}`);
|
|
398
362
|
cleaned++;
|
|
399
363
|
continue;
|
|
400
364
|
}
|
|
401
365
|
try {
|
|
402
366
|
(0, import_fs4.rmSync)(imp.sourcePath, { recursive: true, force: true });
|
|
403
367
|
deleteImport(imp.id);
|
|
404
|
-
|
|
368
|
+
spinner2.succeed(`removed ${import_termkit2.Color.white.encoder(imp.sourcePath)}`);
|
|
405
369
|
cleaned++;
|
|
406
370
|
} catch {
|
|
407
|
-
|
|
371
|
+
spinner2.warn(`locked or inaccessible, skipped: ${import_termkit2.Color.white.encoder(imp.sourcePath)}`);
|
|
408
372
|
skipped++;
|
|
409
373
|
}
|
|
410
374
|
}
|
|
411
|
-
|
|
412
|
-
if (skipped)
|
|
413
|
-
|
|
375
|
+
spinner2.succeed(`cleaned ${cleaned} items`);
|
|
376
|
+
if (skipped) spinner2.info(`skipped ${skipped} items`);
|
|
377
|
+
spinner2.stop();
|
|
414
378
|
};
|
|
415
379
|
var clean_default = clean;
|
|
416
380
|
|
|
417
381
|
// src/actions/config.ts
|
|
418
382
|
var import_fs5 = require("fs");
|
|
419
383
|
var import_path4 = require("path");
|
|
420
|
-
var
|
|
384
|
+
var import_termkit3 = require("termkit");
|
|
421
385
|
|
|
422
386
|
// src/helpers/formatEpisode.ts
|
|
423
387
|
var DEFAULT_EPISODE_FORMAT = "{s}x{ee} - {title}";
|
|
@@ -436,6 +400,7 @@ var formatEpisode = (season, episode, format = DEFAULT_EPISODE_FORMAT, double =
|
|
|
436
400
|
};
|
|
437
401
|
|
|
438
402
|
// src/actions/config.ts
|
|
403
|
+
var spinner3 = new import_termkit3.Spinner();
|
|
439
404
|
var DEST_TYPES = ["movie", "tv", "ps3", "book"];
|
|
440
405
|
var getSourceEntries = (sources) => {
|
|
441
406
|
const entries = [];
|
|
@@ -459,27 +424,27 @@ var sourceAdd = async ({ dir }) => {
|
|
|
459
424
|
const resolved = (0, import_path4.resolve)(dir);
|
|
460
425
|
const config = getConfig();
|
|
461
426
|
if (config.sources.includes(resolved)) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
427
|
+
spinner3.start();
|
|
428
|
+
spinner3.info(`source already configured: ${import_termkit3.Color.white.encoder(resolved)}`);
|
|
429
|
+
spinner3.stop();
|
|
465
430
|
return;
|
|
466
431
|
}
|
|
467
432
|
config.sources.push(resolved);
|
|
468
433
|
saveConfig(config);
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
434
|
+
spinner3.start();
|
|
435
|
+
spinner3.succeed(`added source: ${import_termkit3.Color.white.encoder(resolved)}`);
|
|
436
|
+
spinner3.stop();
|
|
472
437
|
};
|
|
473
438
|
var sourceRemove = async ({ dir }) => {
|
|
474
439
|
const config = getConfig();
|
|
475
440
|
if (!dir) {
|
|
476
441
|
if (config.sources.length === 0) {
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
442
|
+
spinner3.start();
|
|
443
|
+
spinner3.warn("no sources configured");
|
|
444
|
+
spinner3.stop();
|
|
480
445
|
return;
|
|
481
446
|
}
|
|
482
|
-
const select = new
|
|
447
|
+
const select = new import_termkit3.Select();
|
|
483
448
|
const picked = await select.ask("Which source do you want to remove?", config.sources.map((s) => ({ label: s, value: s })));
|
|
484
449
|
if (!picked) return;
|
|
485
450
|
dir = picked.value;
|
|
@@ -487,16 +452,16 @@ var sourceRemove = async ({ dir }) => {
|
|
|
487
452
|
const resolved = (0, import_path4.resolve)(dir);
|
|
488
453
|
const index = config.sources.indexOf(resolved);
|
|
489
454
|
if (index === -1) {
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
455
|
+
spinner3.start();
|
|
456
|
+
spinner3.warn(`source not found: ${import_termkit3.Color.white.encoder(resolved)}`);
|
|
457
|
+
spinner3.stop();
|
|
493
458
|
return;
|
|
494
459
|
}
|
|
495
460
|
config.sources.splice(index, 1);
|
|
496
461
|
saveConfig(config);
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
462
|
+
spinner3.start();
|
|
463
|
+
spinner3.succeed(`removed source: ${import_termkit3.Color.white.encoder(resolved)}`);
|
|
464
|
+
spinner3.stop();
|
|
500
465
|
};
|
|
501
466
|
var destAdd = async ({ type, dir }) => {
|
|
502
467
|
if (!DEST_TYPES.includes(type)) {
|
|
@@ -506,21 +471,21 @@ var destAdd = async ({ type, dir }) => {
|
|
|
506
471
|
const config = getConfig();
|
|
507
472
|
config.dest[type] = resolved;
|
|
508
473
|
saveConfig(config);
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
474
|
+
spinner3.start();
|
|
475
|
+
spinner3.succeed(`set ${type} destination: ${import_termkit3.Color.green.encoder(resolved)}`);
|
|
476
|
+
spinner3.stop();
|
|
512
477
|
};
|
|
513
478
|
var destRemove = async ({ type }) => {
|
|
514
479
|
const config = getConfig();
|
|
515
480
|
if (!type) {
|
|
516
481
|
const configured = DEST_TYPES.filter((t) => config.dest[t]);
|
|
517
482
|
if (configured.length === 0) {
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
483
|
+
spinner3.start();
|
|
484
|
+
spinner3.warn("no destinations configured");
|
|
485
|
+
spinner3.stop();
|
|
521
486
|
return;
|
|
522
487
|
}
|
|
523
|
-
const select = new
|
|
488
|
+
const select = new import_termkit3.Select();
|
|
524
489
|
const picked = await select.ask("Which destination do you want to remove?", configured.map((t) => ({ label: `${t.padEnd(6)} ${config.dest[t]}`, value: t })));
|
|
525
490
|
if (!picked) return;
|
|
526
491
|
type = picked.value;
|
|
@@ -529,16 +494,16 @@ var destRemove = async ({ type }) => {
|
|
|
529
494
|
throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
|
|
530
495
|
}
|
|
531
496
|
if (!config.dest[type]) {
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
497
|
+
spinner3.start();
|
|
498
|
+
spinner3.warn(`no ${type} destination configured`);
|
|
499
|
+
spinner3.stop();
|
|
535
500
|
return;
|
|
536
501
|
}
|
|
537
502
|
delete config.dest[type];
|
|
538
503
|
saveConfig(config);
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
504
|
+
spinner3.start();
|
|
505
|
+
spinner3.succeed(`removed ${type} destination`);
|
|
506
|
+
spinner3.stop();
|
|
542
507
|
};
|
|
543
508
|
var ignore = async ({ name }) => {
|
|
544
509
|
const config = getConfig();
|
|
@@ -547,12 +512,12 @@ var ignore = async ({ name }) => {
|
|
|
547
512
|
if (names.length === 0) {
|
|
548
513
|
const entries = getSourceEntries(config.sources);
|
|
549
514
|
if (entries.length === 0) {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
515
|
+
spinner3.start();
|
|
516
|
+
spinner3.warn("no files found in configured sources");
|
|
517
|
+
spinner3.stop();
|
|
553
518
|
return;
|
|
554
519
|
}
|
|
555
|
-
const ms = new
|
|
520
|
+
const ms = new import_termkit3.MultiSelect({ allowSkip: true, search: true, maxHeight: 20 });
|
|
556
521
|
const items = entries.map((e) => ({ label: e }));
|
|
557
522
|
const picked = await ms.ask("Select files to ignore during scan:", items);
|
|
558
523
|
if (!picked || picked.length === 0) return;
|
|
@@ -566,67 +531,67 @@ var ignore = async ({ name }) => {
|
|
|
566
531
|
}
|
|
567
532
|
}
|
|
568
533
|
if (added.length === 0) {
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
534
|
+
spinner3.start();
|
|
535
|
+
spinner3.info("all selected files are already ignored");
|
|
536
|
+
spinner3.stop();
|
|
572
537
|
return;
|
|
573
538
|
}
|
|
574
539
|
saveConfig(config);
|
|
575
|
-
|
|
576
|
-
for (const n of added)
|
|
577
|
-
|
|
540
|
+
spinner3.start();
|
|
541
|
+
for (const n of added) spinner3.succeed(`ignoring: ${import_termkit3.Color.white.encoder(n)}`);
|
|
542
|
+
spinner3.stop();
|
|
578
543
|
};
|
|
579
544
|
var ignoreRemove = async ({ name }) => {
|
|
580
545
|
const config = getConfig();
|
|
581
546
|
const list2 = config.ignore ?? [];
|
|
582
547
|
if (!name) {
|
|
583
548
|
if (list2.length === 0) {
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
549
|
+
spinner3.start();
|
|
550
|
+
spinner3.warn("ignore list is empty");
|
|
551
|
+
spinner3.stop();
|
|
587
552
|
return;
|
|
588
553
|
}
|
|
589
|
-
const ms = new
|
|
554
|
+
const ms = new import_termkit3.MultiSelect({ allowSkip: true, search: true, maxHeight: 20 });
|
|
590
555
|
const items = list2.map((n) => ({ label: n }));
|
|
591
556
|
const picked = await ms.ask("Select files to remove from ignore list:", items);
|
|
592
557
|
if (!picked || picked.length === 0) return;
|
|
593
558
|
const toRemove = new Set(picked.map((p) => p.label));
|
|
594
559
|
config.ignore = list2.filter((n) => !toRemove.has(n));
|
|
595
560
|
saveConfig(config);
|
|
596
|
-
|
|
597
|
-
for (const n of [...toRemove])
|
|
598
|
-
|
|
561
|
+
spinner3.start();
|
|
562
|
+
for (const n of [...toRemove]) spinner3.succeed(`removed from ignore list: ${import_termkit3.Color.white.encoder(n)}`);
|
|
563
|
+
spinner3.stop();
|
|
599
564
|
return;
|
|
600
565
|
}
|
|
601
566
|
const index = list2.indexOf(name);
|
|
602
567
|
if (index === -1) {
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
568
|
+
spinner3.start();
|
|
569
|
+
spinner3.warn(`not in ignore list: ${import_termkit3.Color.white.encoder(name)}`);
|
|
570
|
+
spinner3.stop();
|
|
606
571
|
return;
|
|
607
572
|
}
|
|
608
573
|
config.ignore.splice(index, 1);
|
|
609
574
|
saveConfig(config);
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
575
|
+
spinner3.start();
|
|
576
|
+
spinner3.succeed(`removed from ignore list: ${import_termkit3.Color.white.encoder(name)}`);
|
|
577
|
+
spinner3.stop();
|
|
613
578
|
};
|
|
614
579
|
var configSet = async ({ key, subkey, value }) => {
|
|
615
580
|
const config = getConfig();
|
|
616
581
|
if (key === "language") {
|
|
617
582
|
config.language = subkey;
|
|
618
583
|
saveConfig(config);
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
584
|
+
spinner3.start();
|
|
585
|
+
spinner3.succeed(`set subtitle language: ${import_termkit3.Color.green.encoder(subkey)}`);
|
|
586
|
+
spinner3.stop();
|
|
622
587
|
return;
|
|
623
588
|
}
|
|
624
589
|
if (key === "tmdb-key") {
|
|
625
590
|
config.tmdbApiKey = subkey;
|
|
626
591
|
saveConfig(config);
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
592
|
+
spinner3.start();
|
|
593
|
+
spinner3.succeed(`set TMDb API key`);
|
|
594
|
+
spinner3.stop();
|
|
630
595
|
return;
|
|
631
596
|
}
|
|
632
597
|
if (key === "format") {
|
|
@@ -646,9 +611,9 @@ var configSet = async ({ key, subkey, value }) => {
|
|
|
646
611
|
throw new Error(`unknown format key '${subkey}', expected: movie, episode, season`);
|
|
647
612
|
}
|
|
648
613
|
saveConfig(config);
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
614
|
+
spinner3.start();
|
|
615
|
+
spinner3.succeed(`set ${subkey} format: ${import_termkit3.Color.green.encoder(value ?? subkey)}`);
|
|
616
|
+
spinner3.stop();
|
|
652
617
|
return;
|
|
653
618
|
}
|
|
654
619
|
throw new Error(`unknown key '${key}', expected: language, tmdb-key, format`);
|
|
@@ -659,7 +624,7 @@ var configShow = async () => {
|
|
|
659
624
|
if (config.sources.length === 0) {
|
|
660
625
|
console.log(" (none)");
|
|
661
626
|
} else {
|
|
662
|
-
for (const s of config.sources) console.log(` ${
|
|
627
|
+
for (const s of config.sources) console.log(` ${import_termkit3.Color.white.encoder(s)}`);
|
|
663
628
|
}
|
|
664
629
|
console.log("\nDestinations:");
|
|
665
630
|
const entries = DEST_TYPES.map((t) => ({ type: t, path: config.dest[t] })).filter((e) => e.path);
|
|
@@ -667,20 +632,20 @@ var configShow = async () => {
|
|
|
667
632
|
console.log(" (none)");
|
|
668
633
|
} else {
|
|
669
634
|
for (const { type, path } of entries) {
|
|
670
|
-
console.log(` ${type.padEnd(6)} ${
|
|
635
|
+
console.log(` ${type.padEnd(6)} ${import_termkit3.Color.green.encoder(path)}`);
|
|
671
636
|
}
|
|
672
637
|
}
|
|
673
638
|
console.log(`
|
|
674
|
-
Subtitle language: ${
|
|
675
|
-
console.log(`TMDb API key: ${config.tmdbApiKey ?
|
|
676
|
-
console.log(`Movie format: ${
|
|
677
|
-
console.log(`Episode format: ${
|
|
678
|
-
console.log(`Season folder: ${
|
|
639
|
+
Subtitle language: ${import_termkit3.Color.green.encoder(config.language ?? "eng (default)")}`);
|
|
640
|
+
console.log(`TMDb API key: ${config.tmdbApiKey ? import_termkit3.Color.green.encoder("configured") : import_termkit3.Color.red.encoder("not set")}`);
|
|
641
|
+
console.log(`Movie format: ${import_termkit3.Color.green.encoder(config.format?.movie ?? DEFAULT_MOVIE_FORMAT + " (default)")}`);
|
|
642
|
+
console.log(`Episode format: ${import_termkit3.Color.green.encoder(config.format?.episode ?? DEFAULT_EPISODE_FORMAT + " (default)")}`);
|
|
643
|
+
console.log(`Season folder: ${import_termkit3.Color.green.encoder(config.format?.season ?? DEFAULT_SEASON_FORMAT + " (default)")}`);
|
|
679
644
|
console.log("\nIgnored files:");
|
|
680
645
|
if (!config.ignore || config.ignore.length === 0) {
|
|
681
646
|
console.log(" (none)");
|
|
682
647
|
} else {
|
|
683
|
-
for (const name of config.ignore) console.log(` ${
|
|
648
|
+
for (const name of config.ignore) console.log(` ${import_termkit3.Color.white.encoder(name)}`);
|
|
684
649
|
}
|
|
685
650
|
console.log();
|
|
686
651
|
};
|
|
@@ -688,12 +653,13 @@ Subtitle language: ${import_termkit4.Color.green.encoder(config.language ?? "eng
|
|
|
688
653
|
// src/actions/differences.ts
|
|
689
654
|
var import_fs6 = require("fs");
|
|
690
655
|
var import_path5 = require("path");
|
|
691
|
-
var
|
|
656
|
+
var import_termkit4 = require("termkit");
|
|
657
|
+
var spinner4 = new import_termkit4.Spinner();
|
|
692
658
|
var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore: ignore2 }) => {
|
|
693
659
|
let dir1 = rawDir1;
|
|
694
660
|
let dir2 = rawDir2;
|
|
695
|
-
|
|
696
|
-
|
|
661
|
+
spinner4.update(`checking differences between ${import_termkit4.Color.white.encoder(dir1)} and ${import_termkit4.Color.white.encoder(dir2)}`);
|
|
662
|
+
spinner4.start();
|
|
697
663
|
dir1 = (0, import_path5.resolve)(dir1);
|
|
698
664
|
dir2 = (0, import_path5.resolve)(dir2);
|
|
699
665
|
if (!(0, import_fs6.existsSync)(dir1)) throw new Error(`dir1 ${dir1} does not exist`);
|
|
@@ -728,27 +694,28 @@ var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore: ignore2 }
|
|
|
728
694
|
removed.push(l);
|
|
729
695
|
}
|
|
730
696
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
for (const i of added) console.log(`${
|
|
736
|
-
for (const i of removed) console.log(`${
|
|
697
|
+
spinner4.succeed(`checked differences between ${import_termkit4.Color.white.encoder(dir1)} and ${import_termkit4.Color.white.encoder(dir2)}`);
|
|
698
|
+
spinner4.succeed(`found ${added.length} added files`);
|
|
699
|
+
spinner4.succeed(`found ${removed.length} removed files`);
|
|
700
|
+
spinner4.stop();
|
|
701
|
+
for (const i of added) console.log(`${import_termkit4.Color.green.encoder("added")} ${i}`);
|
|
702
|
+
for (const i of removed) console.log(`${import_termkit4.Color.red.encoder("removed")} ${i}`);
|
|
737
703
|
};
|
|
738
704
|
var differences_default = differences;
|
|
739
705
|
|
|
740
706
|
// src/actions/ended.ts
|
|
741
|
-
var
|
|
707
|
+
var import_termkit5 = require("termkit");
|
|
708
|
+
var spinner5 = new import_termkit5.Spinner();
|
|
742
709
|
var ended = async ({ remove }) => {
|
|
743
710
|
const shows2 = getShows();
|
|
744
711
|
const candidates = shows2.filter((s) => remove ? s.ended : !s.ended);
|
|
745
712
|
if (candidates.length === 0) {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
713
|
+
spinner5.start();
|
|
714
|
+
spinner5.info(remove ? "no ended shows to restore" : "no active shows to mark as ended");
|
|
715
|
+
spinner5.stop();
|
|
749
716
|
return;
|
|
750
717
|
}
|
|
751
|
-
const select = new
|
|
718
|
+
const select = new import_termkit5.Select();
|
|
752
719
|
const items = candidates.map((s) => ({
|
|
753
720
|
label: s.path.split("/").pop() ?? s.path,
|
|
754
721
|
path: s.path
|
|
@@ -757,19 +724,19 @@ var ended = async ({ remove }) => {
|
|
|
757
724
|
const picked = await select.ask(prompt, items);
|
|
758
725
|
if (!picked) return;
|
|
759
726
|
setShowEnded(picked.path, !remove);
|
|
760
|
-
|
|
727
|
+
spinner5.start();
|
|
761
728
|
if (remove) {
|
|
762
|
-
|
|
729
|
+
spinner5.succeed(`marked as active: ${import_termkit5.Color.green.encoder(picked.label)}`);
|
|
763
730
|
} else {
|
|
764
|
-
|
|
731
|
+
spinner5.succeed(`marked as ended: ${import_termkit5.Color.green.encoder(picked.label)}`);
|
|
765
732
|
}
|
|
766
|
-
|
|
733
|
+
spinner5.stop();
|
|
767
734
|
};
|
|
768
735
|
var ended_default = ended;
|
|
769
736
|
|
|
770
737
|
// src/actions/history.ts
|
|
771
738
|
var import_path6 = require("path");
|
|
772
|
-
var
|
|
739
|
+
var import_termkit6 = require("termkit");
|
|
773
740
|
var history = async ({ limit, imports }) => {
|
|
774
741
|
if (imports) {
|
|
775
742
|
const sessions = getImportHistory(limit ?? 10);
|
|
@@ -781,11 +748,11 @@ var history = async ({ limit, imports }) => {
|
|
|
781
748
|
const date = new Date(session.sessionId);
|
|
782
749
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
783
750
|
console.log(`
|
|
784
|
-
${
|
|
751
|
+
${import_termkit6.Color.yellow.encoder(label)} (${session.records.length} item${session.records.length !== 1 ? "s" : ""})`);
|
|
785
752
|
for (const r of session.records) {
|
|
786
753
|
const src = (0, import_path6.basename)(r.sourcePath);
|
|
787
|
-
const dest =
|
|
788
|
-
const mode = r.mode !== "move" ? ` ${
|
|
754
|
+
const dest = import_termkit6.Color.green.encoder(r.destinationPath);
|
|
755
|
+
const mode = r.mode !== "move" ? ` ${import_termkit6.Color.white.encoder(`[${r.mode}]`)}` : "";
|
|
789
756
|
console.log(` ${src} \u2192 ${dest}${mode}`);
|
|
790
757
|
}
|
|
791
758
|
}
|
|
@@ -800,11 +767,11 @@ ${import_termkit7.Color.yellow.encoder(label)} (${session.records.length} item$
|
|
|
800
767
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
801
768
|
const folders = session.records.filter((r) => (0, import_path6.extname)(r.newPath) === "");
|
|
802
769
|
console.log(`
|
|
803
|
-
${
|
|
770
|
+
${import_termkit6.Color.yellow.encoder(label)} (${folders.length} item${folders.length !== 1 ? "s" : ""})`);
|
|
804
771
|
for (const r of folders) {
|
|
805
772
|
const oldName = (0, import_path6.basename)(r.oldPath);
|
|
806
773
|
const newName = (0, import_path6.basename)(r.newPath);
|
|
807
|
-
console.log(` ${
|
|
774
|
+
console.log(` ${import_termkit6.Color.white.encoder(oldName)} \u2192 ${import_termkit6.Color.green.encoder(newName)}`);
|
|
808
775
|
}
|
|
809
776
|
}
|
|
810
777
|
}
|
|
@@ -815,7 +782,8 @@ var history_default = history;
|
|
|
815
782
|
// src/actions/link.ts
|
|
816
783
|
var import_fs7 = require("fs");
|
|
817
784
|
var import_path7 = require("path");
|
|
818
|
-
var
|
|
785
|
+
var import_termkit7 = require("termkit");
|
|
786
|
+
var spinner6 = new import_termkit7.Spinner();
|
|
819
787
|
var parseShowTitle = (folderName) => {
|
|
820
788
|
const withoutYear = folderName.replace(/\s*\(\d{4}\)\s*$/, "").trim();
|
|
821
789
|
return withoutYear || folderName;
|
|
@@ -842,49 +810,49 @@ var link = async ({ force }) => {
|
|
|
842
810
|
skipped++;
|
|
843
811
|
continue;
|
|
844
812
|
}
|
|
845
|
-
|
|
813
|
+
spinner6.update(`linking ${import_termkit7.Color.white.encoder(show)}`).start();
|
|
846
814
|
const title = parseShowTitle(show);
|
|
847
815
|
const results = await searchTv(title, config.tmdbApiKey);
|
|
848
816
|
if (results.length === 0) {
|
|
849
|
-
|
|
817
|
+
spinner6.warn(`not found in TMDb: ${show}`);
|
|
850
818
|
notFound++;
|
|
851
819
|
continue;
|
|
852
820
|
}
|
|
853
821
|
if (results.length === 1) {
|
|
854
822
|
upsertShow(showPath, results[0].id, results[0].title);
|
|
855
|
-
|
|
823
|
+
spinner6.succeed(`${show} \u2192 ${import_termkit7.Color.green.encoder(results[0].title)} (${results[0].year})`);
|
|
856
824
|
linked++;
|
|
857
825
|
continue;
|
|
858
826
|
}
|
|
859
|
-
|
|
860
|
-
const select = new
|
|
827
|
+
spinner6.stop();
|
|
828
|
+
const select = new import_termkit7.Select();
|
|
861
829
|
const items = results.map((r) => ({
|
|
862
830
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
863
831
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
864
832
|
...r
|
|
865
833
|
}));
|
|
866
834
|
const picked = await select.ask(`Multiple shows found for "${show}":`, items);
|
|
867
|
-
|
|
835
|
+
spinner6.start();
|
|
868
836
|
if (picked) {
|
|
869
837
|
upsertShow(showPath, picked.id, picked.title);
|
|
870
|
-
|
|
838
|
+
spinner6.succeed(`${show} \u2192 ${import_termkit7.Color.green.encoder(picked.title)} (${picked.year})`);
|
|
871
839
|
linked++;
|
|
872
840
|
} else {
|
|
873
|
-
|
|
841
|
+
spinner6.info(`skipped: ${show}`);
|
|
874
842
|
skipped++;
|
|
875
843
|
}
|
|
876
844
|
}
|
|
877
|
-
|
|
878
|
-
if (notFound)
|
|
879
|
-
if (skipped)
|
|
880
|
-
|
|
845
|
+
spinner6.succeed(`linked ${linked} show${linked !== 1 ? "s" : ""}`);
|
|
846
|
+
if (notFound) spinner6.warn(`not found in TMDb: ${notFound}`);
|
|
847
|
+
if (skipped) spinner6.info(`skipped ${skipped} (already linked \u2014 use --force to re-link)`);
|
|
848
|
+
spinner6.stop();
|
|
881
849
|
};
|
|
882
850
|
var link_default = link;
|
|
883
851
|
|
|
884
852
|
// src/actions/list.ts
|
|
885
853
|
var import_fs9 = require("fs");
|
|
886
854
|
var import_path9 = require("path");
|
|
887
|
-
var
|
|
855
|
+
var import_termkit8 = require("termkit");
|
|
888
856
|
|
|
889
857
|
// src/helpers/dirSize.ts
|
|
890
858
|
var import_fs8 = require("fs");
|
|
@@ -1024,7 +992,7 @@ var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter
|
|
|
1024
992
|
const destRoot = config.dest[t];
|
|
1025
993
|
if (!(0, import_fs9.existsSync)(destRoot)) {
|
|
1026
994
|
console.log(`
|
|
1027
|
-
${t.toUpperCase()} ${
|
|
995
|
+
${t.toUpperCase()} ${import_termkit8.Color.white.encoder(destRoot)} (not found)`);
|
|
1028
996
|
continue;
|
|
1029
997
|
}
|
|
1030
998
|
const folders = (0, import_fs9.readdirSync)(destRoot).filter((f) => {
|
|
@@ -1055,8 +1023,8 @@ ${t.toUpperCase()} ${import_termkit9.Color.white.encoder(destRoot)} (not found
|
|
|
1055
1023
|
return yearDiff !== 0 ? yearDiff : a.title.localeCompare(b.title);
|
|
1056
1024
|
});
|
|
1057
1025
|
console.log(`
|
|
1058
|
-
${
|
|
1059
|
-
new
|
|
1026
|
+
${import_termkit8.Color.yellow.encoder(t.toUpperCase())} ${import_termkit8.Color.white.encoder(destRoot)}`);
|
|
1027
|
+
new import_termkit8.Table(
|
|
1060
1028
|
filtered.map((e) => ({
|
|
1061
1029
|
title: e.title,
|
|
1062
1030
|
year: e.year,
|
|
@@ -1073,7 +1041,7 @@ ${import_termkit9.Color.yellow.encoder(t.toUpperCase())} ${import_termkit9.Colo
|
|
|
1073
1041
|
{ key: "resolution", title: "Res", value: (v) => v ?? "\u2014" },
|
|
1074
1042
|
{ key: "codec", title: "Codec", value: (v) => v ?? "\u2014" },
|
|
1075
1043
|
{ key: "size", title: "Size" },
|
|
1076
|
-
{ key: "sub", title: "Sub", value: (v) => v ?
|
|
1044
|
+
{ key: "sub", title: "Sub", value: (v) => v ? import_termkit8.Color.green.encoder("\u2713") : import_termkit8.Color.red.encoder("\u2717") }
|
|
1077
1045
|
]
|
|
1078
1046
|
}
|
|
1079
1047
|
).print();
|
|
@@ -1086,7 +1054,7 @@ var list_default = list;
|
|
|
1086
1054
|
// src/actions/missing.ts
|
|
1087
1055
|
var import_fs10 = require("fs");
|
|
1088
1056
|
var import_path10 = require("path");
|
|
1089
|
-
var
|
|
1057
|
+
var import_termkit9 = require("termkit");
|
|
1090
1058
|
var TODAY = (/* @__PURE__ */ new Date()).toISOString().slice(0, 10);
|
|
1091
1059
|
var parseSeasonNumber = (folderName) => {
|
|
1092
1060
|
const match = folderName.match(/(?:season|s)\s*0*(\d+)/i);
|
|
@@ -1148,7 +1116,7 @@ var missing = async ({ show: showFilter }) => {
|
|
|
1148
1116
|
if (showMissing.length > 0) {
|
|
1149
1117
|
totalMissing += showMissing.length;
|
|
1150
1118
|
console.log(`
|
|
1151
|
-
${
|
|
1119
|
+
${import_termkit9.Color.yellow.encoder(show)}`);
|
|
1152
1120
|
for (const line of showMissing) console.log(line);
|
|
1153
1121
|
}
|
|
1154
1122
|
}
|
|
@@ -1169,7 +1137,7 @@ var missing_default = missing;
|
|
|
1169
1137
|
var import_child_process = require("child_process");
|
|
1170
1138
|
var import_fs11 = require("fs");
|
|
1171
1139
|
var import_path11 = require("path");
|
|
1172
|
-
var
|
|
1140
|
+
var import_termkit10 = require("termkit");
|
|
1173
1141
|
|
|
1174
1142
|
// src/refs/verbose.ts
|
|
1175
1143
|
var _verbose = false;
|
|
@@ -1179,6 +1147,7 @@ var setVerbose = (v) => {
|
|
|
1179
1147
|
var isVerbose = () => _verbose;
|
|
1180
1148
|
|
|
1181
1149
|
// src/actions/probe.ts
|
|
1150
|
+
var spinner7 = new import_termkit10.Spinner();
|
|
1182
1151
|
var DEST_TYPES3 = ["movie", "tv", "ps3"];
|
|
1183
1152
|
var CODEC_MAP2 = {
|
|
1184
1153
|
hevc: "x265",
|
|
@@ -1241,10 +1210,10 @@ var walkVideoFiles = (dir, depth = 0, maxDepth = 3) => {
|
|
|
1241
1210
|
return results;
|
|
1242
1211
|
};
|
|
1243
1212
|
var probe = async ({ type, force }) => {
|
|
1244
|
-
|
|
1213
|
+
spinner7.start();
|
|
1245
1214
|
if (!isFfprobeAvailable()) {
|
|
1246
|
-
|
|
1247
|
-
|
|
1215
|
+
spinner7.fail("ffprobe not found \u2014 install ffmpeg to use this command");
|
|
1216
|
+
spinner7.stop();
|
|
1248
1217
|
return;
|
|
1249
1218
|
}
|
|
1250
1219
|
const config = getConfig();
|
|
@@ -1254,30 +1223,30 @@ var probe = async ({ type, force }) => {
|
|
|
1254
1223
|
for (const t of types) {
|
|
1255
1224
|
const destRoot = config.dest[t];
|
|
1256
1225
|
if (!(0, import_fs11.existsSync)(destRoot)) continue;
|
|
1257
|
-
|
|
1226
|
+
spinner7.update(`scanning ${import_termkit10.Color.white.encoder(destRoot)}`);
|
|
1258
1227
|
const files = walkVideoFiles(destRoot);
|
|
1259
1228
|
for (const filePath of files) {
|
|
1260
1229
|
if (!force && getMediaInfo(filePath)) {
|
|
1261
|
-
if (isVerbose())
|
|
1230
|
+
if (isVerbose()) spinner7.info(`already probed: ${filePath}`);
|
|
1262
1231
|
skipped++;
|
|
1263
1232
|
continue;
|
|
1264
1233
|
}
|
|
1265
|
-
|
|
1234
|
+
spinner7.update(`probing ${import_termkit10.Color.white.encoder(filePath)}`);
|
|
1266
1235
|
const result = runFfprobe(filePath);
|
|
1267
1236
|
if (!result) {
|
|
1268
|
-
if (isVerbose())
|
|
1237
|
+
if (isVerbose()) spinner7.warn(`ffprobe failed: ${filePath}`);
|
|
1269
1238
|
failed++;
|
|
1270
1239
|
continue;
|
|
1271
1240
|
}
|
|
1272
1241
|
upsertMediaInfo(filePath, result.codec, result.resolution, result.width, result.height, result.duration);
|
|
1273
|
-
if (isVerbose())
|
|
1242
|
+
if (isVerbose()) spinner7.succeed(`${result.resolution ?? "?"} ${result.codec ?? "?"} ${filePath}`);
|
|
1274
1243
|
probed++;
|
|
1275
1244
|
}
|
|
1276
1245
|
}
|
|
1277
|
-
|
|
1278
|
-
if (skipped)
|
|
1279
|
-
if (failed)
|
|
1280
|
-
|
|
1246
|
+
spinner7.succeed(`probed ${probed} files`);
|
|
1247
|
+
if (skipped) spinner7.info(`skipped ${skipped} already indexed`);
|
|
1248
|
+
if (failed) spinner7.warn(`failed ${failed} files`);
|
|
1249
|
+
spinner7.stop();
|
|
1281
1250
|
};
|
|
1282
1251
|
var probe_default = probe;
|
|
1283
1252
|
|
|
@@ -1285,7 +1254,7 @@ var probe_default = probe;
|
|
|
1285
1254
|
var import_fs12 = require("fs");
|
|
1286
1255
|
var import_path12 = require("path");
|
|
1287
1256
|
var import_rimraf = require("rimraf");
|
|
1288
|
-
var
|
|
1257
|
+
var import_termkit11 = require("termkit");
|
|
1289
1258
|
|
|
1290
1259
|
// src/helpers/findSubtitle.ts
|
|
1291
1260
|
var LANGUAGE_ALIASES = {
|
|
@@ -1340,21 +1309,22 @@ var titleCase_default = (s) => {
|
|
|
1340
1309
|
};
|
|
1341
1310
|
|
|
1342
1311
|
// src/actions/rename.ts
|
|
1312
|
+
var spinner8 = new import_termkit11.Spinner();
|
|
1343
1313
|
var rename = async ({ dir: inputDir, type }) => {
|
|
1344
1314
|
const dir = (0, import_path12.resolve)(inputDir);
|
|
1345
1315
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
1346
1316
|
const config = getConfig();
|
|
1347
1317
|
const language = config.language ?? "eng";
|
|
1348
1318
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1349
|
-
|
|
1350
|
-
|
|
1319
|
+
spinner8.update(`renaming in ${import_termkit11.Color.white.encoder(dir)}`);
|
|
1320
|
+
spinner8.start();
|
|
1351
1321
|
if (!(0, import_fs12.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
1352
1322
|
const list2 = (0, import_fs12.readdirSync)(dir);
|
|
1353
1323
|
let renamed = 0, removed = 0, skipped = 0;
|
|
1354
1324
|
for (const [index, entry] of list2.entries()) {
|
|
1355
|
-
|
|
1325
|
+
spinner8.update(`renaming in ${import_termkit11.Color.white.encoder(dir)} ${index + 1}/${list2.length}`);
|
|
1356
1326
|
if (!(0, import_fs12.lstatSync)((0, import_path12.resolve)(dir, entry)).isDirectory()) {
|
|
1357
|
-
if (isVerbose())
|
|
1327
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1358
1328
|
skipped++;
|
|
1359
1329
|
continue;
|
|
1360
1330
|
}
|
|
@@ -1364,7 +1334,7 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1364
1334
|
const nameMatch = entry.match(/(?<=\[).+?(?=\])/);
|
|
1365
1335
|
const id = entry.split("-")[0];
|
|
1366
1336
|
if (!nameMatch || !id) {
|
|
1367
|
-
if (isVerbose())
|
|
1337
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1368
1338
|
skipped++;
|
|
1369
1339
|
continue;
|
|
1370
1340
|
}
|
|
@@ -1372,19 +1342,19 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1372
1342
|
const ps3New = (0, import_path12.resolve)(dir, `${nameMatch[0]} [${id}]`);
|
|
1373
1343
|
(0, import_fs12.renameSync)(ps3Old, ps3New);
|
|
1374
1344
|
recordRename(sessionId, ps3Old, ps3New);
|
|
1375
|
-
|
|
1345
|
+
spinner8.succeed(`${nameMatch[0]} [${id}]`);
|
|
1376
1346
|
renamed++;
|
|
1377
1347
|
continue;
|
|
1378
1348
|
}
|
|
1379
1349
|
const yearMatch = entry.match(/\([^\d]*(\d+)[^\d]*\)/);
|
|
1380
1350
|
if (!yearMatch) {
|
|
1381
|
-
if (isVerbose())
|
|
1351
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1382
1352
|
skipped++;
|
|
1383
1353
|
continue;
|
|
1384
1354
|
}
|
|
1385
1355
|
const year = yearMatch[0];
|
|
1386
1356
|
if (year.length !== 6) {
|
|
1387
|
-
if (isVerbose())
|
|
1357
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1388
1358
|
skipped++;
|
|
1389
1359
|
continue;
|
|
1390
1360
|
}
|
|
@@ -1395,20 +1365,20 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1395
1365
|
return videoExtensions_default.includes(ext2) && title.split(" ").reduce((a, w) => f.toLowerCase().includes(w.toLowerCase()) ? a : false, true);
|
|
1396
1366
|
});
|
|
1397
1367
|
if (!video) {
|
|
1398
|
-
if (isVerbose())
|
|
1368
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1399
1369
|
skipped++;
|
|
1400
1370
|
continue;
|
|
1401
1371
|
}
|
|
1402
1372
|
const ext = video.match(/([^.]+$)/)?.[0];
|
|
1403
1373
|
if (!ext) {
|
|
1404
|
-
if (isVerbose())
|
|
1374
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1405
1375
|
skipped++;
|
|
1406
1376
|
continue;
|
|
1407
1377
|
}
|
|
1408
1378
|
const yearNum = parseInt(year.replace(/\D/g, ""));
|
|
1409
1379
|
const formatted = formatMovieName(movieFormat, title, yearNum);
|
|
1410
1380
|
if (entry === formatted && video === `${formatted}.${ext}`) {
|
|
1411
|
-
if (isVerbose())
|
|
1381
|
+
if (isVerbose()) spinner8.info(`skipped ${entry}`);
|
|
1412
1382
|
skipped++;
|
|
1413
1383
|
continue;
|
|
1414
1384
|
}
|
|
@@ -1431,25 +1401,26 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1431
1401
|
(0, import_fs12.renameSync)(folderOld, folderNew);
|
|
1432
1402
|
recordRename(sessionId, fileOld, fileNew);
|
|
1433
1403
|
recordRename(sessionId, folderOld, folderNew);
|
|
1434
|
-
|
|
1404
|
+
spinner8.succeed(formatted);
|
|
1435
1405
|
renamed++;
|
|
1436
1406
|
}
|
|
1437
|
-
|
|
1438
|
-
if (removed)
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1407
|
+
spinner8.succeed(`renamed ${renamed} files`);
|
|
1408
|
+
if (removed) spinner8.info(`removed ${removed} files`);
|
|
1409
|
+
spinner8.info(`skipped ${skipped} files`);
|
|
1410
|
+
spinner8.succeed(`done in ${import_termkit11.Color.green.encoder(dir)}`);
|
|
1411
|
+
spinner8.stop();
|
|
1442
1412
|
};
|
|
1443
1413
|
var rename_default = rename;
|
|
1444
1414
|
|
|
1445
1415
|
// src/actions/reset.ts
|
|
1446
1416
|
var import_fs13 = require("fs");
|
|
1447
1417
|
var import_path13 = require("path");
|
|
1448
|
-
var
|
|
1418
|
+
var import_termkit12 = require("termkit");
|
|
1419
|
+
var spinner9 = new import_termkit12.Spinner();
|
|
1449
1420
|
var reset = async ({ dir: inputDir, double }) => {
|
|
1450
1421
|
let dir = inputDir;
|
|
1451
|
-
|
|
1452
|
-
|
|
1422
|
+
spinner9.update(`resetting episodes in ${import_termkit12.Color.white.encoder(dir)}`);
|
|
1423
|
+
spinner9.start();
|
|
1453
1424
|
dir = (0, import_path13.resolve)(dir);
|
|
1454
1425
|
if (!(0, import_fs13.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
1455
1426
|
const list2 = (0, import_fs13.readdirSync)(dir).sort();
|
|
@@ -1465,7 +1436,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1465
1436
|
if (!seasonNum) throw new Error(`unable to identify season number`);
|
|
1466
1437
|
const parentFolder = (0, import_path13.basename)((0, import_path13.dirname)(dir));
|
|
1467
1438
|
const showTitle = parentFolder.match(/^(.+?)\s*(?:\(\d{4}\))?$/)?.[1]?.trim() || void 0;
|
|
1468
|
-
|
|
1439
|
+
spinner9.info(`identified as season ${seasonNum}${showTitle ? ` of ${showTitle}` : ""}`);
|
|
1469
1440
|
const sublist = list2.filter((f) => {
|
|
1470
1441
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1471
1442
|
return videoExtensions_default.includes(ext) && f.split(" ").reduce((a, w) => f.toLowerCase().includes(w.toLowerCase()) ? a : false, true);
|
|
@@ -1477,7 +1448,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1477
1448
|
const episodeFormat = getConfig().format?.episode;
|
|
1478
1449
|
let renamed = 0, skipped = other.length;
|
|
1479
1450
|
for (const [index, i] of sublist.entries()) {
|
|
1480
|
-
|
|
1451
|
+
spinner9.update(`resetting episodes in ${import_termkit12.Color.white.encoder(dir)} ${index}/${list2.length}`);
|
|
1481
1452
|
const ext = i.match(/([^.]+$)/)?.[0];
|
|
1482
1453
|
const episode = double ? index * 2 + 1 : index + 1;
|
|
1483
1454
|
const name = `${formatEpisode(seasonNum, episode, episodeFormat, double, showTitle)}.${ext}`;
|
|
@@ -1488,17 +1459,17 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1488
1459
|
(0, import_fs13.renameSync)((0, import_path13.resolve)(dir, i), (0, import_path13.resolve)(dir, name));
|
|
1489
1460
|
renamed++;
|
|
1490
1461
|
}
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1462
|
+
spinner9.succeed(`renamed ${renamed} files`);
|
|
1463
|
+
spinner9.info(`skipped ${skipped} files`);
|
|
1464
|
+
spinner9.succeed(`done in ${import_termkit12.Color.green.encoder(dir)}`);
|
|
1465
|
+
spinner9.stop();
|
|
1495
1466
|
};
|
|
1496
1467
|
var reset_default = reset;
|
|
1497
1468
|
|
|
1498
1469
|
// src/actions/scan.ts
|
|
1499
1470
|
var import_fs15 = require("fs");
|
|
1500
1471
|
var import_path15 = require("path");
|
|
1501
|
-
var
|
|
1472
|
+
var import_termkit13 = require("termkit");
|
|
1502
1473
|
|
|
1503
1474
|
// src/helpers/detectEdition.ts
|
|
1504
1475
|
var EDITIONS = [
|
|
@@ -1601,6 +1572,7 @@ var parseDownloadName = (rawName) => {
|
|
|
1601
1572
|
var bookExtensions_default = ["epub", "mobi", "azw3", "azw"];
|
|
1602
1573
|
|
|
1603
1574
|
// src/actions/scan.ts
|
|
1575
|
+
var spinner10 = new import_termkit13.Spinner();
|
|
1604
1576
|
var sameDev = (a, b) => {
|
|
1605
1577
|
try {
|
|
1606
1578
|
let bExisting = b;
|
|
@@ -1802,13 +1774,17 @@ var classifyMovieConfidence = (entry) => {
|
|
|
1802
1774
|
return "ambiguous";
|
|
1803
1775
|
};
|
|
1804
1776
|
var typeColor = {
|
|
1805
|
-
movie: (s) =>
|
|
1806
|
-
tv: (s) =>
|
|
1807
|
-
book: (s) =>
|
|
1808
|
-
ps3: (s) =>
|
|
1809
|
-
};
|
|
1810
|
-
var typeGlyph = (t) => typeColor[t]("
|
|
1811
|
-
var
|
|
1777
|
+
movie: (s) => import_termkit13.Color.cyan.encoder(s),
|
|
1778
|
+
tv: (s) => import_termkit13.Color.green.encoder(s),
|
|
1779
|
+
book: (s) => import_termkit13.Color.yellow.encoder(s),
|
|
1780
|
+
ps3: (s) => import_termkit13.Color.magenta.encoder(s)
|
|
1781
|
+
};
|
|
1782
|
+
var typeGlyph = (t) => typeColor[t]("?");
|
|
1783
|
+
var checkGlyph = (t) => typeColor[t]("\u2714");
|
|
1784
|
+
var greyGlyph = import_termkit13.Color.white.faint.encoder("\u25CF");
|
|
1785
|
+
var warnGlyph = import_termkit13.Color.yellow.encoder("\u26A0");
|
|
1786
|
+
var typeTag = (t) => isVerbose() ? import_termkit13.Color.white.faint.encoder(` (${t})`) : "";
|
|
1787
|
+
var sortByEntry = (arr) => arr.sort((a, b) => a.entry.localeCompare(b.entry, void 0, { sensitivity: "base" }));
|
|
1812
1788
|
var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactive }) => {
|
|
1813
1789
|
const config = getConfig();
|
|
1814
1790
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1816,27 +1792,28 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1816
1792
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1817
1793
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
1818
1794
|
const specialsFolder = config.specialsFolder ?? "Specials";
|
|
1795
|
+
const dryTag = dryRun ? import_termkit13.Color.white.faint.encoder(" [dry]") : "";
|
|
1819
1796
|
const lookupMovie = async (parsed) => {
|
|
1820
1797
|
let tmdbId;
|
|
1821
1798
|
let resolvedTitle = parsed.title;
|
|
1822
1799
|
let resolvedYear = parsed.year;
|
|
1823
1800
|
if (config.tmdbApiKey) {
|
|
1824
|
-
|
|
1801
|
+
spinner10.update(`TMDb: ${parsed.title}`);
|
|
1825
1802
|
const results = await searchMovie(parsed.title, parsed.year, config.tmdbApiKey);
|
|
1826
1803
|
if (results.length === 1) {
|
|
1827
1804
|
tmdbId = results[0].id;
|
|
1828
1805
|
resolvedTitle = results[0].title;
|
|
1829
1806
|
resolvedYear = results[0].year ?? parsed.year;
|
|
1830
1807
|
} else if (results.length > 1) {
|
|
1831
|
-
|
|
1832
|
-
const select = new
|
|
1808
|
+
spinner10.stop();
|
|
1809
|
+
const select = new import_termkit13.Select();
|
|
1833
1810
|
const items = results.map((r) => ({
|
|
1834
1811
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
1835
1812
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
1836
1813
|
...r
|
|
1837
1814
|
}));
|
|
1838
1815
|
const picked = await select.ask(`Multiple movies found for "${parsed.title}":`, items);
|
|
1839
|
-
|
|
1816
|
+
spinner10.start();
|
|
1840
1817
|
if (picked) {
|
|
1841
1818
|
tmdbId = picked.id;
|
|
1842
1819
|
resolvedTitle = picked.title;
|
|
@@ -1851,12 +1828,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1851
1828
|
const folderName = formatMovieName(movieFormat, resolvedTitle, resolvedYear, edition);
|
|
1852
1829
|
const destFolder = (0, import_path15.resolve)(destRoot, folderName);
|
|
1853
1830
|
if ((0, import_fs15.existsSync)(destFolder)) {
|
|
1854
|
-
|
|
1831
|
+
spinner10.log(`${typeColor.movie(folderName)}${typeTag("movie")}`, greyGlyph);
|
|
1855
1832
|
return false;
|
|
1856
1833
|
}
|
|
1857
1834
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
1858
1835
|
if (!videoFile) {
|
|
1859
|
-
|
|
1836
|
+
spinner10.log(`${entry}${typeTag("movie")}`, warnGlyph);
|
|
1860
1837
|
return false;
|
|
1861
1838
|
}
|
|
1862
1839
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
@@ -1877,7 +1854,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1877
1854
|
(0, import_fs15.linkSync)(videoSourcePath, destVideoPath);
|
|
1878
1855
|
mode = "hardlink";
|
|
1879
1856
|
} catch {
|
|
1880
|
-
|
|
1857
|
+
spinner10.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
1881
1858
|
(0, import_fs15.cpSync)(videoSourcePath, destVideoPath);
|
|
1882
1859
|
mode = "copy";
|
|
1883
1860
|
}
|
|
@@ -1903,10 +1880,10 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1903
1880
|
recordImport(sessionId, entryPath, destFolder, "move", tmdbId, "movie");
|
|
1904
1881
|
}
|
|
1905
1882
|
}
|
|
1906
|
-
|
|
1883
|
+
spinner10.log(`${typeColor.movie(folderName)}${typeTag("movie")}${dryTag}`, checkGlyph("movie"));
|
|
1907
1884
|
return true;
|
|
1908
1885
|
};
|
|
1909
|
-
|
|
1886
|
+
spinner10.start();
|
|
1910
1887
|
if (config.sources.length === 0) throw new Error("no sources configured \u2014 run: reelsort config add source <dir>");
|
|
1911
1888
|
let imported = 0, skipped = 0;
|
|
1912
1889
|
const pendingMovies = [];
|
|
@@ -1917,15 +1894,19 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1917
1894
|
const seenIgnored = /* @__PURE__ */ new Set();
|
|
1918
1895
|
for (const source of config.sources) {
|
|
1919
1896
|
if (!(0, import_fs15.existsSync)(source)) {
|
|
1920
|
-
|
|
1897
|
+
spinner10.warn(`source not found: ${import_termkit13.Color.white.encoder(source)}`);
|
|
1921
1898
|
continue;
|
|
1922
1899
|
}
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1900
|
+
spinner10.update(`scanning ${import_termkit13.Color.white.encoder(source)}`);
|
|
1901
|
+
const entries = gatherEntries(source).sort(
|
|
1902
|
+
(a, b) => a.entry.localeCompare(b.entry, void 0, { sensitivity: "base" })
|
|
1903
|
+
);
|
|
1904
|
+
for (const { entry, entryPath, isDir } of entries) {
|
|
1905
|
+
spinner10.update(`scanning: ${entry}`);
|
|
1926
1906
|
if (ignoreSet.has(entry)) {
|
|
1927
1907
|
seenIgnored.add(entry);
|
|
1928
|
-
if (isVerbose())
|
|
1908
|
+
if (isVerbose()) spinner10.log(entry, greyGlyph);
|
|
1909
|
+
skipped++;
|
|
1929
1910
|
continue;
|
|
1930
1911
|
}
|
|
1931
1912
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
@@ -1945,7 +1926,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1945
1926
|
}
|
|
1946
1927
|
const destRoot = config.dest[detectedType];
|
|
1947
1928
|
if (!destRoot) {
|
|
1948
|
-
if (isVerbose())
|
|
1929
|
+
if (isVerbose()) spinner10.log(`${entry}${typeTag(detectedType)}`, greyGlyph);
|
|
1949
1930
|
skipped++;
|
|
1950
1931
|
continue;
|
|
1951
1932
|
}
|
|
@@ -1959,7 +1940,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1959
1940
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
1960
1941
|
const destPath = (0, import_path15.resolve)(destRoot, destName);
|
|
1961
1942
|
if ((0, import_fs15.existsSync)(destPath)) {
|
|
1962
|
-
|
|
1943
|
+
spinner10.log(`${typeColor.ps3(destName)}${typeTag("ps3")}`, greyGlyph);
|
|
1963
1944
|
skipped++;
|
|
1964
1945
|
continue;
|
|
1965
1946
|
}
|
|
@@ -1967,14 +1948,14 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1967
1948
|
moveFolder(entryPath, destPath);
|
|
1968
1949
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "ps3");
|
|
1969
1950
|
}
|
|
1970
|
-
|
|
1951
|
+
spinner10.log(`${typeColor.ps3(destName)}${typeTag("ps3")}${dryTag}`, checkGlyph("ps3"));
|
|
1971
1952
|
imported++;
|
|
1972
1953
|
continue;
|
|
1973
1954
|
}
|
|
1974
1955
|
if (detectedType === "book") {
|
|
1975
1956
|
const destPath = (0, import_path15.resolve)(destRoot, entry);
|
|
1976
1957
|
if ((0, import_fs15.existsSync)(destPath)) {
|
|
1977
|
-
|
|
1958
|
+
spinner10.log(`${typeColor.book(entry)}${typeTag("book")}`, greyGlyph);
|
|
1978
1959
|
skipped++;
|
|
1979
1960
|
continue;
|
|
1980
1961
|
}
|
|
@@ -1992,7 +1973,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1992
1973
|
}
|
|
1993
1974
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
1994
1975
|
}
|
|
1995
|
-
|
|
1976
|
+
spinner10.log(`${typeColor.book(entry)}${typeTag("book")}${dryTag}`, checkGlyph("book"));
|
|
1996
1977
|
imported++;
|
|
1997
1978
|
continue;
|
|
1998
1979
|
}
|
|
@@ -2001,10 +1982,10 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2001
1982
|
if (videoCount === 0) {
|
|
2002
1983
|
if (containsPdf(entryPath)) {
|
|
2003
1984
|
pendingBooks.push({ entry, entryPath });
|
|
2004
|
-
} else
|
|
2005
|
-
|
|
1985
|
+
} else {
|
|
1986
|
+
if (isVerbose()) spinner10.log(entry, greyGlyph);
|
|
1987
|
+
skipped++;
|
|
2006
1988
|
}
|
|
2007
|
-
skipped++;
|
|
2008
1989
|
continue;
|
|
2009
1990
|
}
|
|
2010
1991
|
if (videoCount >= 2) {
|
|
@@ -2014,14 +1995,14 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2014
1995
|
}
|
|
2015
1996
|
const parsed = parseDownloadName(entry);
|
|
2016
1997
|
if (!parsed) {
|
|
2017
|
-
if (isVerbose())
|
|
1998
|
+
if (isVerbose()) spinner10.log(entry, greyGlyph);
|
|
2018
1999
|
skipped++;
|
|
2019
2000
|
continue;
|
|
2020
2001
|
}
|
|
2021
2002
|
if (detectedType === "movie") {
|
|
2022
2003
|
const confidence = classifyMovieConfidence(entry);
|
|
2023
2004
|
if (confidence === "skip") {
|
|
2024
|
-
if (isVerbose())
|
|
2005
|
+
if (isVerbose()) spinner10.log(entry, greyGlyph);
|
|
2025
2006
|
skipped++;
|
|
2026
2007
|
continue;
|
|
2027
2008
|
}
|
|
@@ -2035,22 +2016,22 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2035
2016
|
let resolvedYear = parsed.year;
|
|
2036
2017
|
if (config.tmdbApiKey) {
|
|
2037
2018
|
if (detectedType === "tv") {
|
|
2038
|
-
|
|
2019
|
+
spinner10.update(`TMDb: ${parsed.title}`);
|
|
2039
2020
|
const results = await searchTv(parsed.title, config.tmdbApiKey);
|
|
2040
2021
|
if (results.length === 1) {
|
|
2041
2022
|
tmdbId = results[0].id;
|
|
2042
2023
|
resolvedTitle = results[0].title;
|
|
2043
2024
|
resolvedYear = results[0].year ?? parsed.year;
|
|
2044
2025
|
} else if (results.length > 1) {
|
|
2045
|
-
|
|
2046
|
-
const select = new
|
|
2026
|
+
spinner10.stop();
|
|
2027
|
+
const select = new import_termkit13.Select();
|
|
2047
2028
|
const items = results.map((r) => ({
|
|
2048
2029
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
2049
2030
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
2050
2031
|
...r
|
|
2051
2032
|
}));
|
|
2052
2033
|
const picked = await select.ask(`Multiple shows found for "${parsed.title}":`, items);
|
|
2053
|
-
|
|
2034
|
+
spinner10.start();
|
|
2054
2035
|
if (picked) {
|
|
2055
2036
|
tmdbId = picked.id;
|
|
2056
2037
|
resolvedTitle = picked.title;
|
|
@@ -2066,7 +2047,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2066
2047
|
}
|
|
2067
2048
|
if (detectedType === "tv") {
|
|
2068
2049
|
if (parsed.season === void 0) {
|
|
2069
|
-
if (isVerbose())
|
|
2050
|
+
if (isVerbose()) spinner10.log(entry, greyGlyph);
|
|
2070
2051
|
skipped++;
|
|
2071
2052
|
continue;
|
|
2072
2053
|
}
|
|
@@ -2094,12 +2075,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2094
2075
|
const seasonPath = (0, import_path15.resolve)(showPath, seasonFolderName);
|
|
2095
2076
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
2096
2077
|
if (!videoFile) {
|
|
2097
|
-
|
|
2078
|
+
spinner10.log(`${entry}${typeTag("tv")}`, warnGlyph);
|
|
2098
2079
|
skipped++;
|
|
2099
2080
|
continue;
|
|
2100
2081
|
}
|
|
2101
2082
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
2102
|
-
if (tmdbId && config.tmdbApiKey)
|
|
2083
|
+
if (tmdbId && config.tmdbApiKey) spinner10.update(`TMDb: episode name for ${resolvedTitle}`);
|
|
2103
2084
|
const tmdbEpisodeName = tmdbId && config.tmdbApiKey ? await getEpisodeName(tmdbId, parsed.season, parsed.episode ?? 1, config.tmdbApiKey) : null;
|
|
2104
2085
|
const episodeName = formatEpisode(parsed.season, parsed.episode ?? 1, config.format?.episode, false, resolvedTitle, tmdbEpisodeName ?? void 0);
|
|
2105
2086
|
const destVideoName = `${episodeName}.${videoExt}`;
|
|
@@ -2109,17 +2090,17 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2109
2090
|
const isRepack = /\brepack\d*\b|\bproper\b/i.test(entry);
|
|
2110
2091
|
let shouldReplace = force || isRepack;
|
|
2111
2092
|
if (!shouldReplace && interactive) {
|
|
2112
|
-
|
|
2113
|
-
const select = new
|
|
2093
|
+
spinner10.stop();
|
|
2094
|
+
const select = new import_termkit13.Select();
|
|
2114
2095
|
const picked = await select.ask(`Already exists \u2014 replace?`, [
|
|
2115
2096
|
{ label: `${showFolderName} / ${seasonFolderName} / ${episodeName}`, value: "replace" },
|
|
2116
2097
|
{ label: "Skip", value: "skip" }
|
|
2117
2098
|
]);
|
|
2118
|
-
|
|
2099
|
+
spinner10.start();
|
|
2119
2100
|
shouldReplace = picked?.value === "replace";
|
|
2120
2101
|
}
|
|
2121
2102
|
if (!shouldReplace) {
|
|
2122
|
-
|
|
2103
|
+
spinner10.log(`${typeColor.tv(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}${typeTag("tv")}`, greyGlyph);
|
|
2123
2104
|
skipped++;
|
|
2124
2105
|
continue;
|
|
2125
2106
|
}
|
|
@@ -2143,7 +2124,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2143
2124
|
(0, import_fs15.linkSync)(videoSourcePath, destVideoPath);
|
|
2144
2125
|
mode = "hardlink";
|
|
2145
2126
|
} catch {
|
|
2146
|
-
|
|
2127
|
+
spinner10.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
2147
2128
|
(0, import_fs15.cpSync)(videoSourcePath, destVideoPath);
|
|
2148
2129
|
mode = "copy";
|
|
2149
2130
|
}
|
|
@@ -2160,7 +2141,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2160
2141
|
}
|
|
2161
2142
|
recordImport(sessionId, entryPath, seasonPath, mode, tmdbId, "tv");
|
|
2162
2143
|
}
|
|
2163
|
-
|
|
2144
|
+
spinner10.log(`${typeColor.tv(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}${typeTag("tv")}${dryTag}`, checkGlyph("tv"));
|
|
2164
2145
|
imported++;
|
|
2165
2146
|
continue;
|
|
2166
2147
|
}
|
|
@@ -2171,25 +2152,27 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2171
2152
|
}
|
|
2172
2153
|
}
|
|
2173
2154
|
}
|
|
2155
|
+
let uncertainMovies = 0;
|
|
2174
2156
|
if (pendingMovies.length > 0) {
|
|
2175
|
-
spinner_default.warn(`${pendingMovies.length} uncertain movie match${pendingMovies.length > 1 ? "es" : ""} skipped \u2014 use -i to review or -f to import all`);
|
|
2176
|
-
for (const p of pendingMovies) spinner_default.info(` ${typeGlyph("movie")} ${p.entry.replace(/\/$/, "")}${typeTag("movie")}`);
|
|
2177
2157
|
let toProcess = [];
|
|
2178
2158
|
if (interactive) {
|
|
2179
|
-
|
|
2180
|
-
const ms = new
|
|
2159
|
+
spinner10.stop();
|
|
2160
|
+
const ms = new import_termkit13.MultiSelect({ allowSkip: true, search: true, maxHeight: 20 });
|
|
2181
2161
|
const items = pendingMovies.map((p) => ({
|
|
2182
2162
|
label: p.entry.replace(/\/$/, ""),
|
|
2183
2163
|
description: p.parsed.year ? `parsed: ${p.parsed.title} \xB7 ${p.parsed.year}` : `parsed: ${p.parsed.title}`,
|
|
2184
2164
|
...p
|
|
2185
2165
|
}));
|
|
2186
2166
|
toProcess = await ms.ask("Select entries to import as movies:", items) ?? [];
|
|
2187
|
-
|
|
2188
|
-
skipped += pendingMovies.length - toProcess.length;
|
|
2167
|
+
spinner10.start();
|
|
2189
2168
|
} else if (force) {
|
|
2190
2169
|
toProcess = pendingMovies;
|
|
2191
|
-
}
|
|
2192
|
-
|
|
2170
|
+
}
|
|
2171
|
+
const toSkip = pendingMovies.filter((p) => !toProcess.includes(p));
|
|
2172
|
+
uncertainMovies = toSkip.length;
|
|
2173
|
+
sortByEntry(toSkip);
|
|
2174
|
+
for (const p of toSkip) {
|
|
2175
|
+
spinner10.log(`${typeColor.movie(p.entry.replace(/\/$/, ""))}${typeTag("movie")}`, typeGlyph("movie"));
|
|
2193
2176
|
}
|
|
2194
2177
|
for (const p of toProcess) {
|
|
2195
2178
|
const { tmdbId, resolvedTitle, resolvedYear } = await lookupMovie(p.parsed);
|
|
@@ -2201,18 +2184,22 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2201
2184
|
}
|
|
2202
2185
|
}
|
|
2203
2186
|
if (pendingTv.length > 0) {
|
|
2204
|
-
|
|
2205
|
-
for (const p of pendingTv)
|
|
2206
|
-
|
|
2187
|
+
pendingTv.sort((a, b) => a.resolvedTitle.localeCompare(b.resolvedTitle, void 0, { sensitivity: "base" }));
|
|
2188
|
+
for (const p of pendingTv) {
|
|
2189
|
+
spinner10.log(`${typeColor.tv(p.resolvedTitle)} \u2014 ${p.entry.replace(/\/$/, "")}${typeTag("tv")}`, typeGlyph("tv"));
|
|
2190
|
+
}
|
|
2207
2191
|
}
|
|
2208
2192
|
if (pendingBooks.length > 0) {
|
|
2209
|
-
|
|
2210
|
-
for (const p of pendingBooks)
|
|
2193
|
+
sortByEntry(pendingBooks);
|
|
2194
|
+
for (const p of pendingBooks) {
|
|
2195
|
+
spinner10.log(`${typeColor.book(p.entry)}${typeTag("book")}`, typeGlyph("book"));
|
|
2196
|
+
}
|
|
2211
2197
|
}
|
|
2212
2198
|
if (pendingAnime.length > 0) {
|
|
2213
|
-
|
|
2214
|
-
for (const p of pendingAnime)
|
|
2215
|
-
|
|
2199
|
+
sortByEntry(pendingAnime);
|
|
2200
|
+
for (const p of pendingAnime) {
|
|
2201
|
+
spinner10.log(`${typeColor.tv(p.entry)} (${p.videoCount} video${p.videoCount > 1 ? "s" : ""})${typeTag("tv")}`, typeGlyph("tv"));
|
|
2202
|
+
}
|
|
2216
2203
|
}
|
|
2217
2204
|
if (ignoreSet.size > 0) {
|
|
2218
2205
|
const stale = [...ignoreSet].filter((name) => !seenIgnored.has(name));
|
|
@@ -2220,18 +2207,23 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
2220
2207
|
const updated = config.ignore.filter((name) => !stale.includes(name));
|
|
2221
2208
|
config.ignore = updated;
|
|
2222
2209
|
saveConfig(config);
|
|
2223
|
-
for (const name of stale)
|
|
2210
|
+
for (const name of stale) spinner10.info(`removed from ignore list (not found): ${import_termkit13.Color.white.encoder(name)}`);
|
|
2224
2211
|
}
|
|
2225
2212
|
}
|
|
2226
|
-
|
|
2227
|
-
if (skipped)
|
|
2228
|
-
|
|
2213
|
+
const summaryParts = [`${dryRun ? "would import" : "imported"} ${imported}`];
|
|
2214
|
+
if (skipped) summaryParts.push(`skipped ${skipped}`);
|
|
2215
|
+
if (uncertainMovies) summaryParts.push(`uncertain movie ${uncertainMovies}`);
|
|
2216
|
+
if (pendingTv.length) summaryParts.push(`uncertain tv ${pendingTv.length}`);
|
|
2217
|
+
if (pendingBooks.length) summaryParts.push(`uncertain book ${pendingBooks.length}`);
|
|
2218
|
+
if (pendingAnime.length) summaryParts.push(`uncertain anime ${pendingAnime.length}`);
|
|
2219
|
+
spinner10.succeed(summaryParts.join(", "));
|
|
2220
|
+
spinner10.stop();
|
|
2229
2221
|
};
|
|
2230
2222
|
var scan_default = scan;
|
|
2231
2223
|
|
|
2232
2224
|
// src/actions/shows.ts
|
|
2233
2225
|
var import_fs16 = require("fs");
|
|
2234
|
-
var
|
|
2226
|
+
var import_termkit14 = require("termkit");
|
|
2235
2227
|
var dim = (s) => `\x1B[2m${s}\x1B[0m`;
|
|
2236
2228
|
var shows = async () => {
|
|
2237
2229
|
const config = getConfig();
|
|
@@ -2243,8 +2235,8 @@ var shows = async () => {
|
|
|
2243
2235
|
return;
|
|
2244
2236
|
}
|
|
2245
2237
|
console.log(`
|
|
2246
|
-
${
|
|
2247
|
-
new
|
|
2238
|
+
${import_termkit14.Color.yellow.encoder("SHOWS")}${destRoot ? ` ${import_termkit14.Color.white.encoder(destRoot)}` : ""} (${allShows.length} registered)`);
|
|
2239
|
+
new import_termkit14.Table(
|
|
2248
2240
|
allShows.map((show) => ({
|
|
2249
2241
|
name: show.path.split("/").pop() ?? show.path,
|
|
2250
2242
|
size: (0, import_fs16.existsSync)(show.path) ? formatSize(dirSize(show.path)) : "\u2014",
|
|
@@ -2263,9 +2255,9 @@ ${import_termkit15.Color.yellow.encoder("SHOWS")}${destRoot ? ` ${import_termki
|
|
|
2263
2255
|
if (v) {
|
|
2264
2256
|
const url = `https://www.themoviedb.org/tv/${v}`;
|
|
2265
2257
|
const text = process.stdout.isTTY ? hyperlink(url, "\u2713 tmdb") : "\u2713 tmdb";
|
|
2266
|
-
return
|
|
2258
|
+
return import_termkit14.Color.green.encoder(text);
|
|
2267
2259
|
}
|
|
2268
|
-
return
|
|
2260
|
+
return import_termkit14.Color.red.encoder("\u2717");
|
|
2269
2261
|
}
|
|
2270
2262
|
},
|
|
2271
2263
|
{ key: "ended", title: "Status", value: (v) => v ? dim("ended") : "active" }
|
|
@@ -2282,7 +2274,7 @@ var shows_default = shows;
|
|
|
2282
2274
|
// src/actions/stats.ts
|
|
2283
2275
|
var import_fs17 = require("fs");
|
|
2284
2276
|
var import_path16 = require("path");
|
|
2285
|
-
var
|
|
2277
|
+
var import_termkit15 = require("termkit");
|
|
2286
2278
|
var countVideos2 = (dir) => {
|
|
2287
2279
|
let count = 0;
|
|
2288
2280
|
try {
|
|
@@ -2330,7 +2322,7 @@ var stats = async () => {
|
|
|
2330
2322
|
}
|
|
2331
2323
|
if (rows.length === 0) return;
|
|
2332
2324
|
console.log();
|
|
2333
|
-
new
|
|
2325
|
+
new import_termkit15.Table(rows, {
|
|
2334
2326
|
title: "LIBRARY STATISTICS",
|
|
2335
2327
|
separator: " ",
|
|
2336
2328
|
columns: [
|
|
@@ -2345,14 +2337,15 @@ var stats_default = stats;
|
|
|
2345
2337
|
|
|
2346
2338
|
// src/actions/undo.ts
|
|
2347
2339
|
var import_fs18 = require("fs");
|
|
2348
|
-
var
|
|
2340
|
+
var import_termkit16 = require("termkit");
|
|
2341
|
+
var spinner11 = new import_termkit16.Spinner();
|
|
2349
2342
|
var undo = async () => {
|
|
2350
|
-
|
|
2343
|
+
spinner11.start();
|
|
2351
2344
|
const renameRecords = getLastSession();
|
|
2352
2345
|
const importRecords = getLastImportSession();
|
|
2353
2346
|
if (renameRecords.length === 0 && importRecords.length === 0) {
|
|
2354
|
-
|
|
2355
|
-
|
|
2347
|
+
spinner11.info("nothing to undo");
|
|
2348
|
+
spinner11.stop();
|
|
2356
2349
|
return;
|
|
2357
2350
|
}
|
|
2358
2351
|
const useImports = importRecords.length > 0 && (renameRecords.length === 0 || importRecords[0].sessionId > renameRecords[0].sessionId);
|
|
@@ -2360,40 +2353,40 @@ var undo = async () => {
|
|
|
2360
2353
|
let undone2 = 0;
|
|
2361
2354
|
for (const record of renameRecords) {
|
|
2362
2355
|
(0, import_fs18.renameSync)(record.newPath, record.oldPath);
|
|
2363
|
-
|
|
2356
|
+
spinner11.succeed(`${import_termkit16.Color.green.encoder(record.newPath)} \u2192 ${import_termkit16.Color.white.encoder(record.oldPath)}`);
|
|
2364
2357
|
undone2++;
|
|
2365
2358
|
}
|
|
2366
2359
|
deleteSession(renameRecords[0].sessionId);
|
|
2367
|
-
|
|
2368
|
-
|
|
2360
|
+
spinner11.succeed(`undid ${undone2} renames`);
|
|
2361
|
+
spinner11.stop();
|
|
2369
2362
|
return;
|
|
2370
2363
|
}
|
|
2371
2364
|
let undone = 0;
|
|
2372
2365
|
let skipped = 0;
|
|
2373
2366
|
for (const record of importRecords) {
|
|
2374
2367
|
if (record.mode !== "move") {
|
|
2375
|
-
|
|
2368
|
+
spinner11.info(`skipped ${record.destinationPath} (${record.mode} \u2014 source file unchanged)`);
|
|
2376
2369
|
skipped++;
|
|
2377
2370
|
continue;
|
|
2378
2371
|
}
|
|
2379
2372
|
if (record.type === "tv") {
|
|
2380
|
-
|
|
2373
|
+
spinner11.info(`skipped TV import \u2014 season folder cannot be cleanly reversed: ${record.destinationPath}`);
|
|
2381
2374
|
skipped++;
|
|
2382
2375
|
continue;
|
|
2383
2376
|
}
|
|
2384
2377
|
if (!(0, import_fs18.existsSync)(record.destinationPath)) {
|
|
2385
|
-
|
|
2378
|
+
spinner11.info(`skipped \u2014 destination no longer exists: ${record.destinationPath}`);
|
|
2386
2379
|
skipped++;
|
|
2387
2380
|
continue;
|
|
2388
2381
|
}
|
|
2389
2382
|
(0, import_fs18.renameSync)(record.destinationPath, record.sourcePath);
|
|
2390
|
-
|
|
2383
|
+
spinner11.succeed(`${import_termkit16.Color.green.encoder(record.destinationPath)} \u2192 ${import_termkit16.Color.white.encoder(record.sourcePath)}`);
|
|
2391
2384
|
undone++;
|
|
2392
2385
|
}
|
|
2393
2386
|
deleteImportSession(importRecords[0].sessionId);
|
|
2394
|
-
if (undone > 0)
|
|
2395
|
-
if (skipped > 0)
|
|
2396
|
-
|
|
2387
|
+
if (undone > 0) spinner11.succeed(`undid ${undone} import${undone !== 1 ? "s" : ""}`);
|
|
2388
|
+
if (skipped > 0) spinner11.info(`skipped ${skipped} item${skipped !== 1 ? "s" : ""} (TV or non-move mode)`);
|
|
2389
|
+
spinner11.stop();
|
|
2397
2390
|
};
|
|
2398
2391
|
var undo_default = undo;
|
|
2399
2392
|
|
|
@@ -2401,7 +2394,8 @@ var undo_default = undo;
|
|
|
2401
2394
|
var import_chokidar = __toESM(require("chokidar"));
|
|
2402
2395
|
var import_fs19 = require("fs");
|
|
2403
2396
|
var import_path17 = require("path");
|
|
2404
|
-
var
|
|
2397
|
+
var import_termkit17 = require("termkit");
|
|
2398
|
+
var spinner12 = new import_termkit17.Spinner();
|
|
2405
2399
|
var sameDev2 = (a, b) => {
|
|
2406
2400
|
try {
|
|
2407
2401
|
let bExisting = b;
|
|
@@ -2541,7 +2535,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2541
2535
|
}
|
|
2542
2536
|
const destRoot = config.dest[detectedType];
|
|
2543
2537
|
if (!destRoot) {
|
|
2544
|
-
if (isVerbose())
|
|
2538
|
+
if (isVerbose()) spinner12.info(`no ${detectedType} destination configured, skipped: ${entry}`);
|
|
2545
2539
|
return;
|
|
2546
2540
|
}
|
|
2547
2541
|
if (detectedType === "ps3") {
|
|
@@ -2551,18 +2545,18 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2551
2545
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
2552
2546
|
const destPath = (0, import_path17.resolve)(destRoot, destName);
|
|
2553
2547
|
if ((0, import_fs19.existsSync)(destPath)) {
|
|
2554
|
-
|
|
2548
|
+
spinner12.warn(`already exists: ${destName}`);
|
|
2555
2549
|
return;
|
|
2556
2550
|
}
|
|
2557
2551
|
moveItem(entryPath, destPath);
|
|
2558
2552
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "ps3");
|
|
2559
|
-
|
|
2553
|
+
spinner12.succeed(`imported ${import_termkit17.Color.green.encoder(destName)}`);
|
|
2560
2554
|
return;
|
|
2561
2555
|
}
|
|
2562
2556
|
if (detectedType === "book") {
|
|
2563
2557
|
const destPath = (0, import_path17.resolve)(destRoot, entry);
|
|
2564
2558
|
if ((0, import_fs19.existsSync)(destPath)) {
|
|
2565
|
-
|
|
2559
|
+
spinner12.warn(`already exists: ${entry}`);
|
|
2566
2560
|
return;
|
|
2567
2561
|
}
|
|
2568
2562
|
if (isDir || isBookDir) {
|
|
@@ -2577,17 +2571,17 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2577
2571
|
}
|
|
2578
2572
|
}
|
|
2579
2573
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
2580
|
-
|
|
2574
|
+
spinner12.succeed(`imported ${import_termkit17.Color.green.encoder(entry)}`);
|
|
2581
2575
|
return;
|
|
2582
2576
|
}
|
|
2583
2577
|
const parsed = parseDownloadName(entry);
|
|
2584
2578
|
if (!parsed) {
|
|
2585
|
-
if (isVerbose())
|
|
2579
|
+
if (isVerbose()) spinner12.info(`could not parse: ${entry}`);
|
|
2586
2580
|
return;
|
|
2587
2581
|
}
|
|
2588
2582
|
if (detectedType === "tv") {
|
|
2589
2583
|
if (parsed.season === void 0) {
|
|
2590
|
-
if (isVerbose())
|
|
2584
|
+
if (isVerbose()) spinner12.info(`could not detect season from: ${entry}`);
|
|
2591
2585
|
return;
|
|
2592
2586
|
}
|
|
2593
2587
|
const registeredShow = getShowByTitle(parsed.title);
|
|
@@ -2601,14 +2595,14 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2601
2595
|
showPath = (0, import_path17.resolve)(destRoot, showFolderName);
|
|
2602
2596
|
upsertShow(showPath, null, parsed.title);
|
|
2603
2597
|
} else {
|
|
2604
|
-
if (isVerbose())
|
|
2598
|
+
if (isVerbose()) spinner12.info(`not registered, skipped: ${parsed.title} \u2014 run: reelsort add "${parsed.title}"`);
|
|
2605
2599
|
return;
|
|
2606
2600
|
}
|
|
2607
2601
|
const seasonFolderName = findSeasonFolder2(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
2608
2602
|
const seasonPath = (0, import_path17.resolve)(showPath, seasonFolderName);
|
|
2609
2603
|
const videoFile2 = isDir ? findVideo2(entryPath) : entry;
|
|
2610
2604
|
if (!videoFile2) {
|
|
2611
|
-
if (isVerbose())
|
|
2605
|
+
if (isVerbose()) spinner12.info(`no video found in: ${entry}`);
|
|
2612
2606
|
return;
|
|
2613
2607
|
}
|
|
2614
2608
|
const videoExt2 = videoFile2.match(/([^.]+$)/)?.[0];
|
|
@@ -2618,7 +2612,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2618
2612
|
const destVideoPath = (0, import_path17.resolve)(seasonPath, destVideoName2);
|
|
2619
2613
|
const videoSourcePath2 = isDir ? (0, import_path17.resolve)(entryPath, videoFile2) : entryPath;
|
|
2620
2614
|
if ((0, import_fs19.existsSync)(destVideoPath)) {
|
|
2621
|
-
|
|
2615
|
+
spinner12.warn(`already exists: ${episodeName}`);
|
|
2622
2616
|
return;
|
|
2623
2617
|
}
|
|
2624
2618
|
const dirFiles2 = isDir ? (0, import_fs19.readdirSync)(entryPath) : [];
|
|
@@ -2634,7 +2628,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2634
2628
|
(0, import_fs19.linkSync)(videoSourcePath2, destVideoPath);
|
|
2635
2629
|
mode = "hardlink";
|
|
2636
2630
|
} catch {
|
|
2637
|
-
|
|
2631
|
+
spinner12.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
2638
2632
|
(0, import_fs19.cpSync)(videoSourcePath2, destVideoPath);
|
|
2639
2633
|
mode = "copy";
|
|
2640
2634
|
}
|
|
@@ -2650,19 +2644,19 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2650
2644
|
if (isDir) (0, import_fs19.rmSync)(entryPath, { recursive: true, force: true });
|
|
2651
2645
|
}
|
|
2652
2646
|
recordImport(sessionId, entryPath, seasonPath, mode, void 0, "tv");
|
|
2653
|
-
|
|
2647
|
+
spinner12.succeed(`imported ${import_termkit17.Color.green.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
|
|
2654
2648
|
return;
|
|
2655
2649
|
}
|
|
2656
2650
|
const edition = detectEdition(entry);
|
|
2657
2651
|
const folderName = formatMovieName(movieFormat, parsed.title, parsed.year, edition);
|
|
2658
2652
|
const destFolder = (0, import_path17.resolve)(destRoot, folderName);
|
|
2659
2653
|
if ((0, import_fs19.existsSync)(destFolder)) {
|
|
2660
|
-
|
|
2654
|
+
spinner12.warn(`already exists: ${folderName}`);
|
|
2661
2655
|
return;
|
|
2662
2656
|
}
|
|
2663
2657
|
const videoFile = isDir ? findVideo2(entryPath) : entry;
|
|
2664
2658
|
if (!videoFile) {
|
|
2665
|
-
if (isVerbose())
|
|
2659
|
+
if (isVerbose()) spinner12.info(`no video found in: ${entry}`);
|
|
2666
2660
|
return;
|
|
2667
2661
|
}
|
|
2668
2662
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
@@ -2682,7 +2676,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2682
2676
|
(0, import_fs19.linkSync)(videoSourcePath, destVideoPath);
|
|
2683
2677
|
mode = "hardlink";
|
|
2684
2678
|
} catch {
|
|
2685
|
-
|
|
2679
|
+
spinner12.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
2686
2680
|
(0, import_fs19.cpSync)(videoSourcePath, destVideoPath);
|
|
2687
2681
|
mode = "copy";
|
|
2688
2682
|
}
|
|
@@ -2707,7 +2701,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2707
2701
|
}
|
|
2708
2702
|
recordImport(sessionId, entryPath, destFolder, "move", void 0, "movie");
|
|
2709
2703
|
}
|
|
2710
|
-
|
|
2704
|
+
spinner12.succeed(`imported ${import_termkit17.Color.green.encoder(folderName)}`);
|
|
2711
2705
|
};
|
|
2712
2706
|
var watch = async ({ hardlink = false, auto = false }) => {
|
|
2713
2707
|
const config = getConfig();
|
|
@@ -2726,7 +2720,7 @@ var watch = async ({ hardlink = false, auto = false }) => {
|
|
|
2726
2720
|
await processItem(entry, hardlink, language, auto);
|
|
2727
2721
|
}
|
|
2728
2722
|
} catch (err) {
|
|
2729
|
-
|
|
2723
|
+
spinner12.fail(`error processing ${path}: ${err.message}`);
|
|
2730
2724
|
}
|
|
2731
2725
|
}, 5e3)
|
|
2732
2726
|
);
|
|
@@ -2738,16 +2732,16 @@ var watch = async ({ hardlink = false, auto = false }) => {
|
|
|
2738
2732
|
});
|
|
2739
2733
|
watcher.on("addDir", handle);
|
|
2740
2734
|
watcher.on("add", handle);
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
for (const s of config.sources)
|
|
2744
|
-
|
|
2735
|
+
spinner12.start();
|
|
2736
|
+
spinner12.succeed(`watching ${config.sources.length} source${config.sources.length !== 1 ? "s" : ""}`);
|
|
2737
|
+
for (const s of config.sources) spinner12.info(` ${import_termkit17.Color.white.encoder(s)}`);
|
|
2738
|
+
spinner12.stop();
|
|
2745
2739
|
process.stdin.resume();
|
|
2746
2740
|
};
|
|
2747
2741
|
var watch_default = watch;
|
|
2748
2742
|
|
|
2749
2743
|
// package.json
|
|
2750
|
-
var version = "0.2.
|
|
2744
|
+
var version = "0.2.8";
|
|
2751
2745
|
|
|
2752
2746
|
// src/program.ts
|
|
2753
2747
|
var toCamel = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
@@ -2756,8 +2750,8 @@ var adapt = (fn) => (options) => {
|
|
|
2756
2750
|
setVerbose(!!camel.verbose);
|
|
2757
2751
|
return fn(camel);
|
|
2758
2752
|
};
|
|
2759
|
-
var { command, option } =
|
|
2760
|
-
var program =
|
|
2753
|
+
var { command, option } = import_termkit18.Program;
|
|
2754
|
+
var program = import_termkit18.Program.command("reelsort").version(version).description("a cli to manage media").commands([
|
|
2761
2755
|
command("config").description("manage configuration").commands([
|
|
2762
2756
|
command("source").description("manage source directories").commands([command("add", "<dir>").description("add a source directory").action(adapt(sourceAdd)), command("remove", "[dir]").description("remove a source directory").action(adapt(sourceRemove))]),
|
|
2763
2757
|
command("dest").description("manage destinations").commands([command("add", "<type> <dir>").description("set a destination (movie, tv, ps3, book)").action(adapt(destAdd)), command("remove", "[type]").description("remove a destination (movie, tv, ps3, book)").action(adapt(destRemove))]),
|
|
@@ -2795,8 +2789,8 @@ var run = async (args) => {
|
|
|
2795
2789
|
try {
|
|
2796
2790
|
await program_default.parse(args);
|
|
2797
2791
|
} catch (err) {
|
|
2798
|
-
|
|
2799
|
-
|
|
2792
|
+
import_termkit19.Spinner.current?.fail(err.message);
|
|
2793
|
+
import_termkit19.Spinner.current?.stop();
|
|
2800
2794
|
}
|
|
2801
2795
|
process.exit();
|
|
2802
2796
|
};
|