reelsort 0.2.6 → 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 +360 -321
- package/dist/index.js +284 -251
- package/dist/index.mjs +251 -218
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -78,7 +78,7 @@ module.exports = __toCommonJS(index_exports);
|
|
|
78
78
|
|
|
79
79
|
// src/actions/clean.ts
|
|
80
80
|
var import_fs2 = require("fs");
|
|
81
|
-
var
|
|
81
|
+
var import_termkit = require("termkit");
|
|
82
82
|
|
|
83
83
|
// src/db.ts
|
|
84
84
|
var import_better_sqlite3 = __toESM(require("better-sqlite3"));
|
|
@@ -220,48 +220,8 @@ var getHistory = (limit = 10) => {
|
|
|
220
220
|
}));
|
|
221
221
|
};
|
|
222
222
|
|
|
223
|
-
// src/refs/spinner.ts
|
|
224
|
-
var import_termkit = require("termkit");
|
|
225
|
-
var Spinner = class {
|
|
226
|
-
spinner;
|
|
227
|
-
constructor() {
|
|
228
|
-
this.spinner = new import_termkit.Spinner();
|
|
229
|
-
}
|
|
230
|
-
get text() {
|
|
231
|
-
return this.spinner.text;
|
|
232
|
-
}
|
|
233
|
-
set text(t) {
|
|
234
|
-
this.spinner.text = t;
|
|
235
|
-
}
|
|
236
|
-
start(s) {
|
|
237
|
-
if (s) this.spinner.text = s;
|
|
238
|
-
this.spinner.start();
|
|
239
|
-
return this;
|
|
240
|
-
}
|
|
241
|
-
info(s) {
|
|
242
|
-
this.spinner.info(s);
|
|
243
|
-
return this;
|
|
244
|
-
}
|
|
245
|
-
warn(s) {
|
|
246
|
-
this.spinner.warn(s);
|
|
247
|
-
return this;
|
|
248
|
-
}
|
|
249
|
-
fail(s) {
|
|
250
|
-
this.spinner.fail(s);
|
|
251
|
-
return this;
|
|
252
|
-
}
|
|
253
|
-
succeed(s) {
|
|
254
|
-
this.spinner.succeed(s);
|
|
255
|
-
return this;
|
|
256
|
-
}
|
|
257
|
-
stop() {
|
|
258
|
-
this.spinner.stop();
|
|
259
|
-
return this;
|
|
260
|
-
}
|
|
261
|
-
};
|
|
262
|
-
var spinner_default = new Spinner();
|
|
263
|
-
|
|
264
223
|
// src/actions/clean.ts
|
|
224
|
+
var spinner = new import_termkit.Spinner();
|
|
265
225
|
var parseOlderThan = (s) => {
|
|
266
226
|
const match = s.match(/^(\d+)([dhm])$/);
|
|
267
227
|
if (!match) return null;
|
|
@@ -271,11 +231,11 @@ var parseOlderThan = (s) => {
|
|
|
271
231
|
return ms;
|
|
272
232
|
};
|
|
273
233
|
var clean = async ({ dryRun, olderThan }) => {
|
|
274
|
-
|
|
234
|
+
spinner.start();
|
|
275
235
|
const imports = getCleanableImports();
|
|
276
236
|
if (imports.length === 0) {
|
|
277
|
-
|
|
278
|
-
|
|
237
|
+
spinner.info("nothing to clean");
|
|
238
|
+
spinner.stop();
|
|
279
239
|
return;
|
|
280
240
|
}
|
|
281
241
|
const cutoffMs = olderThan ? parseOlderThan(olderThan) : null;
|
|
@@ -294,29 +254,29 @@ var clean = async ({ dryRun, olderThan }) => {
|
|
|
294
254
|
continue;
|
|
295
255
|
}
|
|
296
256
|
if (dryRun) {
|
|
297
|
-
|
|
257
|
+
spinner.succeed(`[dry] would remove ${import_termkit.Color.white.encoder(imp.sourcePath)}`);
|
|
298
258
|
cleaned++;
|
|
299
259
|
continue;
|
|
300
260
|
}
|
|
301
261
|
try {
|
|
302
262
|
(0, import_fs2.rmSync)(imp.sourcePath, { recursive: true, force: true });
|
|
303
263
|
deleteImport(imp.id);
|
|
304
|
-
|
|
264
|
+
spinner.succeed(`removed ${import_termkit.Color.white.encoder(imp.sourcePath)}`);
|
|
305
265
|
cleaned++;
|
|
306
266
|
} catch {
|
|
307
|
-
|
|
267
|
+
spinner.warn(`locked or inaccessible, skipped: ${import_termkit.Color.white.encoder(imp.sourcePath)}`);
|
|
308
268
|
skipped++;
|
|
309
269
|
}
|
|
310
270
|
}
|
|
311
|
-
|
|
312
|
-
if (skipped)
|
|
313
|
-
|
|
271
|
+
spinner.succeed(`cleaned ${cleaned} items`);
|
|
272
|
+
if (skipped) spinner.info(`skipped ${skipped} items`);
|
|
273
|
+
spinner.stop();
|
|
314
274
|
};
|
|
315
275
|
var clean_default = clean;
|
|
316
276
|
|
|
317
277
|
// src/actions/config.ts
|
|
318
278
|
var import_path3 = require("path");
|
|
319
|
-
var
|
|
279
|
+
var import_termkit2 = require("termkit");
|
|
320
280
|
|
|
321
281
|
// src/config.ts
|
|
322
282
|
var import_fs3 = require("fs");
|
|
@@ -363,32 +323,33 @@ var formatMovieName = (template, title, year, edition) => {
|
|
|
363
323
|
};
|
|
364
324
|
|
|
365
325
|
// src/actions/config.ts
|
|
326
|
+
var spinner2 = new import_termkit2.Spinner();
|
|
366
327
|
var DEST_TYPES = ["movie", "tv", "ps3", "book"];
|
|
367
328
|
var sourceAdd = async ({ dir }) => {
|
|
368
329
|
const resolved = (0, import_path3.resolve)(dir);
|
|
369
330
|
const config = getConfig();
|
|
370
331
|
if (config.sources.includes(resolved)) {
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
332
|
+
spinner2.start();
|
|
333
|
+
spinner2.info(`source already configured: ${import_termkit2.Color.white.encoder(resolved)}`);
|
|
334
|
+
spinner2.stop();
|
|
374
335
|
return;
|
|
375
336
|
}
|
|
376
337
|
config.sources.push(resolved);
|
|
377
338
|
saveConfig(config);
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
339
|
+
spinner2.start();
|
|
340
|
+
spinner2.succeed(`added source: ${import_termkit2.Color.white.encoder(resolved)}`);
|
|
341
|
+
spinner2.stop();
|
|
381
342
|
};
|
|
382
343
|
var sourceRemove = async ({ dir }) => {
|
|
383
344
|
const config = getConfig();
|
|
384
345
|
if (!dir) {
|
|
385
346
|
if (config.sources.length === 0) {
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
347
|
+
spinner2.start();
|
|
348
|
+
spinner2.warn("no sources configured");
|
|
349
|
+
spinner2.stop();
|
|
389
350
|
return;
|
|
390
351
|
}
|
|
391
|
-
const select = new
|
|
352
|
+
const select = new import_termkit2.Select();
|
|
392
353
|
const picked = await select.ask("Which source do you want to remove?", config.sources.map((s) => ({ label: s, value: s })));
|
|
393
354
|
if (!picked) return;
|
|
394
355
|
dir = picked.value;
|
|
@@ -396,16 +357,16 @@ var sourceRemove = async ({ dir }) => {
|
|
|
396
357
|
const resolved = (0, import_path3.resolve)(dir);
|
|
397
358
|
const index = config.sources.indexOf(resolved);
|
|
398
359
|
if (index === -1) {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
360
|
+
spinner2.start();
|
|
361
|
+
spinner2.warn(`source not found: ${import_termkit2.Color.white.encoder(resolved)}`);
|
|
362
|
+
spinner2.stop();
|
|
402
363
|
return;
|
|
403
364
|
}
|
|
404
365
|
config.sources.splice(index, 1);
|
|
405
366
|
saveConfig(config);
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
367
|
+
spinner2.start();
|
|
368
|
+
spinner2.succeed(`removed source: ${import_termkit2.Color.white.encoder(resolved)}`);
|
|
369
|
+
spinner2.stop();
|
|
409
370
|
};
|
|
410
371
|
var destAdd = async ({ type, dir }) => {
|
|
411
372
|
if (!DEST_TYPES.includes(type)) {
|
|
@@ -415,21 +376,21 @@ var destAdd = async ({ type, dir }) => {
|
|
|
415
376
|
const config = getConfig();
|
|
416
377
|
config.dest[type] = resolved;
|
|
417
378
|
saveConfig(config);
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
379
|
+
spinner2.start();
|
|
380
|
+
spinner2.succeed(`set ${type} destination: ${import_termkit2.Color.green.encoder(resolved)}`);
|
|
381
|
+
spinner2.stop();
|
|
421
382
|
};
|
|
422
383
|
var destRemove = async ({ type }) => {
|
|
423
384
|
const config = getConfig();
|
|
424
385
|
if (!type) {
|
|
425
386
|
const configured = DEST_TYPES.filter((t) => config.dest[t]);
|
|
426
387
|
if (configured.length === 0) {
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
388
|
+
spinner2.start();
|
|
389
|
+
spinner2.warn("no destinations configured");
|
|
390
|
+
spinner2.stop();
|
|
430
391
|
return;
|
|
431
392
|
}
|
|
432
|
-
const select = new
|
|
393
|
+
const select = new import_termkit2.Select();
|
|
433
394
|
const picked = await select.ask("Which destination do you want to remove?", configured.map((t) => ({ label: `${t.padEnd(6)} ${config.dest[t]}`, value: t })));
|
|
434
395
|
if (!picked) return;
|
|
435
396
|
type = picked.value;
|
|
@@ -438,33 +399,33 @@ var destRemove = async ({ type }) => {
|
|
|
438
399
|
throw new Error(`unknown type '${type}', expected: ${DEST_TYPES.join(", ")}`);
|
|
439
400
|
}
|
|
440
401
|
if (!config.dest[type]) {
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
402
|
+
spinner2.start();
|
|
403
|
+
spinner2.warn(`no ${type} destination configured`);
|
|
404
|
+
spinner2.stop();
|
|
444
405
|
return;
|
|
445
406
|
}
|
|
446
407
|
delete config.dest[type];
|
|
447
408
|
saveConfig(config);
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
409
|
+
spinner2.start();
|
|
410
|
+
spinner2.succeed(`removed ${type} destination`);
|
|
411
|
+
spinner2.stop();
|
|
451
412
|
};
|
|
452
413
|
var configSet = async ({ key, subkey, value }) => {
|
|
453
414
|
const config = getConfig();
|
|
454
415
|
if (key === "language") {
|
|
455
416
|
config.language = subkey;
|
|
456
417
|
saveConfig(config);
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
418
|
+
spinner2.start();
|
|
419
|
+
spinner2.succeed(`set subtitle language: ${import_termkit2.Color.green.encoder(subkey)}`);
|
|
420
|
+
spinner2.stop();
|
|
460
421
|
return;
|
|
461
422
|
}
|
|
462
423
|
if (key === "tmdb-key") {
|
|
463
424
|
config.tmdbApiKey = subkey;
|
|
464
425
|
saveConfig(config);
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
426
|
+
spinner2.start();
|
|
427
|
+
spinner2.succeed(`set TMDb API key`);
|
|
428
|
+
spinner2.stop();
|
|
468
429
|
return;
|
|
469
430
|
}
|
|
470
431
|
if (key === "format") {
|
|
@@ -484,9 +445,9 @@ var configSet = async ({ key, subkey, value }) => {
|
|
|
484
445
|
throw new Error(`unknown format key '${subkey}', expected: movie, episode, season`);
|
|
485
446
|
}
|
|
486
447
|
saveConfig(config);
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
448
|
+
spinner2.start();
|
|
449
|
+
spinner2.succeed(`set ${subkey} format: ${import_termkit2.Color.green.encoder(value ?? subkey)}`);
|
|
450
|
+
spinner2.stop();
|
|
490
451
|
return;
|
|
491
452
|
}
|
|
492
453
|
throw new Error(`unknown key '${key}', expected: language, tmdb-key, format`);
|
|
@@ -497,7 +458,7 @@ var configShow = async () => {
|
|
|
497
458
|
if (config.sources.length === 0) {
|
|
498
459
|
console.log(" (none)");
|
|
499
460
|
} else {
|
|
500
|
-
for (const s of config.sources) console.log(` ${
|
|
461
|
+
for (const s of config.sources) console.log(` ${import_termkit2.Color.white.encoder(s)}`);
|
|
501
462
|
}
|
|
502
463
|
console.log("\nDestinations:");
|
|
503
464
|
const entries = DEST_TYPES.map((t) => ({ type: t, path: config.dest[t] })).filter((e) => e.path);
|
|
@@ -505,20 +466,20 @@ var configShow = async () => {
|
|
|
505
466
|
console.log(" (none)");
|
|
506
467
|
} else {
|
|
507
468
|
for (const { type, path } of entries) {
|
|
508
|
-
console.log(` ${type.padEnd(6)} ${
|
|
469
|
+
console.log(` ${type.padEnd(6)} ${import_termkit2.Color.green.encoder(path)}`);
|
|
509
470
|
}
|
|
510
471
|
}
|
|
511
472
|
console.log(`
|
|
512
|
-
Subtitle language: ${
|
|
513
|
-
console.log(`TMDb API key: ${config.tmdbApiKey ?
|
|
514
|
-
console.log(`Movie format: ${
|
|
515
|
-
console.log(`Episode format: ${
|
|
516
|
-
console.log(`Season folder: ${
|
|
473
|
+
Subtitle language: ${import_termkit2.Color.green.encoder(config.language ?? "eng (default)")}`);
|
|
474
|
+
console.log(`TMDb API key: ${config.tmdbApiKey ? import_termkit2.Color.green.encoder("configured") : import_termkit2.Color.red.encoder("not set")}`);
|
|
475
|
+
console.log(`Movie format: ${import_termkit2.Color.green.encoder(config.format?.movie ?? DEFAULT_MOVIE_FORMAT + " (default)")}`);
|
|
476
|
+
console.log(`Episode format: ${import_termkit2.Color.green.encoder(config.format?.episode ?? DEFAULT_EPISODE_FORMAT + " (default)")}`);
|
|
477
|
+
console.log(`Season folder: ${import_termkit2.Color.green.encoder(config.format?.season ?? DEFAULT_SEASON_FORMAT + " (default)")}`);
|
|
517
478
|
console.log("\nIgnored files:");
|
|
518
479
|
if (!config.ignore || config.ignore.length === 0) {
|
|
519
480
|
console.log(" (none)");
|
|
520
481
|
} else {
|
|
521
|
-
for (const name of config.ignore) console.log(` ${
|
|
482
|
+
for (const name of config.ignore) console.log(` ${import_termkit2.Color.white.encoder(name)}`);
|
|
522
483
|
}
|
|
523
484
|
console.log();
|
|
524
485
|
};
|
|
@@ -526,12 +487,13 @@ Subtitle language: ${import_termkit3.Color.green.encoder(config.language ?? "eng
|
|
|
526
487
|
// src/actions/differences.ts
|
|
527
488
|
var import_fs4 = require("fs");
|
|
528
489
|
var import_path4 = require("path");
|
|
529
|
-
var
|
|
490
|
+
var import_termkit3 = require("termkit");
|
|
491
|
+
var spinner3 = new import_termkit3.Spinner();
|
|
530
492
|
var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
|
|
531
493
|
let dir1 = rawDir1;
|
|
532
494
|
let dir2 = rawDir2;
|
|
533
|
-
|
|
534
|
-
|
|
495
|
+
spinner3.update(`checking differences between ${import_termkit3.Color.white.encoder(dir1)} and ${import_termkit3.Color.white.encoder(dir2)}`);
|
|
496
|
+
spinner3.start();
|
|
535
497
|
dir1 = (0, import_path4.resolve)(dir1);
|
|
536
498
|
dir2 = (0, import_path4.resolve)(dir2);
|
|
537
499
|
if (!(0, import_fs4.existsSync)(dir1)) throw new Error(`dir1 ${dir1} does not exist`);
|
|
@@ -566,18 +528,18 @@ var differences = async ({ dir1: rawDir1, dir2: rawDir2, only, ignore }) => {
|
|
|
566
528
|
removed.push(l);
|
|
567
529
|
}
|
|
568
530
|
}
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
for (const i of added) console.log(`${
|
|
574
|
-
for (const i of removed) console.log(`${
|
|
531
|
+
spinner3.succeed(`checked differences between ${import_termkit3.Color.white.encoder(dir1)} and ${import_termkit3.Color.white.encoder(dir2)}`);
|
|
532
|
+
spinner3.succeed(`found ${added.length} added files`);
|
|
533
|
+
spinner3.succeed(`found ${removed.length} removed files`);
|
|
534
|
+
spinner3.stop();
|
|
535
|
+
for (const i of added) console.log(`${import_termkit3.Color.green.encoder("added")} ${i}`);
|
|
536
|
+
for (const i of removed) console.log(`${import_termkit3.Color.red.encoder("removed")} ${i}`);
|
|
575
537
|
};
|
|
576
538
|
var differences_default = differences;
|
|
577
539
|
|
|
578
540
|
// src/actions/history.ts
|
|
579
541
|
var import_path5 = require("path");
|
|
580
|
-
var
|
|
542
|
+
var import_termkit4 = require("termkit");
|
|
581
543
|
var history = async ({ limit, imports }) => {
|
|
582
544
|
if (imports) {
|
|
583
545
|
const sessions = getImportHistory(limit ?? 10);
|
|
@@ -589,11 +551,11 @@ var history = async ({ limit, imports }) => {
|
|
|
589
551
|
const date = new Date(session.sessionId);
|
|
590
552
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
591
553
|
console.log(`
|
|
592
|
-
${
|
|
554
|
+
${import_termkit4.Color.yellow.encoder(label)} (${session.records.length} item${session.records.length !== 1 ? "s" : ""})`);
|
|
593
555
|
for (const r of session.records) {
|
|
594
556
|
const src = (0, import_path5.basename)(r.sourcePath);
|
|
595
|
-
const dest =
|
|
596
|
-
const mode = r.mode !== "move" ? ` ${
|
|
557
|
+
const dest = import_termkit4.Color.green.encoder(r.destinationPath);
|
|
558
|
+
const mode = r.mode !== "move" ? ` ${import_termkit4.Color.white.encoder(`[${r.mode}]`)}` : "";
|
|
597
559
|
console.log(` ${src} \u2192 ${dest}${mode}`);
|
|
598
560
|
}
|
|
599
561
|
}
|
|
@@ -608,11 +570,11 @@ ${import_termkit5.Color.yellow.encoder(label)} (${session.records.length} item$
|
|
|
608
570
|
const label = isNaN(date.getTime()) ? session.sessionId : date.toLocaleString();
|
|
609
571
|
const folders = session.records.filter((r) => (0, import_path5.extname)(r.newPath) === "");
|
|
610
572
|
console.log(`
|
|
611
|
-
${
|
|
573
|
+
${import_termkit4.Color.yellow.encoder(label)} (${folders.length} item${folders.length !== 1 ? "s" : ""})`);
|
|
612
574
|
for (const r of folders) {
|
|
613
575
|
const oldName = (0, import_path5.basename)(r.oldPath);
|
|
614
576
|
const newName = (0, import_path5.basename)(r.newPath);
|
|
615
|
-
console.log(` ${
|
|
577
|
+
console.log(` ${import_termkit4.Color.white.encoder(oldName)} \u2192 ${import_termkit4.Color.green.encoder(newName)}`);
|
|
616
578
|
}
|
|
617
579
|
}
|
|
618
580
|
}
|
|
@@ -623,7 +585,7 @@ var history_default = history;
|
|
|
623
585
|
// src/actions/list.ts
|
|
624
586
|
var import_fs6 = require("fs");
|
|
625
587
|
var import_path7 = require("path");
|
|
626
|
-
var
|
|
588
|
+
var import_termkit5 = require("termkit");
|
|
627
589
|
|
|
628
590
|
// src/helpers/dirSize.ts
|
|
629
591
|
var import_fs5 = require("fs");
|
|
@@ -763,7 +725,7 @@ var list = async ({ type, missingSubs, codec: codecFilter, resolution: resFilter
|
|
|
763
725
|
const destRoot = config.dest[t];
|
|
764
726
|
if (!(0, import_fs6.existsSync)(destRoot)) {
|
|
765
727
|
console.log(`
|
|
766
|
-
${t.toUpperCase()} ${
|
|
728
|
+
${t.toUpperCase()} ${import_termkit5.Color.white.encoder(destRoot)} (not found)`);
|
|
767
729
|
continue;
|
|
768
730
|
}
|
|
769
731
|
const folders = (0, import_fs6.readdirSync)(destRoot).filter((f) => {
|
|
@@ -794,8 +756,8 @@ ${t.toUpperCase()} ${import_termkit6.Color.white.encoder(destRoot)} (not found
|
|
|
794
756
|
return yearDiff !== 0 ? yearDiff : a.title.localeCompare(b.title);
|
|
795
757
|
});
|
|
796
758
|
console.log(`
|
|
797
|
-
${
|
|
798
|
-
new
|
|
759
|
+
${import_termkit5.Color.yellow.encoder(t.toUpperCase())} ${import_termkit5.Color.white.encoder(destRoot)}`);
|
|
760
|
+
new import_termkit5.Table(
|
|
799
761
|
filtered.map((e) => ({
|
|
800
762
|
title: e.title,
|
|
801
763
|
year: e.year,
|
|
@@ -812,7 +774,7 @@ ${import_termkit6.Color.yellow.encoder(t.toUpperCase())} ${import_termkit6.Colo
|
|
|
812
774
|
{ key: "resolution", title: "Res", value: (v) => v ?? "\u2014" },
|
|
813
775
|
{ key: "codec", title: "Codec", value: (v) => v ?? "\u2014" },
|
|
814
776
|
{ key: "size", title: "Size" },
|
|
815
|
-
{ key: "sub", title: "Sub", value: (v) => v ?
|
|
777
|
+
{ key: "sub", title: "Sub", value: (v) => v ? import_termkit5.Color.green.encoder("\u2713") : import_termkit5.Color.red.encoder("\u2717") }
|
|
816
778
|
]
|
|
817
779
|
}
|
|
818
780
|
).print();
|
|
@@ -826,13 +788,14 @@ var list_default = list;
|
|
|
826
788
|
var import_child_process = require("child_process");
|
|
827
789
|
var import_fs7 = require("fs");
|
|
828
790
|
var import_path8 = require("path");
|
|
829
|
-
var
|
|
791
|
+
var import_termkit6 = require("termkit");
|
|
830
792
|
|
|
831
793
|
// src/refs/verbose.ts
|
|
832
794
|
var _verbose = false;
|
|
833
795
|
var isVerbose = () => _verbose;
|
|
834
796
|
|
|
835
797
|
// src/actions/probe.ts
|
|
798
|
+
var spinner4 = new import_termkit6.Spinner();
|
|
836
799
|
var DEST_TYPES3 = ["movie", "tv", "ps3"];
|
|
837
800
|
var CODEC_MAP2 = {
|
|
838
801
|
hevc: "x265",
|
|
@@ -895,10 +858,10 @@ var walkVideoFiles = (dir, depth = 0, maxDepth = 3) => {
|
|
|
895
858
|
return results;
|
|
896
859
|
};
|
|
897
860
|
var probe = async ({ type, force }) => {
|
|
898
|
-
|
|
861
|
+
spinner4.start();
|
|
899
862
|
if (!isFfprobeAvailable()) {
|
|
900
|
-
|
|
901
|
-
|
|
863
|
+
spinner4.fail("ffprobe not found \u2014 install ffmpeg to use this command");
|
|
864
|
+
spinner4.stop();
|
|
902
865
|
return;
|
|
903
866
|
}
|
|
904
867
|
const config = getConfig();
|
|
@@ -908,30 +871,30 @@ var probe = async ({ type, force }) => {
|
|
|
908
871
|
for (const t of types) {
|
|
909
872
|
const destRoot = config.dest[t];
|
|
910
873
|
if (!(0, import_fs7.existsSync)(destRoot)) continue;
|
|
911
|
-
|
|
874
|
+
spinner4.update(`scanning ${import_termkit6.Color.white.encoder(destRoot)}`);
|
|
912
875
|
const files = walkVideoFiles(destRoot);
|
|
913
876
|
for (const filePath of files) {
|
|
914
877
|
if (!force && getMediaInfo(filePath)) {
|
|
915
|
-
if (isVerbose())
|
|
878
|
+
if (isVerbose()) spinner4.info(`already probed: ${filePath}`);
|
|
916
879
|
skipped++;
|
|
917
880
|
continue;
|
|
918
881
|
}
|
|
919
|
-
|
|
882
|
+
spinner4.update(`probing ${import_termkit6.Color.white.encoder(filePath)}`);
|
|
920
883
|
const result = runFfprobe(filePath);
|
|
921
884
|
if (!result) {
|
|
922
|
-
if (isVerbose())
|
|
885
|
+
if (isVerbose()) spinner4.warn(`ffprobe failed: ${filePath}`);
|
|
923
886
|
failed++;
|
|
924
887
|
continue;
|
|
925
888
|
}
|
|
926
889
|
upsertMediaInfo(filePath, result.codec, result.resolution, result.width, result.height, result.duration);
|
|
927
|
-
if (isVerbose())
|
|
890
|
+
if (isVerbose()) spinner4.succeed(`${result.resolution ?? "?"} ${result.codec ?? "?"} ${filePath}`);
|
|
928
891
|
probed++;
|
|
929
892
|
}
|
|
930
893
|
}
|
|
931
|
-
|
|
932
|
-
if (skipped)
|
|
933
|
-
if (failed)
|
|
934
|
-
|
|
894
|
+
spinner4.succeed(`probed ${probed} files`);
|
|
895
|
+
if (skipped) spinner4.info(`skipped ${skipped} already indexed`);
|
|
896
|
+
if (failed) spinner4.warn(`failed ${failed} files`);
|
|
897
|
+
spinner4.stop();
|
|
935
898
|
};
|
|
936
899
|
var probe_default = probe;
|
|
937
900
|
|
|
@@ -939,7 +902,7 @@ var probe_default = probe;
|
|
|
939
902
|
var import_fs8 = require("fs");
|
|
940
903
|
var import_path9 = require("path");
|
|
941
904
|
var import_rimraf = require("rimraf");
|
|
942
|
-
var
|
|
905
|
+
var import_termkit7 = require("termkit");
|
|
943
906
|
|
|
944
907
|
// src/helpers/findSubtitle.ts
|
|
945
908
|
var LANGUAGE_ALIASES = {
|
|
@@ -994,21 +957,22 @@ var titleCase_default = (s) => {
|
|
|
994
957
|
};
|
|
995
958
|
|
|
996
959
|
// src/actions/rename.ts
|
|
960
|
+
var spinner5 = new import_termkit7.Spinner();
|
|
997
961
|
var rename = async ({ dir: inputDir, type }) => {
|
|
998
962
|
const dir = (0, import_path9.resolve)(inputDir);
|
|
999
963
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
1000
964
|
const config = getConfig();
|
|
1001
965
|
const language = config.language ?? "eng";
|
|
1002
966
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1003
|
-
|
|
1004
|
-
|
|
967
|
+
spinner5.update(`renaming in ${import_termkit7.Color.white.encoder(dir)}`);
|
|
968
|
+
spinner5.start();
|
|
1005
969
|
if (!(0, import_fs8.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
1006
970
|
const list2 = (0, import_fs8.readdirSync)(dir);
|
|
1007
971
|
let renamed = 0, removed = 0, skipped = 0;
|
|
1008
972
|
for (const [index, entry] of list2.entries()) {
|
|
1009
|
-
|
|
973
|
+
spinner5.update(`renaming in ${import_termkit7.Color.white.encoder(dir)} ${index + 1}/${list2.length}`);
|
|
1010
974
|
if (!(0, import_fs8.lstatSync)((0, import_path9.resolve)(dir, entry)).isDirectory()) {
|
|
1011
|
-
if (isVerbose())
|
|
975
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1012
976
|
skipped++;
|
|
1013
977
|
continue;
|
|
1014
978
|
}
|
|
@@ -1018,7 +982,7 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1018
982
|
const nameMatch = entry.match(/(?<=\[).+?(?=\])/);
|
|
1019
983
|
const id = entry.split("-")[0];
|
|
1020
984
|
if (!nameMatch || !id) {
|
|
1021
|
-
if (isVerbose())
|
|
985
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1022
986
|
skipped++;
|
|
1023
987
|
continue;
|
|
1024
988
|
}
|
|
@@ -1026,19 +990,19 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1026
990
|
const ps3New = (0, import_path9.resolve)(dir, `${nameMatch[0]} [${id}]`);
|
|
1027
991
|
(0, import_fs8.renameSync)(ps3Old, ps3New);
|
|
1028
992
|
recordRename(sessionId, ps3Old, ps3New);
|
|
1029
|
-
|
|
993
|
+
spinner5.succeed(`${nameMatch[0]} [${id}]`);
|
|
1030
994
|
renamed++;
|
|
1031
995
|
continue;
|
|
1032
996
|
}
|
|
1033
997
|
const yearMatch = entry.match(/\([^\d]*(\d+)[^\d]*\)/);
|
|
1034
998
|
if (!yearMatch) {
|
|
1035
|
-
if (isVerbose())
|
|
999
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1036
1000
|
skipped++;
|
|
1037
1001
|
continue;
|
|
1038
1002
|
}
|
|
1039
1003
|
const year = yearMatch[0];
|
|
1040
1004
|
if (year.length !== 6) {
|
|
1041
|
-
if (isVerbose())
|
|
1005
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1042
1006
|
skipped++;
|
|
1043
1007
|
continue;
|
|
1044
1008
|
}
|
|
@@ -1049,20 +1013,20 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1049
1013
|
return videoExtensions_default.includes(ext2) && title.split(" ").reduce((a, w) => f.toLowerCase().includes(w.toLowerCase()) ? a : false, true);
|
|
1050
1014
|
});
|
|
1051
1015
|
if (!video) {
|
|
1052
|
-
if (isVerbose())
|
|
1016
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1053
1017
|
skipped++;
|
|
1054
1018
|
continue;
|
|
1055
1019
|
}
|
|
1056
1020
|
const ext = video.match(/([^.]+$)/)?.[0];
|
|
1057
1021
|
if (!ext) {
|
|
1058
|
-
if (isVerbose())
|
|
1022
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1059
1023
|
skipped++;
|
|
1060
1024
|
continue;
|
|
1061
1025
|
}
|
|
1062
1026
|
const yearNum = parseInt(year.replace(/\D/g, ""));
|
|
1063
1027
|
const formatted = formatMovieName(movieFormat, title, yearNum);
|
|
1064
1028
|
if (entry === formatted && video === `${formatted}.${ext}`) {
|
|
1065
|
-
if (isVerbose())
|
|
1029
|
+
if (isVerbose()) spinner5.info(`skipped ${entry}`);
|
|
1066
1030
|
skipped++;
|
|
1067
1031
|
continue;
|
|
1068
1032
|
}
|
|
@@ -1085,25 +1049,26 @@ var rename = async ({ dir: inputDir, type }) => {
|
|
|
1085
1049
|
(0, import_fs8.renameSync)(folderOld, folderNew);
|
|
1086
1050
|
recordRename(sessionId, fileOld, fileNew);
|
|
1087
1051
|
recordRename(sessionId, folderOld, folderNew);
|
|
1088
|
-
|
|
1052
|
+
spinner5.succeed(formatted);
|
|
1089
1053
|
renamed++;
|
|
1090
1054
|
}
|
|
1091
|
-
|
|
1092
|
-
if (removed)
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1055
|
+
spinner5.succeed(`renamed ${renamed} files`);
|
|
1056
|
+
if (removed) spinner5.info(`removed ${removed} files`);
|
|
1057
|
+
spinner5.info(`skipped ${skipped} files`);
|
|
1058
|
+
spinner5.succeed(`done in ${import_termkit7.Color.green.encoder(dir)}`);
|
|
1059
|
+
spinner5.stop();
|
|
1096
1060
|
};
|
|
1097
1061
|
var rename_default = rename;
|
|
1098
1062
|
|
|
1099
1063
|
// src/actions/reset.ts
|
|
1100
1064
|
var import_fs9 = require("fs");
|
|
1101
1065
|
var import_path10 = require("path");
|
|
1102
|
-
var
|
|
1066
|
+
var import_termkit8 = require("termkit");
|
|
1067
|
+
var spinner6 = new import_termkit8.Spinner();
|
|
1103
1068
|
var reset = async ({ dir: inputDir, double }) => {
|
|
1104
1069
|
let dir = inputDir;
|
|
1105
|
-
|
|
1106
|
-
|
|
1070
|
+
spinner6.update(`resetting episodes in ${import_termkit8.Color.white.encoder(dir)}`);
|
|
1071
|
+
spinner6.start();
|
|
1107
1072
|
dir = (0, import_path10.resolve)(dir);
|
|
1108
1073
|
if (!(0, import_fs9.existsSync)(dir)) throw new Error(`dir ${dir} does not exist`);
|
|
1109
1074
|
const list2 = (0, import_fs9.readdirSync)(dir).sort();
|
|
@@ -1119,7 +1084,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1119
1084
|
if (!seasonNum) throw new Error(`unable to identify season number`);
|
|
1120
1085
|
const parentFolder = (0, import_path10.basename)((0, import_path10.dirname)(dir));
|
|
1121
1086
|
const showTitle = parentFolder.match(/^(.+?)\s*(?:\(\d{4}\))?$/)?.[1]?.trim() || void 0;
|
|
1122
|
-
|
|
1087
|
+
spinner6.info(`identified as season ${seasonNum}${showTitle ? ` of ${showTitle}` : ""}`);
|
|
1123
1088
|
const sublist = list2.filter((f) => {
|
|
1124
1089
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1125
1090
|
return videoExtensions_default.includes(ext) && f.split(" ").reduce((a, w) => f.toLowerCase().includes(w.toLowerCase()) ? a : false, true);
|
|
@@ -1131,7 +1096,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1131
1096
|
const episodeFormat = getConfig().format?.episode;
|
|
1132
1097
|
let renamed = 0, skipped = other.length;
|
|
1133
1098
|
for (const [index, i] of sublist.entries()) {
|
|
1134
|
-
|
|
1099
|
+
spinner6.update(`resetting episodes in ${import_termkit8.Color.white.encoder(dir)} ${index}/${list2.length}`);
|
|
1135
1100
|
const ext = i.match(/([^.]+$)/)?.[0];
|
|
1136
1101
|
const episode = double ? index * 2 + 1 : index + 1;
|
|
1137
1102
|
const name = `${formatEpisode(seasonNum, episode, episodeFormat, double, showTitle)}.${ext}`;
|
|
@@ -1142,17 +1107,17 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1142
1107
|
(0, import_fs9.renameSync)((0, import_path10.resolve)(dir, i), (0, import_path10.resolve)(dir, name));
|
|
1143
1108
|
renamed++;
|
|
1144
1109
|
}
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1110
|
+
spinner6.succeed(`renamed ${renamed} files`);
|
|
1111
|
+
spinner6.info(`skipped ${skipped} files`);
|
|
1112
|
+
spinner6.succeed(`done in ${import_termkit8.Color.green.encoder(dir)}`);
|
|
1113
|
+
spinner6.stop();
|
|
1149
1114
|
};
|
|
1150
1115
|
var reset_default = reset;
|
|
1151
1116
|
|
|
1152
1117
|
// src/actions/scan.ts
|
|
1153
1118
|
var import_fs11 = require("fs");
|
|
1154
1119
|
var import_path12 = require("path");
|
|
1155
|
-
var
|
|
1120
|
+
var import_termkit9 = require("termkit");
|
|
1156
1121
|
|
|
1157
1122
|
// src/helpers/detectEdition.ts
|
|
1158
1123
|
var EDITIONS = [
|
|
@@ -1313,6 +1278,7 @@ var searchTv = async (title, apiKey) => {
|
|
|
1313
1278
|
var bookExtensions_default = ["epub", "mobi", "azw3", "azw"];
|
|
1314
1279
|
|
|
1315
1280
|
// src/actions/scan.ts
|
|
1281
|
+
var spinner7 = new import_termkit9.Spinner();
|
|
1316
1282
|
var sameDev = (a, b) => {
|
|
1317
1283
|
try {
|
|
1318
1284
|
let bExisting = b;
|
|
@@ -1346,6 +1312,24 @@ var containsBook = (dir, depth = 2) => (0, import_fs11.readdirSync)(dir).some((f
|
|
|
1346
1312
|
}
|
|
1347
1313
|
return false;
|
|
1348
1314
|
});
|
|
1315
|
+
var containsPdf = (dir) => {
|
|
1316
|
+
try {
|
|
1317
|
+
return (0, import_fs11.readdirSync)(dir).some((f) => /\.pdf$/i.test(f));
|
|
1318
|
+
} catch {
|
|
1319
|
+
return false;
|
|
1320
|
+
}
|
|
1321
|
+
};
|
|
1322
|
+
var countVideos = (dir) => {
|
|
1323
|
+
try {
|
|
1324
|
+
return (0, import_fs11.readdirSync)(dir).filter((f) => {
|
|
1325
|
+
if (/\bsample\b/i.test(f)) return false;
|
|
1326
|
+
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1327
|
+
return !!(ext && videoExtensions_default.includes(ext));
|
|
1328
|
+
}).length;
|
|
1329
|
+
} catch {
|
|
1330
|
+
return 0;
|
|
1331
|
+
}
|
|
1332
|
+
};
|
|
1349
1333
|
var isTvEpisodeName = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1350
1334
|
var isSeasonDirName = (name) => !isTvEpisodeName(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1351
1335
|
var gatherEntries = (source) => {
|
|
@@ -1496,13 +1480,17 @@ var classifyMovieConfidence = (entry) => {
|
|
|
1496
1480
|
return "ambiguous";
|
|
1497
1481
|
};
|
|
1498
1482
|
var typeColor = {
|
|
1499
|
-
movie: (s) =>
|
|
1500
|
-
tv: (s) =>
|
|
1501
|
-
book: (s) =>
|
|
1502
|
-
ps3: (s) =>
|
|
1503
|
-
};
|
|
1504
|
-
var typeGlyph = (t) => typeColor[t]("
|
|
1505
|
-
var
|
|
1483
|
+
movie: (s) => import_termkit9.Color.cyan.encoder(s),
|
|
1484
|
+
tv: (s) => import_termkit9.Color.green.encoder(s),
|
|
1485
|
+
book: (s) => import_termkit9.Color.yellow.encoder(s),
|
|
1486
|
+
ps3: (s) => import_termkit9.Color.magenta.encoder(s)
|
|
1487
|
+
};
|
|
1488
|
+
var typeGlyph = (t) => typeColor[t]("?");
|
|
1489
|
+
var checkGlyph = (t) => typeColor[t]("\u2714");
|
|
1490
|
+
var greyGlyph = import_termkit9.Color.white.faint.encoder("\u25CF");
|
|
1491
|
+
var warnGlyph = import_termkit9.Color.yellow.encoder("\u26A0");
|
|
1492
|
+
var typeTag = (t) => isVerbose() ? import_termkit9.Color.white.faint.encoder(` (${t})`) : "";
|
|
1493
|
+
var sortByEntry = (arr) => arr.sort((a, b) => a.entry.localeCompare(b.entry, void 0, { sensitivity: "base" }));
|
|
1506
1494
|
var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactive }) => {
|
|
1507
1495
|
const config = getConfig();
|
|
1508
1496
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -1510,27 +1498,28 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1510
1498
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1511
1499
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
1512
1500
|
const specialsFolder = config.specialsFolder ?? "Specials";
|
|
1501
|
+
const dryTag = dryRun ? import_termkit9.Color.white.faint.encoder(" [dry]") : "";
|
|
1513
1502
|
const lookupMovie = async (parsed) => {
|
|
1514
1503
|
let tmdbId;
|
|
1515
1504
|
let resolvedTitle = parsed.title;
|
|
1516
1505
|
let resolvedYear = parsed.year;
|
|
1517
1506
|
if (config.tmdbApiKey) {
|
|
1518
|
-
|
|
1507
|
+
spinner7.update(`TMDb: ${parsed.title}`);
|
|
1519
1508
|
const results = await searchMovie(parsed.title, parsed.year, config.tmdbApiKey);
|
|
1520
1509
|
if (results.length === 1) {
|
|
1521
1510
|
tmdbId = results[0].id;
|
|
1522
1511
|
resolvedTitle = results[0].title;
|
|
1523
1512
|
resolvedYear = results[0].year ?? parsed.year;
|
|
1524
1513
|
} else if (results.length > 1) {
|
|
1525
|
-
|
|
1526
|
-
const select = new
|
|
1514
|
+
spinner7.stop();
|
|
1515
|
+
const select = new import_termkit9.Select();
|
|
1527
1516
|
const items = results.map((r) => ({
|
|
1528
1517
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
1529
1518
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
1530
1519
|
...r
|
|
1531
1520
|
}));
|
|
1532
1521
|
const picked = await select.ask(`Multiple movies found for "${parsed.title}":`, items);
|
|
1533
|
-
|
|
1522
|
+
spinner7.start();
|
|
1534
1523
|
if (picked) {
|
|
1535
1524
|
tmdbId = picked.id;
|
|
1536
1525
|
resolvedTitle = picked.title;
|
|
@@ -1545,12 +1534,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1545
1534
|
const folderName = formatMovieName(movieFormat, resolvedTitle, resolvedYear, edition);
|
|
1546
1535
|
const destFolder = (0, import_path12.resolve)(destRoot, folderName);
|
|
1547
1536
|
if ((0, import_fs11.existsSync)(destFolder)) {
|
|
1548
|
-
|
|
1537
|
+
spinner7.log(`${typeColor.movie(folderName)}${typeTag("movie")}`, greyGlyph);
|
|
1549
1538
|
return false;
|
|
1550
1539
|
}
|
|
1551
1540
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
1552
1541
|
if (!videoFile) {
|
|
1553
|
-
|
|
1542
|
+
spinner7.log(`${entry}${typeTag("movie")}`, warnGlyph);
|
|
1554
1543
|
return false;
|
|
1555
1544
|
}
|
|
1556
1545
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
@@ -1571,7 +1560,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1571
1560
|
(0, import_fs11.linkSync)(videoSourcePath, destVideoPath);
|
|
1572
1561
|
mode = "hardlink";
|
|
1573
1562
|
} catch {
|
|
1574
|
-
|
|
1563
|
+
spinner7.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
1575
1564
|
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1576
1565
|
mode = "copy";
|
|
1577
1566
|
}
|
|
@@ -1597,27 +1586,33 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1597
1586
|
recordImport(sessionId, entryPath, destFolder, "move", tmdbId, "movie");
|
|
1598
1587
|
}
|
|
1599
1588
|
}
|
|
1600
|
-
|
|
1589
|
+
spinner7.log(`${typeColor.movie(folderName)}${typeTag("movie")}${dryTag}`, checkGlyph("movie"));
|
|
1601
1590
|
return true;
|
|
1602
1591
|
};
|
|
1603
|
-
|
|
1592
|
+
spinner7.start();
|
|
1604
1593
|
if (config.sources.length === 0) throw new Error("no sources configured \u2014 run: reelsort config add source <dir>");
|
|
1605
1594
|
let imported = 0, skipped = 0;
|
|
1606
1595
|
const pendingMovies = [];
|
|
1607
1596
|
const pendingTv = [];
|
|
1597
|
+
const pendingBooks = [];
|
|
1598
|
+
const pendingAnime = [];
|
|
1608
1599
|
const ignoreSet = new Set(config.ignore ?? []);
|
|
1609
1600
|
const seenIgnored = /* @__PURE__ */ new Set();
|
|
1610
1601
|
for (const source of config.sources) {
|
|
1611
1602
|
if (!(0, import_fs11.existsSync)(source)) {
|
|
1612
|
-
|
|
1603
|
+
spinner7.warn(`source not found: ${import_termkit9.Color.white.encoder(source)}`);
|
|
1613
1604
|
continue;
|
|
1614
1605
|
}
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1606
|
+
spinner7.update(`scanning ${import_termkit9.Color.white.encoder(source)}`);
|
|
1607
|
+
const entries = gatherEntries(source).sort(
|
|
1608
|
+
(a, b) => a.entry.localeCompare(b.entry, void 0, { sensitivity: "base" })
|
|
1609
|
+
);
|
|
1610
|
+
for (const { entry, entryPath, isDir } of entries) {
|
|
1611
|
+
spinner7.update(`scanning: ${entry}`);
|
|
1618
1612
|
if (ignoreSet.has(entry)) {
|
|
1619
1613
|
seenIgnored.add(entry);
|
|
1620
|
-
if (isVerbose())
|
|
1614
|
+
if (isVerbose()) spinner7.log(entry, greyGlyph);
|
|
1615
|
+
skipped++;
|
|
1621
1616
|
continue;
|
|
1622
1617
|
}
|
|
1623
1618
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
@@ -1637,7 +1632,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1637
1632
|
}
|
|
1638
1633
|
const destRoot = config.dest[detectedType];
|
|
1639
1634
|
if (!destRoot) {
|
|
1640
|
-
if (isVerbose())
|
|
1635
|
+
if (isVerbose()) spinner7.log(`${entry}${typeTag(detectedType)}`, greyGlyph);
|
|
1641
1636
|
skipped++;
|
|
1642
1637
|
continue;
|
|
1643
1638
|
}
|
|
@@ -1651,7 +1646,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1651
1646
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
1652
1647
|
const destPath = (0, import_path12.resolve)(destRoot, destName);
|
|
1653
1648
|
if ((0, import_fs11.existsSync)(destPath)) {
|
|
1654
|
-
|
|
1649
|
+
spinner7.log(`${typeColor.ps3(destName)}${typeTag("ps3")}`, greyGlyph);
|
|
1655
1650
|
skipped++;
|
|
1656
1651
|
continue;
|
|
1657
1652
|
}
|
|
@@ -1659,14 +1654,14 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1659
1654
|
moveFolder(entryPath, destPath);
|
|
1660
1655
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "ps3");
|
|
1661
1656
|
}
|
|
1662
|
-
|
|
1657
|
+
spinner7.log(`${typeColor.ps3(destName)}${typeTag("ps3")}${dryTag}`, checkGlyph("ps3"));
|
|
1663
1658
|
imported++;
|
|
1664
1659
|
continue;
|
|
1665
1660
|
}
|
|
1666
1661
|
if (detectedType === "book") {
|
|
1667
1662
|
const destPath = (0, import_path12.resolve)(destRoot, entry);
|
|
1668
1663
|
if ((0, import_fs11.existsSync)(destPath)) {
|
|
1669
|
-
|
|
1664
|
+
spinner7.log(`${typeColor.book(entry)}${typeTag("book")}`, greyGlyph);
|
|
1670
1665
|
skipped++;
|
|
1671
1666
|
continue;
|
|
1672
1667
|
}
|
|
@@ -1684,20 +1679,36 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1684
1679
|
}
|
|
1685
1680
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
1686
1681
|
}
|
|
1687
|
-
|
|
1682
|
+
spinner7.log(`${typeColor.book(entry)}${typeTag("book")}${dryTag}`, checkGlyph("book"));
|
|
1688
1683
|
imported++;
|
|
1689
1684
|
continue;
|
|
1690
1685
|
}
|
|
1686
|
+
if (detectedType === "movie" && isDir) {
|
|
1687
|
+
const videoCount = countVideos(entryPath);
|
|
1688
|
+
if (videoCount === 0) {
|
|
1689
|
+
if (containsPdf(entryPath)) {
|
|
1690
|
+
pendingBooks.push({ entry, entryPath });
|
|
1691
|
+
} else {
|
|
1692
|
+
if (isVerbose()) spinner7.log(entry, greyGlyph);
|
|
1693
|
+
skipped++;
|
|
1694
|
+
}
|
|
1695
|
+
continue;
|
|
1696
|
+
}
|
|
1697
|
+
if (videoCount >= 2) {
|
|
1698
|
+
pendingAnime.push({ entry, entryPath, videoCount });
|
|
1699
|
+
continue;
|
|
1700
|
+
}
|
|
1701
|
+
}
|
|
1691
1702
|
const parsed = parseDownloadName(entry);
|
|
1692
1703
|
if (!parsed) {
|
|
1693
|
-
if (isVerbose())
|
|
1704
|
+
if (isVerbose()) spinner7.log(entry, greyGlyph);
|
|
1694
1705
|
skipped++;
|
|
1695
1706
|
continue;
|
|
1696
1707
|
}
|
|
1697
1708
|
if (detectedType === "movie") {
|
|
1698
1709
|
const confidence = classifyMovieConfidence(entry);
|
|
1699
1710
|
if (confidence === "skip") {
|
|
1700
|
-
if (isVerbose())
|
|
1711
|
+
if (isVerbose()) spinner7.log(entry, greyGlyph);
|
|
1701
1712
|
skipped++;
|
|
1702
1713
|
continue;
|
|
1703
1714
|
}
|
|
@@ -1711,22 +1722,22 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1711
1722
|
let resolvedYear = parsed.year;
|
|
1712
1723
|
if (config.tmdbApiKey) {
|
|
1713
1724
|
if (detectedType === "tv") {
|
|
1714
|
-
|
|
1725
|
+
spinner7.update(`TMDb: ${parsed.title}`);
|
|
1715
1726
|
const results = await searchTv(parsed.title, config.tmdbApiKey);
|
|
1716
1727
|
if (results.length === 1) {
|
|
1717
1728
|
tmdbId = results[0].id;
|
|
1718
1729
|
resolvedTitle = results[0].title;
|
|
1719
1730
|
resolvedYear = results[0].year ?? parsed.year;
|
|
1720
1731
|
} else if (results.length > 1) {
|
|
1721
|
-
|
|
1722
|
-
const select = new
|
|
1732
|
+
spinner7.stop();
|
|
1733
|
+
const select = new import_termkit9.Select();
|
|
1723
1734
|
const items = results.map((r) => ({
|
|
1724
1735
|
label: r.year ? `${r.title} (${r.year})` : r.title,
|
|
1725
1736
|
description: [r.overview?.slice(0, 60), hyperlink(r.url, "themoviedb.org")].filter(Boolean).join(" \xB7 "),
|
|
1726
1737
|
...r
|
|
1727
1738
|
}));
|
|
1728
1739
|
const picked = await select.ask(`Multiple shows found for "${parsed.title}":`, items);
|
|
1729
|
-
|
|
1740
|
+
spinner7.start();
|
|
1730
1741
|
if (picked) {
|
|
1731
1742
|
tmdbId = picked.id;
|
|
1732
1743
|
resolvedTitle = picked.title;
|
|
@@ -1742,7 +1753,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1742
1753
|
}
|
|
1743
1754
|
if (detectedType === "tv") {
|
|
1744
1755
|
if (parsed.season === void 0) {
|
|
1745
|
-
if (isVerbose())
|
|
1756
|
+
if (isVerbose()) spinner7.log(entry, greyGlyph);
|
|
1746
1757
|
skipped++;
|
|
1747
1758
|
continue;
|
|
1748
1759
|
}
|
|
@@ -1770,12 +1781,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1770
1781
|
const seasonPath = (0, import_path12.resolve)(showPath, seasonFolderName);
|
|
1771
1782
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
1772
1783
|
if (!videoFile) {
|
|
1773
|
-
|
|
1784
|
+
spinner7.log(`${entry}${typeTag("tv")}`, warnGlyph);
|
|
1774
1785
|
skipped++;
|
|
1775
1786
|
continue;
|
|
1776
1787
|
}
|
|
1777
1788
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
1778
|
-
if (tmdbId && config.tmdbApiKey)
|
|
1789
|
+
if (tmdbId && config.tmdbApiKey) spinner7.update(`TMDb: episode name for ${resolvedTitle}`);
|
|
1779
1790
|
const tmdbEpisodeName = tmdbId && config.tmdbApiKey ? await getEpisodeName(tmdbId, parsed.season, parsed.episode ?? 1, config.tmdbApiKey) : null;
|
|
1780
1791
|
const episodeName = formatEpisode(parsed.season, parsed.episode ?? 1, config.format?.episode, false, resolvedTitle, tmdbEpisodeName ?? void 0);
|
|
1781
1792
|
const destVideoName = `${episodeName}.${videoExt}`;
|
|
@@ -1785,17 +1796,17 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1785
1796
|
const isRepack = /\brepack\d*\b|\bproper\b/i.test(entry);
|
|
1786
1797
|
let shouldReplace = force || isRepack;
|
|
1787
1798
|
if (!shouldReplace && interactive) {
|
|
1788
|
-
|
|
1789
|
-
const select = new
|
|
1799
|
+
spinner7.stop();
|
|
1800
|
+
const select = new import_termkit9.Select();
|
|
1790
1801
|
const picked = await select.ask(`Already exists \u2014 replace?`, [
|
|
1791
1802
|
{ label: `${showFolderName} / ${seasonFolderName} / ${episodeName}`, value: "replace" },
|
|
1792
1803
|
{ label: "Skip", value: "skip" }
|
|
1793
1804
|
]);
|
|
1794
|
-
|
|
1805
|
+
spinner7.start();
|
|
1795
1806
|
shouldReplace = picked?.value === "replace";
|
|
1796
1807
|
}
|
|
1797
1808
|
if (!shouldReplace) {
|
|
1798
|
-
|
|
1809
|
+
spinner7.log(`${typeColor.tv(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}${typeTag("tv")}`, greyGlyph);
|
|
1799
1810
|
skipped++;
|
|
1800
1811
|
continue;
|
|
1801
1812
|
}
|
|
@@ -1819,7 +1830,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1819
1830
|
(0, import_fs11.linkSync)(videoSourcePath, destVideoPath);
|
|
1820
1831
|
mode = "hardlink";
|
|
1821
1832
|
} catch {
|
|
1822
|
-
|
|
1833
|
+
spinner7.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
1823
1834
|
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1824
1835
|
mode = "copy";
|
|
1825
1836
|
}
|
|
@@ -1836,7 +1847,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1836
1847
|
}
|
|
1837
1848
|
recordImport(sessionId, entryPath, seasonPath, mode, tmdbId, "tv");
|
|
1838
1849
|
}
|
|
1839
|
-
|
|
1850
|
+
spinner7.log(`${typeColor.tv(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}${typeTag("tv")}${dryTag}`, checkGlyph("tv"));
|
|
1840
1851
|
imported++;
|
|
1841
1852
|
continue;
|
|
1842
1853
|
}
|
|
@@ -1847,25 +1858,27 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1847
1858
|
}
|
|
1848
1859
|
}
|
|
1849
1860
|
}
|
|
1861
|
+
let uncertainMovies = 0;
|
|
1850
1862
|
if (pendingMovies.length > 0) {
|
|
1851
|
-
spinner_default.warn(`${pendingMovies.length} uncertain movie match${pendingMovies.length > 1 ? "es" : ""} skipped \u2014 use -i to review or -f to import all`);
|
|
1852
|
-
for (const p of pendingMovies) spinner_default.info(` ${typeGlyph("movie")} ${p.entry.replace(/\/$/, "")}${typeTag("movie")}`);
|
|
1853
1863
|
let toProcess = [];
|
|
1854
1864
|
if (interactive) {
|
|
1855
|
-
|
|
1856
|
-
const ms = new
|
|
1865
|
+
spinner7.stop();
|
|
1866
|
+
const ms = new import_termkit9.MultiSelect({ allowSkip: true, search: true, maxHeight: 20 });
|
|
1857
1867
|
const items = pendingMovies.map((p) => ({
|
|
1858
1868
|
label: p.entry.replace(/\/$/, ""),
|
|
1859
1869
|
description: p.parsed.year ? `parsed: ${p.parsed.title} \xB7 ${p.parsed.year}` : `parsed: ${p.parsed.title}`,
|
|
1860
1870
|
...p
|
|
1861
1871
|
}));
|
|
1862
1872
|
toProcess = await ms.ask("Select entries to import as movies:", items) ?? [];
|
|
1863
|
-
|
|
1864
|
-
skipped += pendingMovies.length - toProcess.length;
|
|
1873
|
+
spinner7.start();
|
|
1865
1874
|
} else if (force) {
|
|
1866
1875
|
toProcess = pendingMovies;
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1876
|
+
}
|
|
1877
|
+
const toSkip = pendingMovies.filter((p) => !toProcess.includes(p));
|
|
1878
|
+
uncertainMovies = toSkip.length;
|
|
1879
|
+
sortByEntry(toSkip);
|
|
1880
|
+
for (const p of toSkip) {
|
|
1881
|
+
spinner7.log(`${typeColor.movie(p.entry.replace(/\/$/, ""))}${typeTag("movie")}`, typeGlyph("movie"));
|
|
1869
1882
|
}
|
|
1870
1883
|
for (const p of toProcess) {
|
|
1871
1884
|
const { tmdbId, resolvedTitle, resolvedYear } = await lookupMovie(p.parsed);
|
|
@@ -1877,9 +1890,22 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1877
1890
|
}
|
|
1878
1891
|
}
|
|
1879
1892
|
if (pendingTv.length > 0) {
|
|
1880
|
-
|
|
1881
|
-
for (const p of pendingTv)
|
|
1882
|
-
|
|
1893
|
+
pendingTv.sort((a, b) => a.resolvedTitle.localeCompare(b.resolvedTitle, void 0, { sensitivity: "base" }));
|
|
1894
|
+
for (const p of pendingTv) {
|
|
1895
|
+
spinner7.log(`${typeColor.tv(p.resolvedTitle)} \u2014 ${p.entry.replace(/\/$/, "")}${typeTag("tv")}`, typeGlyph("tv"));
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
if (pendingBooks.length > 0) {
|
|
1899
|
+
sortByEntry(pendingBooks);
|
|
1900
|
+
for (const p of pendingBooks) {
|
|
1901
|
+
spinner7.log(`${typeColor.book(p.entry)}${typeTag("book")}`, typeGlyph("book"));
|
|
1902
|
+
}
|
|
1903
|
+
}
|
|
1904
|
+
if (pendingAnime.length > 0) {
|
|
1905
|
+
sortByEntry(pendingAnime);
|
|
1906
|
+
for (const p of pendingAnime) {
|
|
1907
|
+
spinner7.log(`${typeColor.tv(p.entry)} (${p.videoCount} video${p.videoCount > 1 ? "s" : ""})${typeTag("tv")}`, typeGlyph("tv"));
|
|
1908
|
+
}
|
|
1883
1909
|
}
|
|
1884
1910
|
if (ignoreSet.size > 0) {
|
|
1885
1911
|
const stale = [...ignoreSet].filter((name) => !seenIgnored.has(name));
|
|
@@ -1887,25 +1913,31 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1887
1913
|
const updated = config.ignore.filter((name) => !stale.includes(name));
|
|
1888
1914
|
config.ignore = updated;
|
|
1889
1915
|
saveConfig(config);
|
|
1890
|
-
for (const name of stale)
|
|
1916
|
+
for (const name of stale) spinner7.info(`removed from ignore list (not found): ${import_termkit9.Color.white.encoder(name)}`);
|
|
1891
1917
|
}
|
|
1892
1918
|
}
|
|
1893
|
-
|
|
1894
|
-
if (skipped)
|
|
1895
|
-
|
|
1919
|
+
const summaryParts = [`${dryRun ? "would import" : "imported"} ${imported}`];
|
|
1920
|
+
if (skipped) summaryParts.push(`skipped ${skipped}`);
|
|
1921
|
+
if (uncertainMovies) summaryParts.push(`uncertain movie ${uncertainMovies}`);
|
|
1922
|
+
if (pendingTv.length) summaryParts.push(`uncertain tv ${pendingTv.length}`);
|
|
1923
|
+
if (pendingBooks.length) summaryParts.push(`uncertain book ${pendingBooks.length}`);
|
|
1924
|
+
if (pendingAnime.length) summaryParts.push(`uncertain anime ${pendingAnime.length}`);
|
|
1925
|
+
spinner7.succeed(summaryParts.join(", "));
|
|
1926
|
+
spinner7.stop();
|
|
1896
1927
|
};
|
|
1897
1928
|
var scan_default = scan;
|
|
1898
1929
|
|
|
1899
1930
|
// src/actions/undo.ts
|
|
1900
1931
|
var import_fs12 = require("fs");
|
|
1901
|
-
var
|
|
1932
|
+
var import_termkit10 = require("termkit");
|
|
1933
|
+
var spinner8 = new import_termkit10.Spinner();
|
|
1902
1934
|
var undo = async () => {
|
|
1903
|
-
|
|
1935
|
+
spinner8.start();
|
|
1904
1936
|
const renameRecords = getLastSession();
|
|
1905
1937
|
const importRecords = getLastImportSession();
|
|
1906
1938
|
if (renameRecords.length === 0 && importRecords.length === 0) {
|
|
1907
|
-
|
|
1908
|
-
|
|
1939
|
+
spinner8.info("nothing to undo");
|
|
1940
|
+
spinner8.stop();
|
|
1909
1941
|
return;
|
|
1910
1942
|
}
|
|
1911
1943
|
const useImports = importRecords.length > 0 && (renameRecords.length === 0 || importRecords[0].sessionId > renameRecords[0].sessionId);
|
|
@@ -1913,40 +1945,40 @@ var undo = async () => {
|
|
|
1913
1945
|
let undone2 = 0;
|
|
1914
1946
|
for (const record of renameRecords) {
|
|
1915
1947
|
(0, import_fs12.renameSync)(record.newPath, record.oldPath);
|
|
1916
|
-
|
|
1948
|
+
spinner8.succeed(`${import_termkit10.Color.green.encoder(record.newPath)} \u2192 ${import_termkit10.Color.white.encoder(record.oldPath)}`);
|
|
1917
1949
|
undone2++;
|
|
1918
1950
|
}
|
|
1919
1951
|
deleteSession(renameRecords[0].sessionId);
|
|
1920
|
-
|
|
1921
|
-
|
|
1952
|
+
spinner8.succeed(`undid ${undone2} renames`);
|
|
1953
|
+
spinner8.stop();
|
|
1922
1954
|
return;
|
|
1923
1955
|
}
|
|
1924
1956
|
let undone = 0;
|
|
1925
1957
|
let skipped = 0;
|
|
1926
1958
|
for (const record of importRecords) {
|
|
1927
1959
|
if (record.mode !== "move") {
|
|
1928
|
-
|
|
1960
|
+
spinner8.info(`skipped ${record.destinationPath} (${record.mode} \u2014 source file unchanged)`);
|
|
1929
1961
|
skipped++;
|
|
1930
1962
|
continue;
|
|
1931
1963
|
}
|
|
1932
1964
|
if (record.type === "tv") {
|
|
1933
|
-
|
|
1965
|
+
spinner8.info(`skipped TV import \u2014 season folder cannot be cleanly reversed: ${record.destinationPath}`);
|
|
1934
1966
|
skipped++;
|
|
1935
1967
|
continue;
|
|
1936
1968
|
}
|
|
1937
1969
|
if (!(0, import_fs12.existsSync)(record.destinationPath)) {
|
|
1938
|
-
|
|
1970
|
+
spinner8.info(`skipped \u2014 destination no longer exists: ${record.destinationPath}`);
|
|
1939
1971
|
skipped++;
|
|
1940
1972
|
continue;
|
|
1941
1973
|
}
|
|
1942
1974
|
(0, import_fs12.renameSync)(record.destinationPath, record.sourcePath);
|
|
1943
|
-
|
|
1975
|
+
spinner8.succeed(`${import_termkit10.Color.green.encoder(record.destinationPath)} \u2192 ${import_termkit10.Color.white.encoder(record.sourcePath)}`);
|
|
1944
1976
|
undone++;
|
|
1945
1977
|
}
|
|
1946
1978
|
deleteImportSession(importRecords[0].sessionId);
|
|
1947
|
-
if (undone > 0)
|
|
1948
|
-
if (skipped > 0)
|
|
1949
|
-
|
|
1979
|
+
if (undone > 0) spinner8.succeed(`undid ${undone} import${undone !== 1 ? "s" : ""}`);
|
|
1980
|
+
if (skipped > 0) spinner8.info(`skipped ${skipped} item${skipped !== 1 ? "s" : ""} (TV or non-move mode)`);
|
|
1981
|
+
spinner8.stop();
|
|
1950
1982
|
};
|
|
1951
1983
|
var undo_default = undo;
|
|
1952
1984
|
|
|
@@ -1954,7 +1986,8 @@ var undo_default = undo;
|
|
|
1954
1986
|
var import_chokidar = __toESM(require("chokidar"));
|
|
1955
1987
|
var import_fs13 = require("fs");
|
|
1956
1988
|
var import_path13 = require("path");
|
|
1957
|
-
var
|
|
1989
|
+
var import_termkit11 = require("termkit");
|
|
1990
|
+
var spinner9 = new import_termkit11.Spinner();
|
|
1958
1991
|
var sameDev2 = (a, b) => {
|
|
1959
1992
|
try {
|
|
1960
1993
|
let bExisting = b;
|
|
@@ -2094,7 +2127,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2094
2127
|
}
|
|
2095
2128
|
const destRoot = config.dest[detectedType];
|
|
2096
2129
|
if (!destRoot) {
|
|
2097
|
-
if (isVerbose())
|
|
2130
|
+
if (isVerbose()) spinner9.info(`no ${detectedType} destination configured, skipped: ${entry}`);
|
|
2098
2131
|
return;
|
|
2099
2132
|
}
|
|
2100
2133
|
if (detectedType === "ps3") {
|
|
@@ -2104,18 +2137,18 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2104
2137
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
2105
2138
|
const destPath = (0, import_path13.resolve)(destRoot, destName);
|
|
2106
2139
|
if ((0, import_fs13.existsSync)(destPath)) {
|
|
2107
|
-
|
|
2140
|
+
spinner9.warn(`already exists: ${destName}`);
|
|
2108
2141
|
return;
|
|
2109
2142
|
}
|
|
2110
2143
|
moveItem(entryPath, destPath);
|
|
2111
2144
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "ps3");
|
|
2112
|
-
|
|
2145
|
+
spinner9.succeed(`imported ${import_termkit11.Color.green.encoder(destName)}`);
|
|
2113
2146
|
return;
|
|
2114
2147
|
}
|
|
2115
2148
|
if (detectedType === "book") {
|
|
2116
2149
|
const destPath = (0, import_path13.resolve)(destRoot, entry);
|
|
2117
2150
|
if ((0, import_fs13.existsSync)(destPath)) {
|
|
2118
|
-
|
|
2151
|
+
spinner9.warn(`already exists: ${entry}`);
|
|
2119
2152
|
return;
|
|
2120
2153
|
}
|
|
2121
2154
|
if (isDir || isBookDir) {
|
|
@@ -2130,17 +2163,17 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2130
2163
|
}
|
|
2131
2164
|
}
|
|
2132
2165
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
2133
|
-
|
|
2166
|
+
spinner9.succeed(`imported ${import_termkit11.Color.green.encoder(entry)}`);
|
|
2134
2167
|
return;
|
|
2135
2168
|
}
|
|
2136
2169
|
const parsed = parseDownloadName(entry);
|
|
2137
2170
|
if (!parsed) {
|
|
2138
|
-
if (isVerbose())
|
|
2171
|
+
if (isVerbose()) spinner9.info(`could not parse: ${entry}`);
|
|
2139
2172
|
return;
|
|
2140
2173
|
}
|
|
2141
2174
|
if (detectedType === "tv") {
|
|
2142
2175
|
if (parsed.season === void 0) {
|
|
2143
|
-
if (isVerbose())
|
|
2176
|
+
if (isVerbose()) spinner9.info(`could not detect season from: ${entry}`);
|
|
2144
2177
|
return;
|
|
2145
2178
|
}
|
|
2146
2179
|
const registeredShow = getShowByTitle(parsed.title);
|
|
@@ -2154,14 +2187,14 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2154
2187
|
showPath = (0, import_path13.resolve)(destRoot, showFolderName);
|
|
2155
2188
|
upsertShow(showPath, null, parsed.title);
|
|
2156
2189
|
} else {
|
|
2157
|
-
if (isVerbose())
|
|
2190
|
+
if (isVerbose()) spinner9.info(`not registered, skipped: ${parsed.title} \u2014 run: reelsort add "${parsed.title}"`);
|
|
2158
2191
|
return;
|
|
2159
2192
|
}
|
|
2160
2193
|
const seasonFolderName = findSeasonFolder2(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
2161
2194
|
const seasonPath = (0, import_path13.resolve)(showPath, seasonFolderName);
|
|
2162
2195
|
const videoFile2 = isDir ? findVideo2(entryPath) : entry;
|
|
2163
2196
|
if (!videoFile2) {
|
|
2164
|
-
if (isVerbose())
|
|
2197
|
+
if (isVerbose()) spinner9.info(`no video found in: ${entry}`);
|
|
2165
2198
|
return;
|
|
2166
2199
|
}
|
|
2167
2200
|
const videoExt2 = videoFile2.match(/([^.]+$)/)?.[0];
|
|
@@ -2171,7 +2204,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2171
2204
|
const destVideoPath = (0, import_path13.resolve)(seasonPath, destVideoName2);
|
|
2172
2205
|
const videoSourcePath2 = isDir ? (0, import_path13.resolve)(entryPath, videoFile2) : entryPath;
|
|
2173
2206
|
if ((0, import_fs13.existsSync)(destVideoPath)) {
|
|
2174
|
-
|
|
2207
|
+
spinner9.warn(`already exists: ${episodeName}`);
|
|
2175
2208
|
return;
|
|
2176
2209
|
}
|
|
2177
2210
|
const dirFiles2 = isDir ? (0, import_fs13.readdirSync)(entryPath) : [];
|
|
@@ -2187,7 +2220,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2187
2220
|
(0, import_fs13.linkSync)(videoSourcePath2, destVideoPath);
|
|
2188
2221
|
mode = "hardlink";
|
|
2189
2222
|
} catch {
|
|
2190
|
-
|
|
2223
|
+
spinner9.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
2191
2224
|
(0, import_fs13.cpSync)(videoSourcePath2, destVideoPath);
|
|
2192
2225
|
mode = "copy";
|
|
2193
2226
|
}
|
|
@@ -2203,19 +2236,19 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2203
2236
|
if (isDir) (0, import_fs13.rmSync)(entryPath, { recursive: true, force: true });
|
|
2204
2237
|
}
|
|
2205
2238
|
recordImport(sessionId, entryPath, seasonPath, mode, void 0, "tv");
|
|
2206
|
-
|
|
2239
|
+
spinner9.succeed(`imported ${import_termkit11.Color.green.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
|
|
2207
2240
|
return;
|
|
2208
2241
|
}
|
|
2209
2242
|
const edition = detectEdition(entry);
|
|
2210
2243
|
const folderName = formatMovieName(movieFormat, parsed.title, parsed.year, edition);
|
|
2211
2244
|
const destFolder = (0, import_path13.resolve)(destRoot, folderName);
|
|
2212
2245
|
if ((0, import_fs13.existsSync)(destFolder)) {
|
|
2213
|
-
|
|
2246
|
+
spinner9.warn(`already exists: ${folderName}`);
|
|
2214
2247
|
return;
|
|
2215
2248
|
}
|
|
2216
2249
|
const videoFile = isDir ? findVideo2(entryPath) : entry;
|
|
2217
2250
|
if (!videoFile) {
|
|
2218
|
-
if (isVerbose())
|
|
2251
|
+
if (isVerbose()) spinner9.info(`no video found in: ${entry}`);
|
|
2219
2252
|
return;
|
|
2220
2253
|
}
|
|
2221
2254
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
@@ -2235,7 +2268,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2235
2268
|
(0, import_fs13.linkSync)(videoSourcePath, destVideoPath);
|
|
2236
2269
|
mode = "hardlink";
|
|
2237
2270
|
} catch {
|
|
2238
|
-
|
|
2271
|
+
spinner9.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
2239
2272
|
(0, import_fs13.cpSync)(videoSourcePath, destVideoPath);
|
|
2240
2273
|
mode = "copy";
|
|
2241
2274
|
}
|
|
@@ -2260,7 +2293,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2260
2293
|
}
|
|
2261
2294
|
recordImport(sessionId, entryPath, destFolder, "move", void 0, "movie");
|
|
2262
2295
|
}
|
|
2263
|
-
|
|
2296
|
+
spinner9.succeed(`imported ${import_termkit11.Color.green.encoder(folderName)}`);
|
|
2264
2297
|
};
|
|
2265
2298
|
var watch = async ({ hardlink = false, auto = false }) => {
|
|
2266
2299
|
const config = getConfig();
|
|
@@ -2279,7 +2312,7 @@ var watch = async ({ hardlink = false, auto = false }) => {
|
|
|
2279
2312
|
await processItem(entry, hardlink, language, auto);
|
|
2280
2313
|
}
|
|
2281
2314
|
} catch (err) {
|
|
2282
|
-
|
|
2315
|
+
spinner9.fail(`error processing ${path}: ${err.message}`);
|
|
2283
2316
|
}
|
|
2284
2317
|
}, 5e3)
|
|
2285
2318
|
);
|
|
@@ -2291,10 +2324,10 @@ var watch = async ({ hardlink = false, auto = false }) => {
|
|
|
2291
2324
|
});
|
|
2292
2325
|
watcher.on("addDir", handle);
|
|
2293
2326
|
watcher.on("add", handle);
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
for (const s of config.sources)
|
|
2297
|
-
|
|
2327
|
+
spinner9.start();
|
|
2328
|
+
spinner9.succeed(`watching ${config.sources.length} source${config.sources.length !== 1 ? "s" : ""}`);
|
|
2329
|
+
for (const s of config.sources) spinner9.info(` ${import_termkit11.Color.white.encoder(s)}`);
|
|
2330
|
+
spinner9.stop();
|
|
2298
2331
|
process.stdin.resume();
|
|
2299
2332
|
};
|
|
2300
2333
|
var watch_default = watch;
|