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/index.js CHANGED
@@ -34,12 +34,12 @@ __export(index_exports, {
34
34
  DEFAULT_MOVIE_FORMAT: () => DEFAULT_MOVIE_FORMAT,
35
35
  DEFAULT_SEASON_FORMAT: () => DEFAULT_SEASON_FORMAT,
36
36
  clean: () => clean_default,
37
- configAdd: () => configAdd,
38
- configRemove: () => configRemove,
39
37
  configSet: () => configSet,
40
38
  configShow: () => configShow,
41
39
  deleteImport: () => deleteImport,
42
40
  deleteSession: () => deleteSession,
41
+ destAdd: () => destAdd,
42
+ destRemove: () => destRemove,
43
43
  detectEdition: () => detectEdition,
44
44
  differences: () => differences_default,
45
45
  formatEpisode: () => formatEpisode,
@@ -64,6 +64,8 @@ __export(index_exports, {
64
64
  reset: () => reset_default,
65
65
  saveConfig: () => saveConfig,
66
66
  scan: () => scan_default,
67
+ sourceAdd: () => sourceAdd,
68
+ sourceRemove: () => sourceRemove,
67
69
  titleCase: () => titleCase_default,
68
70
  undo: () => undo_default,
69
71
  upsertMediaInfo: () => upsertMediaInfo,
@@ -73,8 +75,8 @@ __export(index_exports, {
73
75
  module.exports = __toCommonJS(index_exports);
74
76
 
75
77
  // src/actions/clean.ts
76
- var import_cosmetic = __toESM(require("cosmetic"));
77
78
  var import_fs2 = require("fs");
79
+ var import_termkit2 = require("termkit");
78
80
 
79
81
  // src/db.ts
80
82
  var import_better_sqlite3 = __toESM(require("better-sqlite3"));
@@ -205,28 +207,21 @@ var getHistory = (limit = 10) => {
205
207
  };
206
208
 
207
209
  // src/refs/spinner.ts
208
- var import_termpulse = require("termpulse");
210
+ var import_termkit = require("termkit");
209
211
  var Spinner = class {
210
212
  spinner;
211
- _isSpinning = false;
212
- _text = "";
213
213
  constructor() {
214
- this.spinner = new import_termpulse.Spinner();
214
+ this.spinner = new import_termkit.Spinner();
215
215
  }
216
216
  get text() {
217
- return this._text;
217
+ return this.spinner.text;
218
218
  }
219
219
  set text(t) {
220
- this._text = t;
221
- if (this._isSpinning) this.spinner.message(t);
222
- }
223
- get isSpinning() {
224
- return this._isSpinning;
220
+ this.spinner.text = t;
225
221
  }
226
222
  start(s) {
227
- if (s) this._text = s;
223
+ if (s) this.spinner.text = s;
228
224
  this.spinner.start();
229
- this._isSpinning = true;
230
225
  return this;
231
226
  }
232
227
  info(s) {
@@ -247,8 +242,6 @@ var Spinner = class {
247
242
  }
248
243
  stop() {
249
244
  this.spinner.stop();
250
- this._isSpinning = false;
251
- process.stdin.resume();
252
245
  return this;
253
246
  }
254
247
  };
@@ -287,17 +280,17 @@ var clean = async ({ dryRun, olderThan }) => {
287
280
  continue;
288
281
  }
289
282
  if (dryRun) {
290
- spinner_default.succeed(`[dry] would remove ${import_cosmetic.default.blue.encoder(imp.sourcePath)}`);
283
+ spinner_default.succeed(`[dry] would remove ${import_termkit2.Color.blue.encoder(imp.sourcePath)}`);
291
284
  cleaned++;
292
285
  continue;
293
286
  }
294
287
  try {
295
288
  (0, import_fs2.rmSync)(imp.sourcePath, { recursive: true, force: true });
296
289
  deleteImport(imp.id);
297
- spinner_default.succeed(`removed ${import_cosmetic.default.blue.encoder(imp.sourcePath)}`);
290
+ spinner_default.succeed(`removed ${import_termkit2.Color.blue.encoder(imp.sourcePath)}`);
298
291
  cleaned++;
299
292
  } catch {
300
- spinner_default.warn(`locked or inaccessible, skipped: ${import_cosmetic.default.blue.encoder(imp.sourcePath)}`);
293
+ spinner_default.warn(`locked or inaccessible, skipped: ${import_termkit2.Color.blue.encoder(imp.sourcePath)}`);
301
294
  skipped++;
302
295
  }
303
296
  }
@@ -308,8 +301,8 @@ var clean = async ({ dryRun, olderThan }) => {
308
301
  var clean_default = clean;
309
302
 
310
303
  // src/actions/config.ts
311
- var import_cosmetic2 = __toESM(require("cosmetic"));
312
304
  var import_path3 = require("path");
305
+ var import_termkit3 = require("termkit");
313
306
 
314
307
  // src/config.ts
315
308
  var import_fs3 = require("fs");
@@ -357,37 +350,64 @@ var formatMovieName = (template, title, year, edition) => {
357
350
 
358
351
  // src/actions/config.ts
359
352
  var DEST_TYPES = ["movie", "tv", "ps3"];
360
- var configAdd = async ({ key, value }) => {
361
- if (key !== "source") throw new Error(`unknown key '${key}', expected: source`);
362
- const dir = (0, import_path3.resolve)(value);
353
+ var sourceAdd = async ({ dir }) => {
354
+ const resolved = (0, import_path3.resolve)(dir);
363
355
  const config = getConfig();
364
- if (config.sources.includes(dir)) {
356
+ if (config.sources.includes(resolved)) {
365
357
  spinner_default.start();
366
- spinner_default.info(`source already configured: ${import_cosmetic2.default.blue.encoder(dir)}`);
358
+ spinner_default.info(`source already configured: ${import_termkit3.Color.blue.encoder(resolved)}`);
367
359
  spinner_default.stop();
368
360
  return;
369
361
  }
370
- config.sources.push(dir);
362
+ config.sources.push(resolved);
371
363
  saveConfig(config);
372
364
  spinner_default.start();
373
- spinner_default.succeed(`added source: ${import_cosmetic2.default.blue.encoder(dir)}`);
365
+ spinner_default.succeed(`added source: ${import_termkit3.Color.blue.encoder(resolved)}`);
374
366
  spinner_default.stop();
375
367
  };
376
- var configRemove = async ({ key, value }) => {
377
- if (key !== "source") throw new Error(`unknown key '${key}', expected: source`);
378
- const dir = (0, import_path3.resolve)(value);
368
+ var sourceRemove = async ({ dir }) => {
369
+ const resolved = (0, import_path3.resolve)(dir);
379
370
  const config = getConfig();
380
- const index = config.sources.indexOf(dir);
371
+ const index = config.sources.indexOf(resolved);
381
372
  if (index === -1) {
382
373
  spinner_default.start();
383
- spinner_default.warn(`source not found: ${import_cosmetic2.default.blue.encoder(dir)}`);
374
+ spinner_default.warn(`source not found: ${import_termkit3.Color.blue.encoder(resolved)}`);
384
375
  spinner_default.stop();
385
376
  return;
386
377
  }
387
378
  config.sources.splice(index, 1);
388
379
  saveConfig(config);
389
380
  spinner_default.start();
390
- spinner_default.succeed(`removed source: ${import_cosmetic2.default.blue.encoder(dir)}`);
381
+ spinner_default.succeed(`removed source: ${import_termkit3.Color.blue.encoder(resolved)}`);
382
+ spinner_default.stop();
383
+ };
384
+ var destAdd = async ({ type, dir }) => {
385
+ if (!DEST_TYPES.includes(type)) {
386
+ throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
387
+ }
388
+ const resolved = (0, import_path3.resolve)(dir);
389
+ const config = getConfig();
390
+ config.dest[type] = resolved;
391
+ saveConfig(config);
392
+ spinner_default.start();
393
+ spinner_default.succeed(`set ${type} destination: ${import_termkit3.Color.cyan.encoder(resolved)}`);
394
+ spinner_default.stop();
395
+ };
396
+ var destRemove = async ({ type }) => {
397
+ if (!DEST_TYPES.includes(type)) {
398
+ throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
399
+ }
400
+ const config = getConfig();
401
+ if (!config.dest[type]) {
402
+ spinner_default.start();
403
+ spinner_default.warn(`no ${type} destination configured`);
404
+ spinner_default.stop();
405
+ return;
406
+ }
407
+ delete config.dest[type];
408
+ saveConfig(config);
409
+ spinner_default.start();
410
+ spinner_default.succeed(`removed ${type} destination`);
391
411
  spinner_default.stop();
392
412
  };
393
413
  var configSet = async ({ key, subkey, value }) => {
@@ -396,7 +416,7 @@ var configSet = async ({ key, subkey, value }) => {
396
416
  config.language = subkey;
397
417
  saveConfig(config);
398
418
  spinner_default.start();
399
- spinner_default.succeed(`set subtitle language: ${import_cosmetic2.default.cyan.encoder(subkey)}`);
419
+ spinner_default.succeed(`set subtitle language: ${import_termkit3.Color.cyan.encoder(subkey)}`);
400
420
  spinner_default.stop();
401
421
  return;
402
422
  }
@@ -426,21 +446,11 @@ var configSet = async ({ key, subkey, value }) => {
426
446
  }
427
447
  saveConfig(config);
428
448
  spinner_default.start();
429
- spinner_default.succeed(`set ${subkey} format: ${import_cosmetic2.default.cyan.encoder(value ?? subkey)}`);
449
+ spinner_default.succeed(`set ${subkey} format: ${import_termkit3.Color.cyan.encoder(value ?? subkey)}`);
430
450
  spinner_default.stop();
431
451
  return;
432
452
  }
433
- if (key !== "dest") throw new Error(`unknown key '${key}', expected: dest, language, tmdb-key, format`);
434
- if (!DEST_TYPES.includes(subkey)) {
435
- throw new Error(`unknown type '${subkey}', expected: ${DEST_TYPES.join(", ")}`);
436
- }
437
- if (!value) throw new Error(`missing path for dest ${subkey}`);
438
- const dir = (0, import_path3.resolve)(value);
439
- config.dest[subkey] = dir;
440
- saveConfig(config);
441
- spinner_default.start();
442
- spinner_default.succeed(`set ${subkey} destination: ${import_cosmetic2.default.cyan.encoder(dir)}`);
443
- spinner_default.stop();
453
+ throw new Error(`unknown key '${key}', expected: language, tmdb-key, format`);
444
454
  };
445
455
  var configShow = async () => {
446
456
  const config = getConfig();
@@ -448,7 +458,7 @@ var configShow = async () => {
448
458
  if (config.sources.length === 0) {
449
459
  console.log(" (none)");
450
460
  } else {
451
- for (const s of config.sources) console.log(` ${import_cosmetic2.default.blue.encoder(s)}`);
461
+ for (const s of config.sources) console.log(` ${import_termkit3.Color.blue.encoder(s)}`);
452
462
  }
453
463
  console.log("\nDestinations:");
454
464
  const entries = DEST_TYPES.map((t) => ({ type: t, path: config.dest[t] })).filter((e) => e.path);
@@ -456,26 +466,26 @@ var configShow = async () => {
456
466
  console.log(" (none)");
457
467
  } else {
458
468
  for (const { type, path } of entries) {
459
- console.log(` ${type.padEnd(6)} ${import_cosmetic2.default.cyan.encoder(path)}`);
469
+ console.log(` ${type.padEnd(6)} ${import_termkit3.Color.cyan.encoder(path)}`);
460
470
  }
461
471
  }
462
472
  console.log(`
463
- Subtitle language: ${import_cosmetic2.default.cyan.encoder(config.language ?? "eng (default)")}`);
464
- console.log(`TMDb API key: ${config.tmdbApiKey ? import_cosmetic2.default.green.encoder("configured") : import_cosmetic2.default.red.encoder("not set")}`);
465
- console.log(`Movie format: ${import_cosmetic2.default.cyan.encoder(config.format?.movie ?? DEFAULT_MOVIE_FORMAT + " (default)")}`);
466
- console.log(`Episode format: ${import_cosmetic2.default.cyan.encoder(config.format?.episode ?? DEFAULT_EPISODE_FORMAT + " (default)")}`);
467
- console.log(`Season folder: ${import_cosmetic2.default.cyan.encoder(config.format?.season ?? DEFAULT_SEASON_FORMAT + " (default)")}`);
473
+ Subtitle language: ${import_termkit3.Color.cyan.encoder(config.language ?? "eng (default)")}`);
474
+ console.log(`TMDb API key: ${config.tmdbApiKey ? import_termkit3.Color.green.encoder("configured") : import_termkit3.Color.red.encoder("not set")}`);
475
+ console.log(`Movie format: ${import_termkit3.Color.cyan.encoder(config.format?.movie ?? DEFAULT_MOVIE_FORMAT + " (default)")}`);
476
+ console.log(`Episode format: ${import_termkit3.Color.cyan.encoder(config.format?.episode ?? DEFAULT_EPISODE_FORMAT + " (default)")}`);
477
+ console.log(`Season folder: ${import_termkit3.Color.cyan.encoder(config.format?.season ?? DEFAULT_SEASON_FORMAT + " (default)")}`);
468
478
  console.log();
469
479
  };
470
480
 
471
481
  // src/actions/differences.ts
472
- var import_cosmetic3 = __toESM(require("cosmetic"));
473
482
  var import_fs4 = require("fs");
474
483
  var import_path4 = require("path");
484
+ var import_termkit4 = require("termkit");
475
485
  var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
476
486
  let dir1 = rawDir1;
477
487
  let dir2 = rawDir2;
478
- spinner_default.text = `checking differences between ${import_cosmetic3.default.blue.encoder(dir1)} and ${import_cosmetic3.default.blue.encoder(dir2)}`;
488
+ spinner_default.text = `checking differences between ${import_termkit4.Color.blue.encoder(dir1)} and ${import_termkit4.Color.blue.encoder(dir2)}`;
479
489
  spinner_default.start();
480
490
  dir1 = (0, import_path4.resolve)(dir1);
481
491
  dir2 = (0, import_path4.resolve)(dir2);
@@ -511,18 +521,18 @@ var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
511
521
  removed.push(l);
512
522
  }
513
523
  }
514
- spinner_default.succeed(`checked differences between ${import_cosmetic3.default.blue.encoder(dir1)} and ${import_cosmetic3.default.blue.encoder(dir2)}`);
524
+ spinner_default.succeed(`checked differences between ${import_termkit4.Color.blue.encoder(dir1)} and ${import_termkit4.Color.blue.encoder(dir2)}`);
515
525
  spinner_default.succeed(`found ${added.length} added files`);
516
526
  spinner_default.succeed(`found ${removed.length} removed files`);
517
527
  spinner_default.stop();
518
- for (const i of added) console.log(`${import_cosmetic3.default.green.encoder("added")} ${i}`);
519
- for (const i of removed) console.log(`${import_cosmetic3.default.red.encoder("removed")} ${i}`);
528
+ for (const i of added) console.log(`${import_termkit4.Color.green.encoder("added")} ${i}`);
529
+ for (const i of removed) console.log(`${import_termkit4.Color.red.encoder("removed")} ${i}`);
520
530
  };
521
531
  var differences_default = differences;
522
532
 
523
533
  // src/actions/history.ts
524
- var import_cosmetic4 = __toESM(require("cosmetic"));
525
534
  var import_path5 = require("path");
535
+ var import_termkit5 = require("termkit");
526
536
  var history = async ({ limit, imports }) => {
527
537
  if (imports) {
528
538
  const sessions = getImportHistory(limit ?? 10);
@@ -534,11 +544,11 @@ var history = async ({ limit, imports }) => {
534
544
  const date = new Date(session.sessionId);
535
545
  const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
536
546
  console.log(`
537
- ${import_cosmetic4.default.yellow.encoder(label)} (${session.records.length} item${session.records.length !== 1 ? "s" : ""})`);
547
+ ${import_termkit5.Color.yellow.encoder(label)} (${session.records.length} item${session.records.length !== 1 ? "s" : ""})`);
538
548
  for (const r of session.records) {
539
549
  const src = (0, import_path5.basename)(r.sourcePath);
540
- const dest = import_cosmetic4.default.cyan.encoder(r.destinationPath);
541
- const mode = r.mode !== "move" ? ` ${import_cosmetic4.default.blue.encoder(`[${r.mode}]`)}` : "";
550
+ const dest = import_termkit5.Color.cyan.encoder(r.destinationPath);
551
+ const mode = r.mode !== "move" ? ` ${import_termkit5.Color.blue.encoder(`[${r.mode}]`)}` : "";
542
552
  console.log(` ${src} \u2192 ${dest}${mode}`);
543
553
  }
544
554
  }
@@ -553,11 +563,11 @@ ${import_cosmetic4.default.yellow.encoder(label)} (${session.records.length} it
553
563
  const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
554
564
  const folders = session.records.filter((r) => (0, import_path5.extname)(r.newPath) === "");
555
565
  console.log(`
556
- ${import_cosmetic4.default.yellow.encoder(label)} (${folders.length} item${folders.length !== 1 ? "s" : ""})`);
566
+ ${import_termkit5.Color.yellow.encoder(label)} (${folders.length} item${folders.length !== 1 ? "s" : ""})`);
557
567
  for (const r of folders) {
558
568
  const oldName = (0, import_path5.basename)(r.oldPath);
559
569
  const newName = (0, import_path5.basename)(r.newPath);
560
- console.log(` ${import_cosmetic4.default.blue.encoder(oldName)} \u2192 ${import_cosmetic4.default.cyan.encoder(newName)}`);
570
+ console.log(` ${import_termkit5.Color.blue.encoder(oldName)} \u2192 ${import_termkit5.Color.cyan.encoder(newName)}`);
561
571
  }
562
572
  }
563
573
  }
@@ -566,9 +576,9 @@ ${import_cosmetic4.default.yellow.encoder(label)} (${folders.length} item${fold
566
576
  var history_default = history;
567
577
 
568
578
  // src/actions/list.ts
569
- var import_cosmetic5 = __toESM(require("cosmetic"));
570
579
  var import_fs6 = require("fs");
571
580
  var import_path7 = require("path");
581
+ var import_termkit6 = require("termkit");
572
582
 
573
583
  // src/helpers/dirSize.ts
574
584
  var import_fs5 = require("fs");
@@ -700,7 +710,6 @@ var parseLibraryFolder = (name) => {
700
710
  if (match) return { title: match[1].trim(), year: parseInt(match[2]) };
701
711
  return { title: name };
702
712
  };
703
- var col = (s, width) => s.padEnd(width).substring(0, width);
704
713
  var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter, sort }) => {
705
714
  const config = getConfig();
706
715
  const types = (type ? [type] : DEST_TYPES2).filter((t) => config.dest[t]);
@@ -709,7 +718,7 @@ var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter
709
718
  const destRoot = config.dest[t];
710
719
  if (!(0, import_fs6.existsSync)(destRoot)) {
711
720
  console.log(`
712
- ${t.toUpperCase()} ${import_cosmetic5.default.blue.encoder(destRoot)} (not found)`);
721
+ ${t.toUpperCase()} ${import_termkit6.Color.blue.encoder(destRoot)} (not found)`);
713
722
  continue;
714
723
  }
715
724
  const folders = (0, import_fs6.readdirSync)(destRoot).filter((f) => {
@@ -739,18 +748,29 @@ ${t.toUpperCase()} ${import_cosmetic5.default.blue.encoder(destRoot)} (not fou
739
748
  const yearDiff = (b.year ?? 0) - (a.year ?? 0);
740
749
  return yearDiff !== 0 ? yearDiff : a.title.localeCompare(b.title);
741
750
  });
742
- const titleW = Math.min(50, Math.max(10, ...filtered.map((e) => e.title.length)) + 2);
743
- const divider = "\u2500".repeat(titleW + 44);
744
751
  console.log(`
745
- ${import_cosmetic5.default.yellow.encoder(t.toUpperCase())} ${import_cosmetic5.default.blue.encoder(destRoot)}`);
746
- console.log(divider);
747
- console.log(`${"Title".padEnd(titleW)} ${"Year".padEnd(6)} ${"Res".padEnd(6)} ${"Codec".padEnd(6)} ${"Size".padEnd(10)} Sub`);
748
- console.log(divider);
749
- for (const e of filtered) {
750
- const sub = e.hasSub ? import_cosmetic5.default.green.encoder("\u2713") : import_cosmetic5.default.red.encoder("\u2717");
751
- console.log(`${col(e.title, titleW)} ${col(e.year?.toString() ?? "\u2014", 6)} ${col(e.resolution ?? "\u2014", 6)} ${col(e.codec ?? "\u2014", 6)} ${col(e.size, 10)} ${sub}`);
752
- }
753
- console.log(divider);
752
+ ${import_termkit6.Color.yellow.encoder(t.toUpperCase())} ${import_termkit6.Color.blue.encoder(destRoot)}`);
753
+ new import_termkit6.Table(
754
+ filtered.map((e) => ({
755
+ title: e.title,
756
+ year: e.year,
757
+ resolution: e.resolution,
758
+ codec: e.codec,
759
+ size: e.size,
760
+ sub: e.hasSub
761
+ })),
762
+ {
763
+ separator: " ",
764
+ columns: [
765
+ { key: "title", title: "Title" },
766
+ { key: "year", title: "Year", align: "right", value: (v) => v != null ? String(v) : "\u2014" },
767
+ { key: "resolution", title: "Res", value: (v) => v ?? "\u2014" },
768
+ { key: "codec", title: "Codec", value: (v) => v ?? "\u2014" },
769
+ { key: "size", title: "Size" },
770
+ { key: "sub", title: "Sub", value: (v) => v ? import_termkit6.Color.green.encoder("\u2713") : import_termkit6.Color.red.encoder("\u2717") }
771
+ ]
772
+ }
773
+ ).print();
754
774
  console.log(`${filtered.length} of ${entries.length} item${entries.length !== 1 ? "s" : ""}`);
755
775
  }
756
776
  console.log();
@@ -759,9 +779,9 @@ var list_default = list;
759
779
 
760
780
  // src/actions/probe.ts
761
781
  var import_child_process = require("child_process");
762
- var import_cosmetic6 = __toESM(require("cosmetic"));
763
782
  var import_fs7 = require("fs");
764
783
  var import_path8 = require("path");
784
+ var import_termkit7 = require("termkit");
765
785
  var DEST_TYPES3 = ["movie", "tv", "ps3"];
766
786
  var CODEC_MAP2 = {
767
787
  hevc: "x265",
@@ -837,7 +857,7 @@ var probe = async ({ type, force, verbose }) => {
837
857
  for (const t of types) {
838
858
  const destRoot = config.dest[t];
839
859
  if (!(0, import_fs7.existsSync)(destRoot)) continue;
840
- spinner_default.text = `scanning ${import_cosmetic6.default.blue.encoder(destRoot)}`;
860
+ spinner_default.text = `scanning ${import_termkit7.Color.blue.encoder(destRoot)}`;
841
861
  const files = walkVideoFiles(destRoot);
842
862
  for (const filePath of files) {
843
863
  if (!force && getMediaInfo(filePath)) {
@@ -845,7 +865,7 @@ var probe = async ({ type, force, verbose }) => {
845
865
  skipped++;
846
866
  continue;
847
867
  }
848
- spinner_default.text = `probing ${import_cosmetic6.default.blue.encoder(filePath)}`;
868
+ spinner_default.text = `probing ${import_termkit7.Color.blue.encoder(filePath)}`;
849
869
  const result = runFfprobe(filePath);
850
870
  if (!result) {
851
871
  if (verbose) spinner_default.warn(`ffprobe failed: ${filePath}`);
@@ -865,10 +885,10 @@ var probe = async ({ type, force, verbose }) => {
865
885
  var probe_default = probe;
866
886
 
867
887
  // src/actions/rename.ts
868
- var import_cosmetic7 = __toESM(require("cosmetic"));
869
888
  var import_fs8 = require("fs");
870
889
  var import_path9 = require("path");
871
890
  var import_rimraf = require("rimraf");
891
+ var import_termkit8 = require("termkit");
872
892
 
873
893
  // src/helpers/findSubtitle.ts
874
894
  var LANGUAGE_ALIASES = {
@@ -929,13 +949,13 @@ var rename = async ({ dir: inputDir, type, verbose }) => {
929
949
  const config = getConfig();
930
950
  const language = config.language ?? "eng";
931
951
  const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
932
- spinner_default.text = `renaming in ${import_cosmetic7.default.blue.encoder(dir)}`;
952
+ spinner_default.text = `renaming in ${import_termkit8.Color.blue.encoder(dir)}`;
933
953
  spinner_default.start();
934
954
  if (!(0, import_fs8.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
935
955
  const list2 = (0, import_fs8.readdirSync)(dir);
936
956
  let renamed = 0, removed = 0, skipped = 0;
937
957
  for (const [index, entry] of list2.entries()) {
938
- spinner_default.text = `renaming in ${import_cosmetic7.default.blue.encoder(dir)} ${index + 1}/${list2.length}`;
958
+ spinner_default.text = `renaming in ${import_termkit8.Color.blue.encoder(dir)} ${index + 1}/${list2.length}`;
939
959
  if (!(0, import_fs8.lstatSync)((0, import_path9.resolve)(dir, entry)).isDirectory()) {
940
960
  if (verbose) spinner_default.info(`skipped ${entry}`);
941
961
  skipped++;
@@ -1020,18 +1040,18 @@ var rename = async ({ dir: inputDir, type, verbose }) => {
1020
1040
  spinner_default.succeed(`renamed ${renamed} files`);
1021
1041
  if (removed) spinner_default.info(`removed ${removed} files`);
1022
1042
  spinner_default.info(`skipped ${skipped} files`);
1023
- spinner_default.succeed(`done in ${import_cosmetic7.default.cyan.encoder(dir)}`);
1043
+ spinner_default.succeed(`done in ${import_termkit8.Color.cyan.encoder(dir)}`);
1024
1044
  spinner_default.stop();
1025
1045
  };
1026
1046
  var rename_default = rename;
1027
1047
 
1028
1048
  // src/actions/reset.ts
1029
- var import_cosmetic8 = __toESM(require("cosmetic"));
1030
1049
  var import_fs9 = require("fs");
1031
1050
  var import_path10 = require("path");
1051
+ var import_termkit9 = require("termkit");
1032
1052
  var reset = async ({ dir: inputDir, double }) => {
1033
1053
  let dir = inputDir;
1034
- spinner_default.text = `resetting episodes in ${import_cosmetic8.default.blue.encoder(dir)}`;
1054
+ spinner_default.text = `resetting episodes in ${import_termkit9.Color.blue.encoder(dir)}`;
1035
1055
  spinner_default.start();
1036
1056
  dir = (0, import_path10.resolve)(dir);
1037
1057
  if (!(0, import_fs9.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
@@ -1060,7 +1080,7 @@ var reset = async ({ dir: inputDir, double }) => {
1060
1080
  const episodeFormat = getConfig().format?.episode;
1061
1081
  let renamed = 0, skipped = other.length;
1062
1082
  for (const [index, i] of sublist.entries()) {
1063
- spinner_default.text = `resetting episodes in ${import_cosmetic8.default.blue.encoder(dir)} ${index}/${list2.length}`;
1083
+ spinner_default.text = `resetting episodes in ${import_termkit9.Color.blue.encoder(dir)} ${index}/${list2.length}`;
1064
1084
  const ext = i.match(/([^.]+$)/)?.[0];
1065
1085
  const episode = double ? index * 2 + 1 : index + 1;
1066
1086
  const name = `${formatEpisode(seasonNum, episode, episodeFormat, double, showTitle)}.${ext}`;
@@ -1073,16 +1093,15 @@ var reset = async ({ dir: inputDir, double }) => {
1073
1093
  }
1074
1094
  spinner_default.succeed(`renamed ${renamed} files`);
1075
1095
  spinner_default.info(`skipped ${skipped} files`);
1076
- spinner_default.succeed(`done in ${import_cosmetic8.default.cyan.encoder(dir)}`);
1096
+ spinner_default.succeed(`done in ${import_termkit9.Color.cyan.encoder(dir)}`);
1077
1097
  spinner_default.stop();
1078
1098
  };
1079
1099
  var reset_default = reset;
1080
1100
 
1081
1101
  // src/actions/scan.ts
1082
- var import_cosmetic9 = __toESM(require("cosmetic"));
1083
1102
  var import_fs10 = require("fs");
1084
1103
  var import_path11 = require("path");
1085
- var import_termpulse2 = require("termpulse");
1104
+ var import_termkit10 = require("termkit");
1086
1105
 
1087
1106
  // src/helpers/detectEdition.ts
1088
1107
  var EDITIONS = [
@@ -1248,10 +1267,10 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto }) => {
1248
1267
  let imported = 0, skipped = 0;
1249
1268
  for (const source of config.sources) {
1250
1269
  if (!(0, import_fs10.existsSync)(source)) {
1251
- spinner_default.warn(`source not found: ${import_cosmetic9.default.blue.encoder(source)}`);
1270
+ spinner_default.warn(`source not found: ${import_termkit10.Color.blue.encoder(source)}`);
1252
1271
  continue;
1253
1272
  }
1254
- spinner_default.text = `scanning ${import_cosmetic9.default.blue.encoder(source)}`;
1273
+ spinner_default.text = `scanning ${import_termkit10.Color.blue.encoder(source)}`;
1255
1274
  for (const entry of (0, import_fs10.readdirSync)(source)) {
1256
1275
  const entryPath = (0, import_path11.resolve)(source, entry);
1257
1276
  const isDir = (0, import_fs10.lstatSync)(entryPath).isDirectory();
@@ -1318,7 +1337,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto }) => {
1318
1337
  resolvedYear = results[0].year ?? parsed.year;
1319
1338
  } else if (results.length > 1) {
1320
1339
  spinner_default.stop();
1321
- const select = new import_termpulse2.Select();
1340
+ const select = new import_termkit10.Select();
1322
1341
  const items = results.map((r) => ({
1323
1342
  label: r.year ? `${r.title} (${r.year})` : r.title,
1324
1343
  description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
@@ -1485,8 +1504,8 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto }) => {
1485
1504
  var scan_default = scan;
1486
1505
 
1487
1506
  // src/actions/undo.ts
1488
- var import_cosmetic10 = __toESM(require("cosmetic"));
1489
1507
  var import_fs11 = require("fs");
1508
+ var import_termkit11 = require("termkit");
1490
1509
  var undo = async () => {
1491
1510
  spinner_default.start();
1492
1511
  const records = getLastSession();
@@ -1498,7 +1517,7 @@ var undo = async () => {
1498
1517
  let undone = 0;
1499
1518
  for (const record of records) {
1500
1519
  (0, import_fs11.renameSync)(record.newPath, record.oldPath);
1501
- spinner_default.succeed(`${import_cosmetic10.default.cyan.encoder(record.newPath)} \u2192 ${import_cosmetic10.default.blue.encoder(record.oldPath)}`);
1520
+ spinner_default.succeed(`${import_termkit11.Color.cyan.encoder(record.newPath)} \u2192 ${import_termkit11.Color.blue.encoder(record.oldPath)}`);
1502
1521
  undone++;
1503
1522
  }
1504
1523
  deleteSession(records[0].sessionId);
@@ -1509,9 +1528,9 @@ var undo_default = undo;
1509
1528
 
1510
1529
  // src/actions/watch.ts
1511
1530
  var import_chokidar = __toESM(require("chokidar"));
1512
- var import_cosmetic11 = __toESM(require("cosmetic"));
1513
1531
  var import_fs12 = require("fs");
1514
1532
  var import_path12 = require("path");
1533
+ var import_termkit12 = require("termkit");
1515
1534
  var sameDev2 = (a, b) => {
1516
1535
  try {
1517
1536
  let bExisting = b;
@@ -1582,7 +1601,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
1582
1601
  }
1583
1602
  moveItem(entryPath, destPath);
1584
1603
  recordImport(sessionId, entryPath, destPath, "move");
1585
- spinner_default.succeed(`imported ${import_cosmetic11.default.cyan.encoder(destName)}`);
1604
+ spinner_default.succeed(`imported ${import_termkit12.Color.cyan.encoder(destName)}`);
1586
1605
  return;
1587
1606
  }
1588
1607
  const parsed = parseDownloadName(entry);
@@ -1655,7 +1674,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
1655
1674
  if (isDir) (0, import_fs12.rmSync)(entryPath, { recursive: true, force: true });
1656
1675
  }
1657
1676
  recordImport(sessionId, entryPath, seasonPath, mode);
1658
- spinner_default.succeed(`imported ${import_cosmetic11.default.cyan.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
1677
+ spinner_default.succeed(`imported ${import_termkit12.Color.cyan.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
1659
1678
  return;
1660
1679
  }
1661
1680
  const edition = detectEdition(entry);
@@ -1712,7 +1731,7 @@ var processItem = async (entryPath, useHardlink, verbose, language, auto) => {
1712
1731
  }
1713
1732
  recordImport(sessionId, entryPath, destFolder, "move");
1714
1733
  }
1715
- spinner_default.succeed(`imported ${import_cosmetic11.default.cyan.encoder(folderName)}`);
1734
+ spinner_default.succeed(`imported ${import_termkit12.Color.cyan.encoder(folderName)}`);
1716
1735
  };
1717
1736
  var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
1718
1737
  const config = getConfig();
@@ -1743,7 +1762,7 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
1743
1762
  watcher.on("add", handle);
1744
1763
  spinner_default.start();
1745
1764
  spinner_default.succeed(`watching ${config.sources.length} source${config.sources.length !== 1 ? "s" : ""}`);
1746
- for (const s of config.sources) spinner_default.info(` ${import_cosmetic11.default.blue.encoder(s)}`);
1765
+ for (const s of config.sources) spinner_default.info(` ${import_termkit12.Color.blue.encoder(s)}`);
1747
1766
  spinner_default.stop();
1748
1767
  process.stdin.resume();
1749
1768
  };
@@ -1754,12 +1773,12 @@ var watch_default = watch;
1754
1773
  DEFAULT_MOVIE_FORMAT,
1755
1774
  DEFAULT_SEASON_FORMAT,
1756
1775
  clean,
1757
- configAdd,
1758
- configRemove,
1759
1776
  configSet,
1760
1777
  configShow,
1761
1778
  deleteImport,
1762
1779
  deleteSession,
1780
+ destAdd,
1781
+ destRemove,
1763
1782
  detectEdition,
1764
1783
  differences,
1765
1784
  formatEpisode,
@@ -1784,6 +1803,8 @@ var watch_default = watch;
1784
1803
  reset,
1785
1804
  saveConfig,
1786
1805
  scan,
1806
+ sourceAdd,
1807
+ sourceRemove,
1787
1808
  titleCase,
1788
1809
  undo,
1789
1810
  upsertMediaInfo,