reelsort 0.2.5 → 0.2.6
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 +219 -170
- package/dist/index.d.mts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +207 -158
- package/dist/index.mjs +112 -63
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1150,8 +1150,8 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1150
1150
|
var reset_default = reset;
|
|
1151
1151
|
|
|
1152
1152
|
// src/actions/scan.ts
|
|
1153
|
-
var
|
|
1154
|
-
var
|
|
1153
|
+
var import_fs11 = require("fs");
|
|
1154
|
+
var import_path12 = require("path");
|
|
1155
1155
|
var import_termkit10 = require("termkit");
|
|
1156
1156
|
|
|
1157
1157
|
// src/helpers/detectEdition.ts
|
|
@@ -1175,10 +1175,49 @@ var detectEdition = (filename) => {
|
|
|
1175
1175
|
// src/helpers/hyperlink.ts
|
|
1176
1176
|
var hyperlink = (url, text) => `\x1B]8;;${url}\x1B\\${text}\x1B]8;;\x1B\\`;
|
|
1177
1177
|
|
|
1178
|
+
// src/helpers/trash.ts
|
|
1179
|
+
var import_child_process2 = require("child_process");
|
|
1180
|
+
var import_fs10 = require("fs");
|
|
1181
|
+
var import_os3 = require("os");
|
|
1182
|
+
var import_path11 = require("path");
|
|
1183
|
+
var trashDir = () => {
|
|
1184
|
+
if (process.platform === "linux") return (0, import_path11.join)((0, import_os3.homedir)(), ".local", "share", "Trash", "files");
|
|
1185
|
+
return (0, import_path11.join)((0, import_os3.homedir)(), ".Trash");
|
|
1186
|
+
};
|
|
1187
|
+
var trashPath = (filePath, opts) => {
|
|
1188
|
+
if (process.platform === "darwin" || process.platform === "linux") {
|
|
1189
|
+
try {
|
|
1190
|
+
const dir = trashDir();
|
|
1191
|
+
if (!(0, import_fs10.existsSync)(dir)) (0, import_fs10.mkdirSync)(dir, { recursive: true });
|
|
1192
|
+
const name = (0, import_path11.basename)(filePath);
|
|
1193
|
+
let dest = (0, import_path11.join)(dir, name);
|
|
1194
|
+
let i = 1;
|
|
1195
|
+
while ((0, import_fs10.existsSync)(dest)) dest = (0, import_path11.join)(dir, `${name} ${i++}`);
|
|
1196
|
+
(0, import_fs10.renameSync)(filePath, dest);
|
|
1197
|
+
return;
|
|
1198
|
+
} catch {
|
|
1199
|
+
}
|
|
1200
|
+
} else if (process.platform === "win32") {
|
|
1201
|
+
try {
|
|
1202
|
+
const escaped = filePath.replace(/'/g, "''");
|
|
1203
|
+
const isDir = opts?.recursive ?? false;
|
|
1204
|
+
const method = isDir ? "DeleteDirectory" : "DeleteFile";
|
|
1205
|
+
(0, import_child_process2.execSync)(
|
|
1206
|
+
`powershell -NoProfile -NonInteractive -Command "Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.FileIO.FileSystem]::${method}('${escaped}', 'OnlyErrorDialogs', 'SendToRecycleBin')"`,
|
|
1207
|
+
{ stdio: "ignore" }
|
|
1208
|
+
);
|
|
1209
|
+
return;
|
|
1210
|
+
} catch {
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
(0, import_fs10.rmSync)(filePath, { recursive: opts?.recursive ?? false, force: true });
|
|
1214
|
+
};
|
|
1215
|
+
|
|
1178
1216
|
// src/helpers/parseDownloadName.ts
|
|
1179
1217
|
var QUALITY_TOKENS = /* @__PURE__ */ new Set(["480p", "576p", "720p", "1080p", "2160p", "4k", "8k", "bluray", "bdrip", "bdremux", "brrip", "webrip", "web-dl", "webdl", "web", "hdtv", "dvdrip", "dvdscr", "cam", "ts", "scr", "x264", "x265", "hevc", "avc", "h264", "h265", "xvid", "divx", "dts", "ac3", "aac", "mp3", "truehd", "atmos", "dd5", "hdr", "hdr10", "hlg", "dv", "dolby", "remux", "proper", "repack", "extended", "theatrical", "unrated", "multi", "dubbed", "subbed", "internal"]);
|
|
1180
1218
|
var TV_PATTERN = /^(.*?)[.\s_-]*(?:S(\d{2,3})E(\d{2,3})|(\d{1,2})x(\d{2,3})|Season[\s.](\d+))/i;
|
|
1181
|
-
var parseDownloadName = (
|
|
1219
|
+
var parseDownloadName = (rawName) => {
|
|
1220
|
+
const name = rawName.replace(/^[\w.-]+\.\w{2,6}\s+-+\s+/i, "");
|
|
1182
1221
|
const base = name.replace(/\.[a-z0-9]{2,4}$/i, "");
|
|
1183
1222
|
const tvMatch = TV_PATTERN.exec(base);
|
|
1184
1223
|
if (tvMatch) {
|
|
@@ -1277,31 +1316,31 @@ var bookExtensions_default = ["epub", "mobi", "azw3", "azw"];
|
|
|
1277
1316
|
var sameDev = (a, b) => {
|
|
1278
1317
|
try {
|
|
1279
1318
|
let bExisting = b;
|
|
1280
|
-
while (!(0,
|
|
1281
|
-
return (0,
|
|
1319
|
+
while (!(0, import_fs11.existsSync)(bExisting)) bExisting = (0, import_path12.dirname)(bExisting);
|
|
1320
|
+
return (0, import_fs11.statSync)(a).dev === (0, import_fs11.statSync)(bExisting).dev;
|
|
1282
1321
|
} catch {
|
|
1283
1322
|
return false;
|
|
1284
1323
|
}
|
|
1285
1324
|
};
|
|
1286
1325
|
var moveFolder = (src, dest) => {
|
|
1287
1326
|
if (sameDev(src, dest)) {
|
|
1288
|
-
(0,
|
|
1327
|
+
(0, import_fs11.renameSync)(src, dest);
|
|
1289
1328
|
} else {
|
|
1290
|
-
(0,
|
|
1291
|
-
(
|
|
1329
|
+
(0, import_fs11.cpSync)(src, dest, { recursive: true });
|
|
1330
|
+
trashPath(src, { recursive: true });
|
|
1292
1331
|
}
|
|
1293
1332
|
};
|
|
1294
|
-
var findVideo = (dir) => (0,
|
|
1333
|
+
var findVideo = (dir) => (0, import_fs11.readdirSync)(dir).find((f) => {
|
|
1295
1334
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1296
1335
|
return ext && videoExtensions_default.includes(ext);
|
|
1297
1336
|
}) ?? null;
|
|
1298
|
-
var containsBook = (dir, depth = 2) => (0,
|
|
1337
|
+
var containsBook = (dir, depth = 2) => (0, import_fs11.readdirSync)(dir).some((f) => {
|
|
1299
1338
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1300
1339
|
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1301
1340
|
if (depth > 1) {
|
|
1302
1341
|
try {
|
|
1303
|
-
const sub = (0,
|
|
1304
|
-
if ((0,
|
|
1342
|
+
const sub = (0, import_path12.resolve)(dir, f);
|
|
1343
|
+
if ((0, import_fs11.lstatSync)(sub).isDirectory()) return containsBook(sub, depth - 1);
|
|
1305
1344
|
} catch {
|
|
1306
1345
|
}
|
|
1307
1346
|
}
|
|
@@ -1311,11 +1350,11 @@ var isTvEpisodeName = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i
|
|
|
1311
1350
|
var isSeasonDirName = (name) => !isTvEpisodeName(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1312
1351
|
var gatherEntries = (source) => {
|
|
1313
1352
|
const result = [];
|
|
1314
|
-
for (const name of (0,
|
|
1315
|
-
const fullPath = (0,
|
|
1353
|
+
for (const name of (0, import_fs11.readdirSync)(source)) {
|
|
1354
|
+
const fullPath = (0, import_path12.resolve)(source, name);
|
|
1316
1355
|
let isDir;
|
|
1317
1356
|
try {
|
|
1318
|
-
isDir = (0,
|
|
1357
|
+
isDir = (0, import_fs11.lstatSync)(fullPath).isDirectory();
|
|
1319
1358
|
} catch {
|
|
1320
1359
|
continue;
|
|
1321
1360
|
}
|
|
@@ -1333,17 +1372,17 @@ var gatherEntries = (source) => {
|
|
|
1333
1372
|
}
|
|
1334
1373
|
let children;
|
|
1335
1374
|
try {
|
|
1336
|
-
children = (0,
|
|
1375
|
+
children = (0, import_fs11.readdirSync)(fullPath);
|
|
1337
1376
|
} catch {
|
|
1338
1377
|
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1339
1378
|
continue;
|
|
1340
1379
|
}
|
|
1341
1380
|
if (children.some((c) => isTvEpisodeName(c))) {
|
|
1342
1381
|
for (const child of children) {
|
|
1343
|
-
const childPath = (0,
|
|
1382
|
+
const childPath = (0, import_path12.resolve)(fullPath, child);
|
|
1344
1383
|
let childIsDir;
|
|
1345
1384
|
try {
|
|
1346
|
-
childIsDir = (0,
|
|
1385
|
+
childIsDir = (0, import_fs11.lstatSync)(childPath).isDirectory();
|
|
1347
1386
|
} catch {
|
|
1348
1387
|
continue;
|
|
1349
1388
|
}
|
|
@@ -1355,25 +1394,25 @@ var gatherEntries = (source) => {
|
|
|
1355
1394
|
}
|
|
1356
1395
|
const seasonDirs = children.filter((c) => {
|
|
1357
1396
|
try {
|
|
1358
|
-
return isSeasonDirName(c) && (0,
|
|
1397
|
+
return isSeasonDirName(c) && (0, import_fs11.lstatSync)((0, import_path12.resolve)(fullPath, c)).isDirectory();
|
|
1359
1398
|
} catch {
|
|
1360
1399
|
return false;
|
|
1361
1400
|
}
|
|
1362
1401
|
});
|
|
1363
1402
|
if (seasonDirs.length > 0) {
|
|
1364
1403
|
for (const seasonDir of seasonDirs) {
|
|
1365
|
-
const seasonPath = (0,
|
|
1404
|
+
const seasonPath = (0, import_path12.resolve)(fullPath, seasonDir);
|
|
1366
1405
|
let seasonChildren;
|
|
1367
1406
|
try {
|
|
1368
|
-
seasonChildren = (0,
|
|
1407
|
+
seasonChildren = (0, import_fs11.readdirSync)(seasonPath);
|
|
1369
1408
|
} catch {
|
|
1370
1409
|
continue;
|
|
1371
1410
|
}
|
|
1372
1411
|
for (const child of seasonChildren) {
|
|
1373
|
-
const childPath = (0,
|
|
1412
|
+
const childPath = (0, import_path12.resolve)(seasonPath, child);
|
|
1374
1413
|
let childIsDir;
|
|
1375
1414
|
try {
|
|
1376
|
-
childIsDir = (0,
|
|
1415
|
+
childIsDir = (0, import_fs11.lstatSync)(childPath).isDirectory();
|
|
1377
1416
|
} catch {
|
|
1378
1417
|
continue;
|
|
1379
1418
|
}
|
|
@@ -1389,19 +1428,19 @@ var gatherEntries = (source) => {
|
|
|
1389
1428
|
return result;
|
|
1390
1429
|
};
|
|
1391
1430
|
var findShowFolder = (destRoot, title) => {
|
|
1392
|
-
if (!(0,
|
|
1431
|
+
if (!(0, import_fs11.existsSync)(destRoot)) return null;
|
|
1393
1432
|
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1394
1433
|
const target = normalize(title);
|
|
1395
|
-
return (0,
|
|
1434
|
+
return (0, import_fs11.readdirSync)(destRoot).filter((f) => {
|
|
1396
1435
|
try {
|
|
1397
|
-
return (0,
|
|
1436
|
+
return (0, import_fs11.lstatSync)((0, import_path12.resolve)(destRoot, f)).isDirectory();
|
|
1398
1437
|
} catch {
|
|
1399
1438
|
return false;
|
|
1400
1439
|
}
|
|
1401
1440
|
}).find((f) => normalize(f) === target) ?? null;
|
|
1402
1441
|
};
|
|
1403
1442
|
var findShowFolderByContent = (destRoot, title) => {
|
|
1404
|
-
if (!(0,
|
|
1443
|
+
if (!(0, import_fs11.existsSync)(destRoot)) return null;
|
|
1405
1444
|
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1406
1445
|
const target = normalize(title);
|
|
1407
1446
|
const matchesTitle = (name) => {
|
|
@@ -1409,18 +1448,18 @@ var findShowFolderByContent = (destRoot, title) => {
|
|
|
1409
1448
|
const p = parseDownloadName(name);
|
|
1410
1449
|
return !!p && normalize(p.title) === target;
|
|
1411
1450
|
};
|
|
1412
|
-
for (const folder of (0,
|
|
1451
|
+
for (const folder of (0, import_fs11.readdirSync)(destRoot)) {
|
|
1413
1452
|
try {
|
|
1414
|
-
const folderPath = (0,
|
|
1415
|
-
if (!(0,
|
|
1416
|
-
const children = (0,
|
|
1453
|
+
const folderPath = (0, import_path12.resolve)(destRoot, folder);
|
|
1454
|
+
if (!(0, import_fs11.lstatSync)(folderPath).isDirectory()) continue;
|
|
1455
|
+
const children = (0, import_fs11.readdirSync)(folderPath);
|
|
1417
1456
|
if (children.some(matchesTitle)) return folder;
|
|
1418
1457
|
for (const child of children) {
|
|
1419
1458
|
if (!isSeasonDirName(child)) continue;
|
|
1420
1459
|
try {
|
|
1421
|
-
const seasonPath = (0,
|
|
1422
|
-
if (!(0,
|
|
1423
|
-
if ((0,
|
|
1460
|
+
const seasonPath = (0, import_path12.resolve)(folderPath, child);
|
|
1461
|
+
if (!(0, import_fs11.lstatSync)(seasonPath).isDirectory()) continue;
|
|
1462
|
+
if ((0, import_fs11.readdirSync)(seasonPath).some(matchesTitle)) return folder;
|
|
1424
1463
|
} catch {
|
|
1425
1464
|
}
|
|
1426
1465
|
}
|
|
@@ -1429,15 +1468,19 @@ var findShowFolderByContent = (destRoot, title) => {
|
|
|
1429
1468
|
}
|
|
1430
1469
|
return null;
|
|
1431
1470
|
};
|
|
1432
|
-
var findSeasonFolder = (showPath, season) => {
|
|
1433
|
-
if (!(0,
|
|
1434
|
-
const folders = (0,
|
|
1471
|
+
var findSeasonFolder = (showPath, season, specialsFolder) => {
|
|
1472
|
+
if (!(0, import_fs11.existsSync)(showPath)) return null;
|
|
1473
|
+
const folders = (0, import_fs11.readdirSync)(showPath).filter((f) => {
|
|
1435
1474
|
try {
|
|
1436
|
-
return (0,
|
|
1475
|
+
return (0, import_fs11.lstatSync)((0, import_path12.resolve)(showPath, f)).isDirectory();
|
|
1437
1476
|
} catch {
|
|
1438
1477
|
return false;
|
|
1439
1478
|
}
|
|
1440
1479
|
});
|
|
1480
|
+
if (season === 0 && specialsFolder) {
|
|
1481
|
+
const existing = folders.find((f) => f.toLowerCase() === specialsFolder.toLowerCase());
|
|
1482
|
+
if (existing) return existing;
|
|
1483
|
+
}
|
|
1441
1484
|
return folders.find((f) => {
|
|
1442
1485
|
const match = f.match(/(?:season|s)\s*0*(\d+)/i);
|
|
1443
1486
|
return match && parseInt(match[1]) === season;
|
|
@@ -1466,11 +1509,13 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1466
1509
|
const language = config.language ?? "eng";
|
|
1467
1510
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1468
1511
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
1512
|
+
const specialsFolder = config.specialsFolder ?? "Specials";
|
|
1469
1513
|
const lookupMovie = async (parsed) => {
|
|
1470
1514
|
let tmdbId;
|
|
1471
1515
|
let resolvedTitle = parsed.title;
|
|
1472
1516
|
let resolvedYear = parsed.year;
|
|
1473
1517
|
if (config.tmdbApiKey) {
|
|
1518
|
+
spinner_default.text = `TMDb: ${parsed.title}`;
|
|
1474
1519
|
const results = await searchMovie(parsed.title, parsed.year, config.tmdbApiKey);
|
|
1475
1520
|
if (results.length === 1) {
|
|
1476
1521
|
tmdbId = results[0].id;
|
|
@@ -1498,8 +1543,8 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1498
1543
|
const importMovie = async (entry, entryPath, isDir, resolvedTitle, resolvedYear, tmdbId, destRoot) => {
|
|
1499
1544
|
const edition = detectEdition(entry);
|
|
1500
1545
|
const folderName = formatMovieName(movieFormat, resolvedTitle, resolvedYear, edition);
|
|
1501
|
-
const destFolder = (0,
|
|
1502
|
-
if ((0,
|
|
1546
|
+
const destFolder = (0, import_path12.resolve)(destRoot, folderName);
|
|
1547
|
+
if ((0, import_fs11.existsSync)(destFolder)) {
|
|
1503
1548
|
spinner_default.warn(`already exists: ${folderName}`);
|
|
1504
1549
|
return false;
|
|
1505
1550
|
}
|
|
@@ -1510,43 +1555,43 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1510
1555
|
}
|
|
1511
1556
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
1512
1557
|
const destVideoName = `${folderName}.${videoExt}`;
|
|
1513
|
-
const videoSourcePath = isDir ? (0,
|
|
1514
|
-
const dirFiles = isDir ? (0,
|
|
1558
|
+
const videoSourcePath = isDir ? (0, import_path12.resolve)(entryPath, videoFile) : entryPath;
|
|
1559
|
+
const dirFiles = isDir ? (0, import_fs11.readdirSync)(entryPath) : [];
|
|
1515
1560
|
const subtitle = isDir ? findSubtitle(dirFiles, language) : null;
|
|
1516
1561
|
const subtitleExt = subtitle?.match(/([^.]+$)/)?.[0];
|
|
1517
|
-
const subtitleSourcePath = subtitle ? (0,
|
|
1562
|
+
const subtitleSourcePath = subtitle ? (0, import_path12.resolve)(entryPath, subtitle) : null;
|
|
1518
1563
|
const destSubtitleName = subtitle && subtitleExt ? `${folderName}.${subtitleExt}` : null;
|
|
1519
1564
|
if (!dryRun) {
|
|
1520
1565
|
if (useHardlink) {
|
|
1521
|
-
(0,
|
|
1522
|
-
const destVideoPath = (0,
|
|
1566
|
+
(0, import_fs11.mkdirSync)(destFolder, { recursive: true });
|
|
1567
|
+
const destVideoPath = (0, import_path12.resolve)(destFolder, destVideoName);
|
|
1523
1568
|
let mode;
|
|
1524
1569
|
try {
|
|
1525
1570
|
if (!sameDev(videoSourcePath, destRoot)) throw new Error("cross-filesystem");
|
|
1526
|
-
(0,
|
|
1571
|
+
(0, import_fs11.linkSync)(videoSourcePath, destVideoPath);
|
|
1527
1572
|
mode = "hardlink";
|
|
1528
1573
|
} catch {
|
|
1529
1574
|
spinner_default.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
1530
|
-
(0,
|
|
1575
|
+
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1531
1576
|
mode = "copy";
|
|
1532
1577
|
}
|
|
1533
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
1578
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs11.cpSync)(subtitleSourcePath, (0, import_path12.resolve)(destFolder, destSubtitleName));
|
|
1534
1579
|
recordImport(sessionId, entryPath, destFolder, mode, tmdbId, "movie");
|
|
1535
1580
|
} else {
|
|
1536
1581
|
if (isDir) {
|
|
1537
1582
|
const keep = new Set([videoFile, subtitle].filter(Boolean));
|
|
1538
|
-
for (const f of dirFiles.filter((f2) => !keep.has(f2))) (
|
|
1539
|
-
(0,
|
|
1540
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
1583
|
+
for (const f of dirFiles.filter((f2) => !keep.has(f2))) trashPath((0, import_path12.resolve)(entryPath, f), { recursive: true });
|
|
1584
|
+
(0, import_fs11.renameSync)(videoSourcePath, (0, import_path12.resolve)(entryPath, destVideoName));
|
|
1585
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs11.renameSync)(subtitleSourcePath, (0, import_path12.resolve)(entryPath, destSubtitleName));
|
|
1541
1586
|
moveFolder(entryPath, destFolder);
|
|
1542
1587
|
} else {
|
|
1543
|
-
(0,
|
|
1544
|
-
const destVideoPath = (0,
|
|
1588
|
+
(0, import_fs11.mkdirSync)(destFolder, { recursive: true });
|
|
1589
|
+
const destVideoPath = (0, import_path12.resolve)(destFolder, destVideoName);
|
|
1545
1590
|
if (sameDev(videoSourcePath, destRoot)) {
|
|
1546
|
-
(0,
|
|
1591
|
+
(0, import_fs11.renameSync)(videoSourcePath, destVideoPath);
|
|
1547
1592
|
} else {
|
|
1548
|
-
(0,
|
|
1549
|
-
(
|
|
1593
|
+
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1594
|
+
trashPath(videoSourcePath);
|
|
1550
1595
|
}
|
|
1551
1596
|
}
|
|
1552
1597
|
recordImport(sessionId, entryPath, destFolder, "move", tmdbId, "movie");
|
|
@@ -1563,12 +1608,13 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1563
1608
|
const ignoreSet = new Set(config.ignore ?? []);
|
|
1564
1609
|
const seenIgnored = /* @__PURE__ */ new Set();
|
|
1565
1610
|
for (const source of config.sources) {
|
|
1566
|
-
if (!(0,
|
|
1611
|
+
if (!(0, import_fs11.existsSync)(source)) {
|
|
1567
1612
|
spinner_default.warn(`source not found: ${import_termkit10.Color.white.encoder(source)}`);
|
|
1568
1613
|
continue;
|
|
1569
1614
|
}
|
|
1570
1615
|
spinner_default.text = `scanning ${import_termkit10.Color.white.encoder(source)}`;
|
|
1571
1616
|
for (const { entry, entryPath, isDir } of gatherEntries(source)) {
|
|
1617
|
+
spinner_default.text = `scanning: ${entry}`;
|
|
1572
1618
|
if (ignoreSet.has(entry)) {
|
|
1573
1619
|
seenIgnored.add(entry);
|
|
1574
1620
|
if (isVerbose()) spinner_default.info(`ignored: ${entry}`);
|
|
@@ -1603,8 +1649,8 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1603
1649
|
continue;
|
|
1604
1650
|
}
|
|
1605
1651
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
1606
|
-
const destPath = (0,
|
|
1607
|
-
if ((0,
|
|
1652
|
+
const destPath = (0, import_path12.resolve)(destRoot, destName);
|
|
1653
|
+
if ((0, import_fs11.existsSync)(destPath)) {
|
|
1608
1654
|
spinner_default.warn(`already exists: ${destName}`);
|
|
1609
1655
|
skipped++;
|
|
1610
1656
|
continue;
|
|
@@ -1618,8 +1664,8 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1618
1664
|
continue;
|
|
1619
1665
|
}
|
|
1620
1666
|
if (detectedType === "book") {
|
|
1621
|
-
const destPath = (0,
|
|
1622
|
-
if ((0,
|
|
1667
|
+
const destPath = (0, import_path12.resolve)(destRoot, entry);
|
|
1668
|
+
if ((0, import_fs11.existsSync)(destPath)) {
|
|
1623
1669
|
spinner_default.warn(`already exists: ${entry}`);
|
|
1624
1670
|
skipped++;
|
|
1625
1671
|
continue;
|
|
@@ -1628,12 +1674,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1628
1674
|
if (isDir || isBookDir) {
|
|
1629
1675
|
moveFolder(entryPath, destPath);
|
|
1630
1676
|
} else {
|
|
1631
|
-
(0,
|
|
1677
|
+
(0, import_fs11.mkdirSync)(destRoot, { recursive: true });
|
|
1632
1678
|
if (sameDev(entryPath, destRoot)) {
|
|
1633
|
-
(0,
|
|
1679
|
+
(0, import_fs11.renameSync)(entryPath, destPath);
|
|
1634
1680
|
} else {
|
|
1635
|
-
(0,
|
|
1636
|
-
(0,
|
|
1681
|
+
(0, import_fs11.cpSync)(entryPath, destPath);
|
|
1682
|
+
(0, import_fs11.rmSync)(entryPath);
|
|
1637
1683
|
}
|
|
1638
1684
|
}
|
|
1639
1685
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
@@ -1665,6 +1711,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1665
1711
|
let resolvedYear = parsed.year;
|
|
1666
1712
|
if (config.tmdbApiKey) {
|
|
1667
1713
|
if (detectedType === "tv") {
|
|
1714
|
+
spinner_default.text = `TMDb: ${parsed.title}`;
|
|
1668
1715
|
const results = await searchTv(parsed.title, config.tmdbApiKey);
|
|
1669
1716
|
if (results.length === 1) {
|
|
1670
1717
|
tmdbId = results[0].id;
|
|
@@ -1709,18 +1756,18 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1709
1756
|
const existingFolder = findShowFolder(destRoot, resolvedTitle) ?? findShowFolderByContent(destRoot, resolvedTitle);
|
|
1710
1757
|
if (existingFolder) {
|
|
1711
1758
|
showFolderName = existingFolder;
|
|
1712
|
-
showPath = (0,
|
|
1759
|
+
showPath = (0, import_path12.resolve)(destRoot, existingFolder);
|
|
1713
1760
|
} else if (auto) {
|
|
1714
1761
|
showFolderName = formatMovieName(movieFormat, resolvedTitle, resolvedYear);
|
|
1715
|
-
showPath = (0,
|
|
1762
|
+
showPath = (0, import_path12.resolve)(destRoot, showFolderName);
|
|
1716
1763
|
if (!dryRun) upsertShow(showPath, tmdbId ?? null, resolvedTitle);
|
|
1717
1764
|
} else {
|
|
1718
1765
|
pendingTv.push({ entry, entryPath, isDir, parsed, resolvedTitle, destRoot });
|
|
1719
1766
|
continue;
|
|
1720
1767
|
}
|
|
1721
1768
|
}
|
|
1722
|
-
const seasonFolderName = findSeasonFolder(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
1723
|
-
const seasonPath = (0,
|
|
1769
|
+
const seasonFolderName = parsed.season === 0 ? findSeasonFolder(showPath, 0, specialsFolder) ?? specialsFolder : findSeasonFolder(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
1770
|
+
const seasonPath = (0, import_path12.resolve)(showPath, seasonFolderName);
|
|
1724
1771
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
1725
1772
|
if (!videoFile) {
|
|
1726
1773
|
if (isVerbose()) spinner_default.info(`no video found in: ${entry}`);
|
|
@@ -1728,13 +1775,15 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1728
1775
|
continue;
|
|
1729
1776
|
}
|
|
1730
1777
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
1778
|
+
if (tmdbId && config.tmdbApiKey) spinner_default.text = `TMDb: episode name for ${resolvedTitle}`;
|
|
1731
1779
|
const tmdbEpisodeName = tmdbId && config.tmdbApiKey ? await getEpisodeName(tmdbId, parsed.season, parsed.episode ?? 1, config.tmdbApiKey) : null;
|
|
1732
1780
|
const episodeName = formatEpisode(parsed.season, parsed.episode ?? 1, config.format?.episode, false, resolvedTitle, tmdbEpisodeName ?? void 0);
|
|
1733
1781
|
const destVideoName = `${episodeName}.${videoExt}`;
|
|
1734
|
-
const destVideoPath = (0,
|
|
1735
|
-
const videoSourcePath = isDir ? (0,
|
|
1736
|
-
if ((0,
|
|
1737
|
-
|
|
1782
|
+
const destVideoPath = (0, import_path12.resolve)(seasonPath, destVideoName);
|
|
1783
|
+
const videoSourcePath = isDir ? (0, import_path12.resolve)(entryPath, videoFile) : entryPath;
|
|
1784
|
+
if ((0, import_fs11.existsSync)(destVideoPath)) {
|
|
1785
|
+
const isRepack = /\brepack\d*\b|\bproper\b/i.test(entry);
|
|
1786
|
+
let shouldReplace = force || isRepack;
|
|
1738
1787
|
if (!shouldReplace && interactive) {
|
|
1739
1788
|
spinner_default.stop();
|
|
1740
1789
|
const select = new import_termkit10.Select();
|
|
@@ -1751,39 +1800,39 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1751
1800
|
continue;
|
|
1752
1801
|
}
|
|
1753
1802
|
if (!dryRun) {
|
|
1754
|
-
for (const f of (0,
|
|
1755
|
-
if (f.startsWith(`${episodeName}.`)) (
|
|
1803
|
+
for (const f of (0, import_fs11.readdirSync)(seasonPath)) {
|
|
1804
|
+
if (f.startsWith(`${episodeName}.`)) trashPath((0, import_path12.resolve)(seasonPath, f));
|
|
1756
1805
|
}
|
|
1757
1806
|
}
|
|
1758
1807
|
}
|
|
1759
|
-
const dirFiles = isDir ? (0,
|
|
1808
|
+
const dirFiles = isDir ? (0, import_fs11.readdirSync)(entryPath) : [];
|
|
1760
1809
|
const subtitle = isDir ? findSubtitle(dirFiles, language) : null;
|
|
1761
1810
|
const subtitleExt = subtitle?.match(/([^.]+$)/)?.[0];
|
|
1762
|
-
const subtitleSourcePath = subtitle ? (0,
|
|
1811
|
+
const subtitleSourcePath = subtitle ? (0, import_path12.resolve)(entryPath, subtitle) : null;
|
|
1763
1812
|
const destSubtitleName = subtitle && subtitleExt ? `${episodeName}.${subtitleExt}` : null;
|
|
1764
1813
|
if (!dryRun) {
|
|
1765
|
-
(0,
|
|
1814
|
+
(0, import_fs11.mkdirSync)(seasonPath, { recursive: true });
|
|
1766
1815
|
let mode = "move";
|
|
1767
1816
|
if (useHardlink) {
|
|
1768
1817
|
try {
|
|
1769
1818
|
if (!sameDev(videoSourcePath, seasonPath)) throw new Error("cross-filesystem");
|
|
1770
|
-
(0,
|
|
1819
|
+
(0, import_fs11.linkSync)(videoSourcePath, destVideoPath);
|
|
1771
1820
|
mode = "hardlink";
|
|
1772
1821
|
} catch {
|
|
1773
1822
|
spinner_default.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
1774
|
-
(0,
|
|
1823
|
+
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1775
1824
|
mode = "copy";
|
|
1776
1825
|
}
|
|
1777
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
1826
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs11.cpSync)(subtitleSourcePath, (0, import_path12.resolve)(seasonPath, destSubtitleName));
|
|
1778
1827
|
} else {
|
|
1779
1828
|
if (sameDev(videoSourcePath, seasonPath)) {
|
|
1780
|
-
(0,
|
|
1829
|
+
(0, import_fs11.renameSync)(videoSourcePath, destVideoPath);
|
|
1781
1830
|
} else {
|
|
1782
|
-
(0,
|
|
1783
|
-
(
|
|
1831
|
+
(0, import_fs11.cpSync)(videoSourcePath, destVideoPath);
|
|
1832
|
+
trashPath(videoSourcePath);
|
|
1784
1833
|
}
|
|
1785
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
1786
|
-
if (isDir) (
|
|
1834
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs11.renameSync)(subtitleSourcePath, (0, import_path12.resolve)(seasonPath, destSubtitleName));
|
|
1835
|
+
if (isDir) trashPath(entryPath, { recursive: true });
|
|
1787
1836
|
}
|
|
1788
1837
|
recordImport(sessionId, entryPath, seasonPath, mode, tmdbId, "tv");
|
|
1789
1838
|
}
|
|
@@ -1848,7 +1897,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1848
1897
|
var scan_default = scan;
|
|
1849
1898
|
|
|
1850
1899
|
// src/actions/undo.ts
|
|
1851
|
-
var
|
|
1900
|
+
var import_fs12 = require("fs");
|
|
1852
1901
|
var import_termkit11 = require("termkit");
|
|
1853
1902
|
var undo = async () => {
|
|
1854
1903
|
spinner_default.start();
|
|
@@ -1863,7 +1912,7 @@ var undo = async () => {
|
|
|
1863
1912
|
if (!useImports) {
|
|
1864
1913
|
let undone2 = 0;
|
|
1865
1914
|
for (const record of renameRecords) {
|
|
1866
|
-
(0,
|
|
1915
|
+
(0, import_fs12.renameSync)(record.newPath, record.oldPath);
|
|
1867
1916
|
spinner_default.succeed(`${import_termkit11.Color.green.encoder(record.newPath)} \u2192 ${import_termkit11.Color.white.encoder(record.oldPath)}`);
|
|
1868
1917
|
undone2++;
|
|
1869
1918
|
}
|
|
@@ -1885,12 +1934,12 @@ var undo = async () => {
|
|
|
1885
1934
|
skipped++;
|
|
1886
1935
|
continue;
|
|
1887
1936
|
}
|
|
1888
|
-
if (!(0,
|
|
1937
|
+
if (!(0, import_fs12.existsSync)(record.destinationPath)) {
|
|
1889
1938
|
spinner_default.info(`skipped \u2014 destination no longer exists: ${record.destinationPath}`);
|
|
1890
1939
|
skipped++;
|
|
1891
1940
|
continue;
|
|
1892
1941
|
}
|
|
1893
|
-
(0,
|
|
1942
|
+
(0, import_fs12.renameSync)(record.destinationPath, record.sourcePath);
|
|
1894
1943
|
spinner_default.succeed(`${import_termkit11.Color.green.encoder(record.destinationPath)} \u2192 ${import_termkit11.Color.white.encoder(record.sourcePath)}`);
|
|
1895
1944
|
undone++;
|
|
1896
1945
|
}
|
|
@@ -1903,37 +1952,37 @@ var undo_default = undo;
|
|
|
1903
1952
|
|
|
1904
1953
|
// src/actions/watch.ts
|
|
1905
1954
|
var import_chokidar = __toESM(require("chokidar"));
|
|
1906
|
-
var
|
|
1907
|
-
var
|
|
1955
|
+
var import_fs13 = require("fs");
|
|
1956
|
+
var import_path13 = require("path");
|
|
1908
1957
|
var import_termkit12 = require("termkit");
|
|
1909
1958
|
var sameDev2 = (a, b) => {
|
|
1910
1959
|
try {
|
|
1911
1960
|
let bExisting = b;
|
|
1912
|
-
while (!(0,
|
|
1913
|
-
return (0,
|
|
1961
|
+
while (!(0, import_fs13.existsSync)(bExisting)) bExisting = (0, import_path13.dirname)(bExisting);
|
|
1962
|
+
return (0, import_fs13.statSync)(a).dev === (0, import_fs13.statSync)(bExisting).dev;
|
|
1914
1963
|
} catch {
|
|
1915
1964
|
return false;
|
|
1916
1965
|
}
|
|
1917
1966
|
};
|
|
1918
1967
|
var moveItem = (src, dest) => {
|
|
1919
1968
|
if (sameDev2(src, dest)) {
|
|
1920
|
-
(0,
|
|
1969
|
+
(0, import_fs13.renameSync)(src, dest);
|
|
1921
1970
|
} else {
|
|
1922
|
-
(0,
|
|
1923
|
-
(0,
|
|
1971
|
+
(0, import_fs13.cpSync)(src, dest, { recursive: true });
|
|
1972
|
+
(0, import_fs13.rmSync)(src, { recursive: true, force: true });
|
|
1924
1973
|
}
|
|
1925
1974
|
};
|
|
1926
|
-
var findVideo2 = (dir) => (0,
|
|
1975
|
+
var findVideo2 = (dir) => (0, import_fs13.readdirSync)(dir).find((f) => {
|
|
1927
1976
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1928
1977
|
return ext && videoExtensions_default.includes(ext);
|
|
1929
1978
|
}) ?? null;
|
|
1930
|
-
var containsBook2 = (dir, depth = 2) => (0,
|
|
1979
|
+
var containsBook2 = (dir, depth = 2) => (0, import_fs13.readdirSync)(dir).some((f) => {
|
|
1931
1980
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1932
1981
|
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1933
1982
|
if (depth > 1) {
|
|
1934
1983
|
try {
|
|
1935
|
-
const sub = (0,
|
|
1936
|
-
if ((0,
|
|
1984
|
+
const sub = (0, import_path13.resolve)(dir, f);
|
|
1985
|
+
if ((0, import_fs13.lstatSync)(sub).isDirectory()) return containsBook2(sub, depth - 1);
|
|
1937
1986
|
} catch {
|
|
1938
1987
|
}
|
|
1939
1988
|
}
|
|
@@ -1944,26 +1993,26 @@ var isSeasonDirName2 = (name) => !isTvEpisodeName2(name) && /(?:^|[.\s_-])(?:sea
|
|
|
1944
1993
|
var expandWatchPath = (p) => {
|
|
1945
1994
|
let isDir;
|
|
1946
1995
|
try {
|
|
1947
|
-
isDir = (0,
|
|
1996
|
+
isDir = (0, import_fs13.lstatSync)(p).isDirectory();
|
|
1948
1997
|
} catch {
|
|
1949
1998
|
return [p];
|
|
1950
1999
|
}
|
|
1951
2000
|
if (!isDir) return [p];
|
|
1952
|
-
const name = (0,
|
|
2001
|
+
const name = (0, import_path13.basename)(p);
|
|
1953
2002
|
if (isTvEpisodeName2(name) || /(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name)) return [p];
|
|
1954
2003
|
let children;
|
|
1955
2004
|
try {
|
|
1956
|
-
children = (0,
|
|
2005
|
+
children = (0, import_fs13.readdirSync)(p);
|
|
1957
2006
|
} catch {
|
|
1958
2007
|
return [p];
|
|
1959
2008
|
}
|
|
1960
2009
|
if (children.some((c) => isTvEpisodeName2(c))) {
|
|
1961
2010
|
const entries = [];
|
|
1962
2011
|
for (const child of children) {
|
|
1963
|
-
const cp = (0,
|
|
2012
|
+
const cp = (0, import_path13.resolve)(p, child);
|
|
1964
2013
|
let cd;
|
|
1965
2014
|
try {
|
|
1966
|
-
cd = (0,
|
|
2015
|
+
cd = (0, import_fs13.lstatSync)(cp).isDirectory();
|
|
1967
2016
|
} catch {
|
|
1968
2017
|
continue;
|
|
1969
2018
|
}
|
|
@@ -1975,7 +2024,7 @@ var expandWatchPath = (p) => {
|
|
|
1975
2024
|
}
|
|
1976
2025
|
const seasonDirs = children.filter((c) => {
|
|
1977
2026
|
try {
|
|
1978
|
-
return isSeasonDirName2(c) && (0,
|
|
2027
|
+
return isSeasonDirName2(c) && (0, import_fs13.lstatSync)((0, import_path13.resolve)(p, c)).isDirectory();
|
|
1979
2028
|
} catch {
|
|
1980
2029
|
return false;
|
|
1981
2030
|
}
|
|
@@ -1983,18 +2032,18 @@ var expandWatchPath = (p) => {
|
|
|
1983
2032
|
if (seasonDirs.length > 0) {
|
|
1984
2033
|
const entries = [];
|
|
1985
2034
|
for (const sd of seasonDirs) {
|
|
1986
|
-
const sp = (0,
|
|
2035
|
+
const sp = (0, import_path13.resolve)(p, sd);
|
|
1987
2036
|
let sc;
|
|
1988
2037
|
try {
|
|
1989
|
-
sc = (0,
|
|
2038
|
+
sc = (0, import_fs13.readdirSync)(sp);
|
|
1990
2039
|
} catch {
|
|
1991
2040
|
continue;
|
|
1992
2041
|
}
|
|
1993
2042
|
for (const child of sc) {
|
|
1994
|
-
const cp = (0,
|
|
2043
|
+
const cp = (0, import_path13.resolve)(sp, child);
|
|
1995
2044
|
let cd;
|
|
1996
2045
|
try {
|
|
1997
|
-
cd = (0,
|
|
2046
|
+
cd = (0, import_fs13.lstatSync)(cp).isDirectory();
|
|
1998
2047
|
} catch {
|
|
1999
2048
|
continue;
|
|
2000
2049
|
}
|
|
@@ -2008,10 +2057,10 @@ var expandWatchPath = (p) => {
|
|
|
2008
2057
|
return [p];
|
|
2009
2058
|
};
|
|
2010
2059
|
var findSeasonFolder2 = (showPath, season) => {
|
|
2011
|
-
if (!(0,
|
|
2012
|
-
const folders = (0,
|
|
2060
|
+
if (!(0, import_fs13.existsSync)(showPath)) return null;
|
|
2061
|
+
const folders = (0, import_fs13.readdirSync)(showPath).filter((f) => {
|
|
2013
2062
|
try {
|
|
2014
|
-
return (0,
|
|
2063
|
+
return (0, import_fs13.lstatSync)((0, import_path13.resolve)(showPath, f)).isDirectory();
|
|
2015
2064
|
} catch {
|
|
2016
2065
|
return false;
|
|
2017
2066
|
}
|
|
@@ -2024,10 +2073,10 @@ var findSeasonFolder2 = (showPath, season) => {
|
|
|
2024
2073
|
var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
2025
2074
|
const config = getConfig();
|
|
2026
2075
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
2027
|
-
const entry = (0,
|
|
2076
|
+
const entry = (0, import_path13.basename)(entryPath);
|
|
2028
2077
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
2029
2078
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
2030
|
-
const isDir = (0,
|
|
2079
|
+
const isDir = (0, import_fs13.lstatSync)(entryPath).isDirectory();
|
|
2031
2080
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
2032
2081
|
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
2033
2082
|
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
@@ -2053,8 +2102,8 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2053
2102
|
const id = entry.split("-")[0];
|
|
2054
2103
|
if (!nameMatch || !id) return;
|
|
2055
2104
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
2056
|
-
const destPath = (0,
|
|
2057
|
-
if ((0,
|
|
2105
|
+
const destPath = (0, import_path13.resolve)(destRoot, destName);
|
|
2106
|
+
if ((0, import_fs13.existsSync)(destPath)) {
|
|
2058
2107
|
spinner_default.warn(`already exists: ${destName}`);
|
|
2059
2108
|
return;
|
|
2060
2109
|
}
|
|
@@ -2064,20 +2113,20 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2064
2113
|
return;
|
|
2065
2114
|
}
|
|
2066
2115
|
if (detectedType === "book") {
|
|
2067
|
-
const destPath = (0,
|
|
2068
|
-
if ((0,
|
|
2116
|
+
const destPath = (0, import_path13.resolve)(destRoot, entry);
|
|
2117
|
+
if ((0, import_fs13.existsSync)(destPath)) {
|
|
2069
2118
|
spinner_default.warn(`already exists: ${entry}`);
|
|
2070
2119
|
return;
|
|
2071
2120
|
}
|
|
2072
2121
|
if (isDir || isBookDir) {
|
|
2073
2122
|
moveItem(entryPath, destPath);
|
|
2074
2123
|
} else {
|
|
2075
|
-
(0,
|
|
2124
|
+
(0, import_fs13.mkdirSync)(destRoot, { recursive: true });
|
|
2076
2125
|
if (sameDev2(entryPath, destRoot)) {
|
|
2077
|
-
(0,
|
|
2126
|
+
(0, import_fs13.renameSync)(entryPath, destPath);
|
|
2078
2127
|
} else {
|
|
2079
|
-
(0,
|
|
2080
|
-
(0,
|
|
2128
|
+
(0, import_fs13.cpSync)(entryPath, destPath);
|
|
2129
|
+
(0, import_fs13.rmSync)(entryPath);
|
|
2081
2130
|
}
|
|
2082
2131
|
}
|
|
2083
2132
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
@@ -2102,14 +2151,14 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2102
2151
|
showFolderName = showPath.split("/").pop() ?? registeredShow.path;
|
|
2103
2152
|
} else if (auto) {
|
|
2104
2153
|
showFolderName = formatMovieName(movieFormat, parsed.title, parsed.year);
|
|
2105
|
-
showPath = (0,
|
|
2154
|
+
showPath = (0, import_path13.resolve)(destRoot, showFolderName);
|
|
2106
2155
|
upsertShow(showPath, null, parsed.title);
|
|
2107
2156
|
} else {
|
|
2108
2157
|
if (isVerbose()) spinner_default.info(`not registered, skipped: ${parsed.title} \u2014 run: reelsort add "${parsed.title}"`);
|
|
2109
2158
|
return;
|
|
2110
2159
|
}
|
|
2111
2160
|
const seasonFolderName = findSeasonFolder2(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
2112
|
-
const seasonPath = (0,
|
|
2161
|
+
const seasonPath = (0, import_path13.resolve)(showPath, seasonFolderName);
|
|
2113
2162
|
const videoFile2 = isDir ? findVideo2(entryPath) : entry;
|
|
2114
2163
|
if (!videoFile2) {
|
|
2115
2164
|
if (isVerbose()) spinner_default.info(`no video found in: ${entry}`);
|
|
@@ -2119,39 +2168,39 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2119
2168
|
const tmdbEpisodeName = registeredShow?.tmdbId && config.tmdbApiKey ? await getEpisodeName(registeredShow.tmdbId, parsed.season, parsed.episode ?? 1, config.tmdbApiKey) : null;
|
|
2120
2169
|
const episodeName = formatEpisode(parsed.season, parsed.episode ?? 1, config.format?.episode, false, parsed.title, tmdbEpisodeName ?? void 0);
|
|
2121
2170
|
const destVideoName2 = `${episodeName}.${videoExt2}`;
|
|
2122
|
-
const destVideoPath = (0,
|
|
2123
|
-
const videoSourcePath2 = isDir ? (0,
|
|
2124
|
-
if ((0,
|
|
2171
|
+
const destVideoPath = (0, import_path13.resolve)(seasonPath, destVideoName2);
|
|
2172
|
+
const videoSourcePath2 = isDir ? (0, import_path13.resolve)(entryPath, videoFile2) : entryPath;
|
|
2173
|
+
if ((0, import_fs13.existsSync)(destVideoPath)) {
|
|
2125
2174
|
spinner_default.warn(`already exists: ${episodeName}`);
|
|
2126
2175
|
return;
|
|
2127
2176
|
}
|
|
2128
|
-
const dirFiles2 = isDir ? (0,
|
|
2177
|
+
const dirFiles2 = isDir ? (0, import_fs13.readdirSync)(entryPath) : [];
|
|
2129
2178
|
const subtitle2 = isDir ? findSubtitle(dirFiles2, language) : null;
|
|
2130
2179
|
const subtitleExt2 = subtitle2?.match(/([^.]+$)/)?.[0];
|
|
2131
|
-
const subtitleSourcePath2 = subtitle2 ? (0,
|
|
2180
|
+
const subtitleSourcePath2 = subtitle2 ? (0, import_path13.resolve)(entryPath, subtitle2) : null;
|
|
2132
2181
|
const destSubtitleName2 = subtitle2 && subtitleExt2 ? `${episodeName}.${subtitleExt2}` : null;
|
|
2133
|
-
(0,
|
|
2182
|
+
(0, import_fs13.mkdirSync)(seasonPath, { recursive: true });
|
|
2134
2183
|
let mode = "move";
|
|
2135
2184
|
if (useHardlink) {
|
|
2136
2185
|
try {
|
|
2137
2186
|
if (!sameDev2(videoSourcePath2, seasonPath)) throw new Error("cross-filesystem");
|
|
2138
|
-
(0,
|
|
2187
|
+
(0, import_fs13.linkSync)(videoSourcePath2, destVideoPath);
|
|
2139
2188
|
mode = "hardlink";
|
|
2140
2189
|
} catch {
|
|
2141
2190
|
spinner_default.warn(`hardlink unavailable \u2014 copying instead: ${episodeName}`);
|
|
2142
|
-
(0,
|
|
2191
|
+
(0, import_fs13.cpSync)(videoSourcePath2, destVideoPath);
|
|
2143
2192
|
mode = "copy";
|
|
2144
2193
|
}
|
|
2145
|
-
if (subtitleSourcePath2 && destSubtitleName2) (0,
|
|
2194
|
+
if (subtitleSourcePath2 && destSubtitleName2) (0, import_fs13.cpSync)(subtitleSourcePath2, (0, import_path13.resolve)(seasonPath, destSubtitleName2));
|
|
2146
2195
|
} else {
|
|
2147
2196
|
if (sameDev2(videoSourcePath2, seasonPath)) {
|
|
2148
|
-
(0,
|
|
2197
|
+
(0, import_fs13.renameSync)(videoSourcePath2, destVideoPath);
|
|
2149
2198
|
} else {
|
|
2150
|
-
(0,
|
|
2151
|
-
(0,
|
|
2199
|
+
(0, import_fs13.cpSync)(videoSourcePath2, destVideoPath);
|
|
2200
|
+
(0, import_fs13.rmSync)(videoSourcePath2);
|
|
2152
2201
|
}
|
|
2153
|
-
if (subtitleSourcePath2 && destSubtitleName2) (0,
|
|
2154
|
-
if (isDir) (0,
|
|
2202
|
+
if (subtitleSourcePath2 && destSubtitleName2) (0, import_fs13.renameSync)(subtitleSourcePath2, (0, import_path13.resolve)(seasonPath, destSubtitleName2));
|
|
2203
|
+
if (isDir) (0, import_fs13.rmSync)(entryPath, { recursive: true, force: true });
|
|
2155
2204
|
}
|
|
2156
2205
|
recordImport(sessionId, entryPath, seasonPath, mode, void 0, "tv");
|
|
2157
2206
|
spinner_default.succeed(`imported ${import_termkit12.Color.green.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
|
|
@@ -2159,8 +2208,8 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2159
2208
|
}
|
|
2160
2209
|
const edition = detectEdition(entry);
|
|
2161
2210
|
const folderName = formatMovieName(movieFormat, parsed.title, parsed.year, edition);
|
|
2162
|
-
const destFolder = (0,
|
|
2163
|
-
if ((0,
|
|
2211
|
+
const destFolder = (0, import_path13.resolve)(destRoot, folderName);
|
|
2212
|
+
if ((0, import_fs13.existsSync)(destFolder)) {
|
|
2164
2213
|
spinner_default.warn(`already exists: ${folderName}`);
|
|
2165
2214
|
return;
|
|
2166
2215
|
}
|
|
@@ -2171,42 +2220,42 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2171
2220
|
}
|
|
2172
2221
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
2173
2222
|
const destVideoName = `${folderName}.${videoExt}`;
|
|
2174
|
-
const videoSourcePath = isDir ? (0,
|
|
2175
|
-
const dirFiles = isDir ? (0,
|
|
2223
|
+
const videoSourcePath = isDir ? (0, import_path13.resolve)(entryPath, videoFile) : entryPath;
|
|
2224
|
+
const dirFiles = isDir ? (0, import_fs13.readdirSync)(entryPath) : [];
|
|
2176
2225
|
const subtitle = isDir ? findSubtitle(dirFiles, language) : null;
|
|
2177
2226
|
const subtitleExt = subtitle?.match(/([^.]+$)/)?.[0];
|
|
2178
|
-
const subtitleSourcePath = subtitle ? (0,
|
|
2227
|
+
const subtitleSourcePath = subtitle ? (0, import_path13.resolve)(entryPath, subtitle) : null;
|
|
2179
2228
|
const destSubtitleName = subtitle && subtitleExt ? `${folderName}.${subtitleExt}` : null;
|
|
2180
2229
|
if (useHardlink) {
|
|
2181
|
-
(0,
|
|
2182
|
-
const destVideoPath = (0,
|
|
2230
|
+
(0, import_fs13.mkdirSync)(destFolder, { recursive: true });
|
|
2231
|
+
const destVideoPath = (0, import_path13.resolve)(destFolder, destVideoName);
|
|
2183
2232
|
let mode;
|
|
2184
2233
|
try {
|
|
2185
2234
|
if (!sameDev2(videoSourcePath, destRoot)) throw new Error("cross-filesystem");
|
|
2186
|
-
(0,
|
|
2235
|
+
(0, import_fs13.linkSync)(videoSourcePath, destVideoPath);
|
|
2187
2236
|
mode = "hardlink";
|
|
2188
2237
|
} catch {
|
|
2189
2238
|
spinner_default.warn(`hardlink unavailable \u2014 copying instead: ${folderName}`);
|
|
2190
|
-
(0,
|
|
2239
|
+
(0, import_fs13.cpSync)(videoSourcePath, destVideoPath);
|
|
2191
2240
|
mode = "copy";
|
|
2192
2241
|
}
|
|
2193
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
2242
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs13.cpSync)(subtitleSourcePath, (0, import_path13.resolve)(destFolder, destSubtitleName));
|
|
2194
2243
|
recordImport(sessionId, entryPath, destFolder, mode, void 0, "movie");
|
|
2195
2244
|
} else {
|
|
2196
2245
|
if (isDir) {
|
|
2197
2246
|
const keep = new Set([videoFile, subtitle].filter(Boolean));
|
|
2198
|
-
for (const f of dirFiles.filter((f2) => !keep.has(f2))) (0,
|
|
2199
|
-
(0,
|
|
2200
|
-
if (subtitleSourcePath && destSubtitleName) (0,
|
|
2247
|
+
for (const f of dirFiles.filter((f2) => !keep.has(f2))) (0, import_fs13.rmSync)((0, import_path13.resolve)(entryPath, f), { recursive: true, force: true });
|
|
2248
|
+
(0, import_fs13.renameSync)(videoSourcePath, (0, import_path13.resolve)(entryPath, destVideoName));
|
|
2249
|
+
if (subtitleSourcePath && destSubtitleName) (0, import_fs13.renameSync)(subtitleSourcePath, (0, import_path13.resolve)(entryPath, destSubtitleName));
|
|
2201
2250
|
moveItem(entryPath, destFolder);
|
|
2202
2251
|
} else {
|
|
2203
|
-
(0,
|
|
2204
|
-
const destVideoPath = (0,
|
|
2252
|
+
(0, import_fs13.mkdirSync)(destFolder, { recursive: true });
|
|
2253
|
+
const destVideoPath = (0, import_path13.resolve)(destFolder, destVideoName);
|
|
2205
2254
|
if (sameDev2(videoSourcePath, destRoot)) {
|
|
2206
|
-
(0,
|
|
2255
|
+
(0, import_fs13.renameSync)(videoSourcePath, destVideoPath);
|
|
2207
2256
|
} else {
|
|
2208
|
-
(0,
|
|
2209
|
-
(0,
|
|
2257
|
+
(0, import_fs13.cpSync)(videoSourcePath, destVideoPath);
|
|
2258
|
+
(0, import_fs13.rmSync)(videoSourcePath);
|
|
2210
2259
|
}
|
|
2211
2260
|
}
|
|
2212
2261
|
recordImport(sessionId, entryPath, destFolder, "move", void 0, "movie");
|