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.mjs
CHANGED
|
@@ -1072,7 +1072,7 @@ var reset = async ({ dir: inputDir, double }) => {
|
|
|
1072
1072
|
var reset_default = reset;
|
|
1073
1073
|
|
|
1074
1074
|
// src/actions/scan.ts
|
|
1075
|
-
import { cpSync, existsSync as
|
|
1075
|
+
import { cpSync, existsSync as existsSync10, linkSync, lstatSync as lstatSync4, mkdirSync as mkdirSync4, readdirSync as readdirSync7, renameSync as renameSync4, rmSync as rmSync3, statSync as statSync2 } from "fs";
|
|
1076
1076
|
import { dirname as dirname2, resolve as resolve8 } from "path";
|
|
1077
1077
|
import { Color as Color9, MultiSelect as MultiSelect2, Select as Select2 } from "termkit";
|
|
1078
1078
|
|
|
@@ -1097,10 +1097,49 @@ var detectEdition = (filename) => {
|
|
|
1097
1097
|
// src/helpers/hyperlink.ts
|
|
1098
1098
|
var hyperlink = (url, text) => `\x1B]8;;${url}\x1B\\${text}\x1B]8;;\x1B\\`;
|
|
1099
1099
|
|
|
1100
|
+
// src/helpers/trash.ts
|
|
1101
|
+
import { execSync } from "child_process";
|
|
1102
|
+
import { existsSync as existsSync9, mkdirSync as mkdirSync3, renameSync as renameSync3, rmSync as rmSync2 } from "fs";
|
|
1103
|
+
import { homedir as homedir3 } from "os";
|
|
1104
|
+
import { basename as basename3, join as join3 } from "path";
|
|
1105
|
+
var trashDir = () => {
|
|
1106
|
+
if (process.platform === "linux") return join3(homedir3(), ".local", "share", "Trash", "files");
|
|
1107
|
+
return join3(homedir3(), ".Trash");
|
|
1108
|
+
};
|
|
1109
|
+
var trashPath = (filePath, opts) => {
|
|
1110
|
+
if (process.platform === "darwin" || process.platform === "linux") {
|
|
1111
|
+
try {
|
|
1112
|
+
const dir = trashDir();
|
|
1113
|
+
if (!existsSync9(dir)) mkdirSync3(dir, { recursive: true });
|
|
1114
|
+
const name = basename3(filePath);
|
|
1115
|
+
let dest = join3(dir, name);
|
|
1116
|
+
let i = 1;
|
|
1117
|
+
while (existsSync9(dest)) dest = join3(dir, `${name} ${i++}`);
|
|
1118
|
+
renameSync3(filePath, dest);
|
|
1119
|
+
return;
|
|
1120
|
+
} catch {
|
|
1121
|
+
}
|
|
1122
|
+
} else if (process.platform === "win32") {
|
|
1123
|
+
try {
|
|
1124
|
+
const escaped = filePath.replace(/'/g, "''");
|
|
1125
|
+
const isDir = opts?.recursive ?? false;
|
|
1126
|
+
const method = isDir ? "DeleteDirectory" : "DeleteFile";
|
|
1127
|
+
execSync(
|
|
1128
|
+
`powershell -NoProfile -NonInteractive -Command "Add-Type -AssemblyName Microsoft.VisualBasic; [Microsoft.VisualBasic.FileIO.FileSystem]::${method}('${escaped}', 'OnlyErrorDialogs', 'SendToRecycleBin')"`,
|
|
1129
|
+
{ stdio: "ignore" }
|
|
1130
|
+
);
|
|
1131
|
+
return;
|
|
1132
|
+
} catch {
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
rmSync2(filePath, { recursive: opts?.recursive ?? false, force: true });
|
|
1136
|
+
};
|
|
1137
|
+
|
|
1100
1138
|
// src/helpers/parseDownloadName.ts
|
|
1101
1139
|
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"]);
|
|
1102
1140
|
var TV_PATTERN = /^(.*?)[.\s_-]*(?:S(\d{2,3})E(\d{2,3})|(\d{1,2})x(\d{2,3})|Season[\s.](\d+))/i;
|
|
1103
|
-
var parseDownloadName = (
|
|
1141
|
+
var parseDownloadName = (rawName) => {
|
|
1142
|
+
const name = rawName.replace(/^[\w.-]+\.\w{2,6}\s+-+\s+/i, "");
|
|
1104
1143
|
const base = name.replace(/\.[a-z0-9]{2,4}$/i, "");
|
|
1105
1144
|
const tvMatch = TV_PATTERN.exec(base);
|
|
1106
1145
|
if (tvMatch) {
|
|
@@ -1199,7 +1238,7 @@ var bookExtensions_default = ["epub", "mobi", "azw3", "azw"];
|
|
|
1199
1238
|
var sameDev = (a, b) => {
|
|
1200
1239
|
try {
|
|
1201
1240
|
let bExisting = b;
|
|
1202
|
-
while (!
|
|
1241
|
+
while (!existsSync10(bExisting)) bExisting = dirname2(bExisting);
|
|
1203
1242
|
return statSync2(a).dev === statSync2(bExisting).dev;
|
|
1204
1243
|
} catch {
|
|
1205
1244
|
return false;
|
|
@@ -1207,10 +1246,10 @@ var sameDev = (a, b) => {
|
|
|
1207
1246
|
};
|
|
1208
1247
|
var moveFolder = (src, dest) => {
|
|
1209
1248
|
if (sameDev(src, dest)) {
|
|
1210
|
-
|
|
1249
|
+
renameSync4(src, dest);
|
|
1211
1250
|
} else {
|
|
1212
1251
|
cpSync(src, dest, { recursive: true });
|
|
1213
|
-
|
|
1252
|
+
trashPath(src, { recursive: true });
|
|
1214
1253
|
}
|
|
1215
1254
|
};
|
|
1216
1255
|
var findVideo = (dir) => readdirSync7(dir).find((f) => {
|
|
@@ -1311,7 +1350,7 @@ var gatherEntries = (source) => {
|
|
|
1311
1350
|
return result;
|
|
1312
1351
|
};
|
|
1313
1352
|
var findShowFolder = (destRoot, title) => {
|
|
1314
|
-
if (!
|
|
1353
|
+
if (!existsSync10(destRoot)) return null;
|
|
1315
1354
|
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1316
1355
|
const target = normalize(title);
|
|
1317
1356
|
return readdirSync7(destRoot).filter((f) => {
|
|
@@ -1323,7 +1362,7 @@ var findShowFolder = (destRoot, title) => {
|
|
|
1323
1362
|
}).find((f) => normalize(f) === target) ?? null;
|
|
1324
1363
|
};
|
|
1325
1364
|
var findShowFolderByContent = (destRoot, title) => {
|
|
1326
|
-
if (!
|
|
1365
|
+
if (!existsSync10(destRoot)) return null;
|
|
1327
1366
|
const normalize = (s) => s.toLowerCase().replace(/[^a-z0-9]/g, "");
|
|
1328
1367
|
const target = normalize(title);
|
|
1329
1368
|
const matchesTitle = (name) => {
|
|
@@ -1351,8 +1390,8 @@ var findShowFolderByContent = (destRoot, title) => {
|
|
|
1351
1390
|
}
|
|
1352
1391
|
return null;
|
|
1353
1392
|
};
|
|
1354
|
-
var findSeasonFolder = (showPath, season) => {
|
|
1355
|
-
if (!
|
|
1393
|
+
var findSeasonFolder = (showPath, season, specialsFolder) => {
|
|
1394
|
+
if (!existsSync10(showPath)) return null;
|
|
1356
1395
|
const folders = readdirSync7(showPath).filter((f) => {
|
|
1357
1396
|
try {
|
|
1358
1397
|
return lstatSync4(resolve8(showPath, f)).isDirectory();
|
|
@@ -1360,6 +1399,10 @@ var findSeasonFolder = (showPath, season) => {
|
|
|
1360
1399
|
return false;
|
|
1361
1400
|
}
|
|
1362
1401
|
});
|
|
1402
|
+
if (season === 0 && specialsFolder) {
|
|
1403
|
+
const existing = folders.find((f) => f.toLowerCase() === specialsFolder.toLowerCase());
|
|
1404
|
+
if (existing) return existing;
|
|
1405
|
+
}
|
|
1363
1406
|
return folders.find((f) => {
|
|
1364
1407
|
const match = f.match(/(?:season|s)\s*0*(\d+)/i);
|
|
1365
1408
|
return match && parseInt(match[1]) === season;
|
|
@@ -1388,11 +1431,13 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1388
1431
|
const language = config.language ?? "eng";
|
|
1389
1432
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1390
1433
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
1434
|
+
const specialsFolder = config.specialsFolder ?? "Specials";
|
|
1391
1435
|
const lookupMovie = async (parsed) => {
|
|
1392
1436
|
let tmdbId;
|
|
1393
1437
|
let resolvedTitle = parsed.title;
|
|
1394
1438
|
let resolvedYear = parsed.year;
|
|
1395
1439
|
if (config.tmdbApiKey) {
|
|
1440
|
+
spinner_default.text = `TMDb: ${parsed.title}`;
|
|
1396
1441
|
const results = await searchMovie(parsed.title, parsed.year, config.tmdbApiKey);
|
|
1397
1442
|
if (results.length === 1) {
|
|
1398
1443
|
tmdbId = results[0].id;
|
|
@@ -1421,7 +1466,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1421
1466
|
const edition = detectEdition(entry);
|
|
1422
1467
|
const folderName = formatMovieName(movieFormat, resolvedTitle, resolvedYear, edition);
|
|
1423
1468
|
const destFolder = resolve8(destRoot, folderName);
|
|
1424
|
-
if (
|
|
1469
|
+
if (existsSync10(destFolder)) {
|
|
1425
1470
|
spinner_default.warn(`already exists: ${folderName}`);
|
|
1426
1471
|
return false;
|
|
1427
1472
|
}
|
|
@@ -1440,7 +1485,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1440
1485
|
const destSubtitleName = subtitle && subtitleExt ? `${folderName}.${subtitleExt}` : null;
|
|
1441
1486
|
if (!dryRun) {
|
|
1442
1487
|
if (useHardlink) {
|
|
1443
|
-
|
|
1488
|
+
mkdirSync4(destFolder, { recursive: true });
|
|
1444
1489
|
const destVideoPath = resolve8(destFolder, destVideoName);
|
|
1445
1490
|
let mode;
|
|
1446
1491
|
try {
|
|
@@ -1457,18 +1502,18 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1457
1502
|
} else {
|
|
1458
1503
|
if (isDir) {
|
|
1459
1504
|
const keep = new Set([videoFile, subtitle].filter(Boolean));
|
|
1460
|
-
for (const f of dirFiles.filter((f2) => !keep.has(f2)))
|
|
1461
|
-
|
|
1462
|
-
if (subtitleSourcePath && destSubtitleName)
|
|
1505
|
+
for (const f of dirFiles.filter((f2) => !keep.has(f2))) trashPath(resolve8(entryPath, f), { recursive: true });
|
|
1506
|
+
renameSync4(videoSourcePath, resolve8(entryPath, destVideoName));
|
|
1507
|
+
if (subtitleSourcePath && destSubtitleName) renameSync4(subtitleSourcePath, resolve8(entryPath, destSubtitleName));
|
|
1463
1508
|
moveFolder(entryPath, destFolder);
|
|
1464
1509
|
} else {
|
|
1465
|
-
|
|
1510
|
+
mkdirSync4(destFolder, { recursive: true });
|
|
1466
1511
|
const destVideoPath = resolve8(destFolder, destVideoName);
|
|
1467
1512
|
if (sameDev(videoSourcePath, destRoot)) {
|
|
1468
|
-
|
|
1513
|
+
renameSync4(videoSourcePath, destVideoPath);
|
|
1469
1514
|
} else {
|
|
1470
1515
|
cpSync(videoSourcePath, destVideoPath);
|
|
1471
|
-
|
|
1516
|
+
trashPath(videoSourcePath);
|
|
1472
1517
|
}
|
|
1473
1518
|
}
|
|
1474
1519
|
recordImport(sessionId, entryPath, destFolder, "move", tmdbId, "movie");
|
|
@@ -1485,12 +1530,13 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1485
1530
|
const ignoreSet = new Set(config.ignore ?? []);
|
|
1486
1531
|
const seenIgnored = /* @__PURE__ */ new Set();
|
|
1487
1532
|
for (const source of config.sources) {
|
|
1488
|
-
if (!
|
|
1533
|
+
if (!existsSync10(source)) {
|
|
1489
1534
|
spinner_default.warn(`source not found: ${Color9.white.encoder(source)}`);
|
|
1490
1535
|
continue;
|
|
1491
1536
|
}
|
|
1492
1537
|
spinner_default.text = `scanning ${Color9.white.encoder(source)}`;
|
|
1493
1538
|
for (const { entry, entryPath, isDir } of gatherEntries(source)) {
|
|
1539
|
+
spinner_default.text = `scanning: ${entry}`;
|
|
1494
1540
|
if (ignoreSet.has(entry)) {
|
|
1495
1541
|
seenIgnored.add(entry);
|
|
1496
1542
|
if (isVerbose()) spinner_default.info(`ignored: ${entry}`);
|
|
@@ -1526,7 +1572,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1526
1572
|
}
|
|
1527
1573
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
1528
1574
|
const destPath = resolve8(destRoot, destName);
|
|
1529
|
-
if (
|
|
1575
|
+
if (existsSync10(destPath)) {
|
|
1530
1576
|
spinner_default.warn(`already exists: ${destName}`);
|
|
1531
1577
|
skipped++;
|
|
1532
1578
|
continue;
|
|
@@ -1541,7 +1587,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1541
1587
|
}
|
|
1542
1588
|
if (detectedType === "book") {
|
|
1543
1589
|
const destPath = resolve8(destRoot, entry);
|
|
1544
|
-
if (
|
|
1590
|
+
if (existsSync10(destPath)) {
|
|
1545
1591
|
spinner_default.warn(`already exists: ${entry}`);
|
|
1546
1592
|
skipped++;
|
|
1547
1593
|
continue;
|
|
@@ -1550,12 +1596,12 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1550
1596
|
if (isDir || isBookDir) {
|
|
1551
1597
|
moveFolder(entryPath, destPath);
|
|
1552
1598
|
} else {
|
|
1553
|
-
|
|
1599
|
+
mkdirSync4(destRoot, { recursive: true });
|
|
1554
1600
|
if (sameDev(entryPath, destRoot)) {
|
|
1555
|
-
|
|
1601
|
+
renameSync4(entryPath, destPath);
|
|
1556
1602
|
} else {
|
|
1557
1603
|
cpSync(entryPath, destPath);
|
|
1558
|
-
|
|
1604
|
+
rmSync3(entryPath);
|
|
1559
1605
|
}
|
|
1560
1606
|
}
|
|
1561
1607
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
@@ -1587,6 +1633,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1587
1633
|
let resolvedYear = parsed.year;
|
|
1588
1634
|
if (config.tmdbApiKey) {
|
|
1589
1635
|
if (detectedType === "tv") {
|
|
1636
|
+
spinner_default.text = `TMDb: ${parsed.title}`;
|
|
1590
1637
|
const results = await searchTv(parsed.title, config.tmdbApiKey);
|
|
1591
1638
|
if (results.length === 1) {
|
|
1592
1639
|
tmdbId = results[0].id;
|
|
@@ -1641,7 +1688,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1641
1688
|
continue;
|
|
1642
1689
|
}
|
|
1643
1690
|
}
|
|
1644
|
-
const seasonFolderName = findSeasonFolder(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
1691
|
+
const seasonFolderName = parsed.season === 0 ? findSeasonFolder(showPath, 0, specialsFolder) ?? specialsFolder : findSeasonFolder(showPath, parsed.season) ?? formatSeasonFolder(seasonFormat, parsed.season);
|
|
1645
1692
|
const seasonPath = resolve8(showPath, seasonFolderName);
|
|
1646
1693
|
const videoFile = isDir ? findVideo(entryPath) : entry;
|
|
1647
1694
|
if (!videoFile) {
|
|
@@ -1650,13 +1697,15 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1650
1697
|
continue;
|
|
1651
1698
|
}
|
|
1652
1699
|
const videoExt = videoFile.match(/([^.]+$)/)?.[0];
|
|
1700
|
+
if (tmdbId && config.tmdbApiKey) spinner_default.text = `TMDb: episode name for ${resolvedTitle}`;
|
|
1653
1701
|
const tmdbEpisodeName = tmdbId && config.tmdbApiKey ? await getEpisodeName(tmdbId, parsed.season, parsed.episode ?? 1, config.tmdbApiKey) : null;
|
|
1654
1702
|
const episodeName = formatEpisode(parsed.season, parsed.episode ?? 1, config.format?.episode, false, resolvedTitle, tmdbEpisodeName ?? void 0);
|
|
1655
1703
|
const destVideoName = `${episodeName}.${videoExt}`;
|
|
1656
1704
|
const destVideoPath = resolve8(seasonPath, destVideoName);
|
|
1657
1705
|
const videoSourcePath = isDir ? resolve8(entryPath, videoFile) : entryPath;
|
|
1658
|
-
if (
|
|
1659
|
-
|
|
1706
|
+
if (existsSync10(destVideoPath)) {
|
|
1707
|
+
const isRepack = /\brepack\d*\b|\bproper\b/i.test(entry);
|
|
1708
|
+
let shouldReplace = force || isRepack;
|
|
1660
1709
|
if (!shouldReplace && interactive) {
|
|
1661
1710
|
spinner_default.stop();
|
|
1662
1711
|
const select = new Select2();
|
|
@@ -1674,7 +1723,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1674
1723
|
}
|
|
1675
1724
|
if (!dryRun) {
|
|
1676
1725
|
for (const f of readdirSync7(seasonPath)) {
|
|
1677
|
-
if (f.startsWith(`${episodeName}.`))
|
|
1726
|
+
if (f.startsWith(`${episodeName}.`)) trashPath(resolve8(seasonPath, f));
|
|
1678
1727
|
}
|
|
1679
1728
|
}
|
|
1680
1729
|
}
|
|
@@ -1684,7 +1733,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1684
1733
|
const subtitleSourcePath = subtitle ? resolve8(entryPath, subtitle) : null;
|
|
1685
1734
|
const destSubtitleName = subtitle && subtitleExt ? `${episodeName}.${subtitleExt}` : null;
|
|
1686
1735
|
if (!dryRun) {
|
|
1687
|
-
|
|
1736
|
+
mkdirSync4(seasonPath, { recursive: true });
|
|
1688
1737
|
let mode = "move";
|
|
1689
1738
|
if (useHardlink) {
|
|
1690
1739
|
try {
|
|
@@ -1699,13 +1748,13 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1699
1748
|
if (subtitleSourcePath && destSubtitleName) cpSync(subtitleSourcePath, resolve8(seasonPath, destSubtitleName));
|
|
1700
1749
|
} else {
|
|
1701
1750
|
if (sameDev(videoSourcePath, seasonPath)) {
|
|
1702
|
-
|
|
1751
|
+
renameSync4(videoSourcePath, destVideoPath);
|
|
1703
1752
|
} else {
|
|
1704
1753
|
cpSync(videoSourcePath, destVideoPath);
|
|
1705
|
-
|
|
1754
|
+
trashPath(videoSourcePath);
|
|
1706
1755
|
}
|
|
1707
|
-
if (subtitleSourcePath && destSubtitleName)
|
|
1708
|
-
if (isDir)
|
|
1756
|
+
if (subtitleSourcePath && destSubtitleName) renameSync4(subtitleSourcePath, resolve8(seasonPath, destSubtitleName));
|
|
1757
|
+
if (isDir) trashPath(entryPath, { recursive: true });
|
|
1709
1758
|
}
|
|
1710
1759
|
recordImport(sessionId, entryPath, seasonPath, mode, tmdbId, "tv");
|
|
1711
1760
|
}
|
|
@@ -1770,7 +1819,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, auto, force, interactiv
|
|
|
1770
1819
|
var scan_default = scan;
|
|
1771
1820
|
|
|
1772
1821
|
// src/actions/undo.ts
|
|
1773
|
-
import { existsSync as
|
|
1822
|
+
import { existsSync as existsSync11, renameSync as renameSync5 } from "fs";
|
|
1774
1823
|
import { Color as Color10 } from "termkit";
|
|
1775
1824
|
var undo = async () => {
|
|
1776
1825
|
spinner_default.start();
|
|
@@ -1785,7 +1834,7 @@ var undo = async () => {
|
|
|
1785
1834
|
if (!useImports) {
|
|
1786
1835
|
let undone2 = 0;
|
|
1787
1836
|
for (const record of renameRecords) {
|
|
1788
|
-
|
|
1837
|
+
renameSync5(record.newPath, record.oldPath);
|
|
1789
1838
|
spinner_default.succeed(`${Color10.green.encoder(record.newPath)} \u2192 ${Color10.white.encoder(record.oldPath)}`);
|
|
1790
1839
|
undone2++;
|
|
1791
1840
|
}
|
|
@@ -1807,12 +1856,12 @@ var undo = async () => {
|
|
|
1807
1856
|
skipped++;
|
|
1808
1857
|
continue;
|
|
1809
1858
|
}
|
|
1810
|
-
if (!
|
|
1859
|
+
if (!existsSync11(record.destinationPath)) {
|
|
1811
1860
|
spinner_default.info(`skipped \u2014 destination no longer exists: ${record.destinationPath}`);
|
|
1812
1861
|
skipped++;
|
|
1813
1862
|
continue;
|
|
1814
1863
|
}
|
|
1815
|
-
|
|
1864
|
+
renameSync5(record.destinationPath, record.sourcePath);
|
|
1816
1865
|
spinner_default.succeed(`${Color10.green.encoder(record.destinationPath)} \u2192 ${Color10.white.encoder(record.sourcePath)}`);
|
|
1817
1866
|
undone++;
|
|
1818
1867
|
}
|
|
@@ -1825,13 +1874,13 @@ var undo_default = undo;
|
|
|
1825
1874
|
|
|
1826
1875
|
// src/actions/watch.ts
|
|
1827
1876
|
import chokidar from "chokidar";
|
|
1828
|
-
import { cpSync as cpSync2, existsSync as
|
|
1829
|
-
import { basename as
|
|
1877
|
+
import { cpSync as cpSync2, existsSync as existsSync12, linkSync as linkSync2, lstatSync as lstatSync5, mkdirSync as mkdirSync5, readdirSync as readdirSync8, renameSync as renameSync6, rmSync as rmSync4, statSync as statSync3 } from "fs";
|
|
1878
|
+
import { basename as basename4, dirname as dirname3, resolve as resolve9 } from "path";
|
|
1830
1879
|
import { Color as Color11 } from "termkit";
|
|
1831
1880
|
var sameDev2 = (a, b) => {
|
|
1832
1881
|
try {
|
|
1833
1882
|
let bExisting = b;
|
|
1834
|
-
while (!
|
|
1883
|
+
while (!existsSync12(bExisting)) bExisting = dirname3(bExisting);
|
|
1835
1884
|
return statSync3(a).dev === statSync3(bExisting).dev;
|
|
1836
1885
|
} catch {
|
|
1837
1886
|
return false;
|
|
@@ -1839,10 +1888,10 @@ var sameDev2 = (a, b) => {
|
|
|
1839
1888
|
};
|
|
1840
1889
|
var moveItem = (src, dest) => {
|
|
1841
1890
|
if (sameDev2(src, dest)) {
|
|
1842
|
-
|
|
1891
|
+
renameSync6(src, dest);
|
|
1843
1892
|
} else {
|
|
1844
1893
|
cpSync2(src, dest, { recursive: true });
|
|
1845
|
-
|
|
1894
|
+
rmSync4(src, { recursive: true, force: true });
|
|
1846
1895
|
}
|
|
1847
1896
|
};
|
|
1848
1897
|
var findVideo2 = (dir) => readdirSync8(dir).find((f) => {
|
|
@@ -1871,7 +1920,7 @@ var expandWatchPath = (p) => {
|
|
|
1871
1920
|
return [p];
|
|
1872
1921
|
}
|
|
1873
1922
|
if (!isDir) return [p];
|
|
1874
|
-
const name =
|
|
1923
|
+
const name = basename4(p);
|
|
1875
1924
|
if (isTvEpisodeName2(name) || /(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name)) return [p];
|
|
1876
1925
|
let children;
|
|
1877
1926
|
try {
|
|
@@ -1930,7 +1979,7 @@ var expandWatchPath = (p) => {
|
|
|
1930
1979
|
return [p];
|
|
1931
1980
|
};
|
|
1932
1981
|
var findSeasonFolder2 = (showPath, season) => {
|
|
1933
|
-
if (!
|
|
1982
|
+
if (!existsSync12(showPath)) return null;
|
|
1934
1983
|
const folders = readdirSync8(showPath).filter((f) => {
|
|
1935
1984
|
try {
|
|
1936
1985
|
return lstatSync5(resolve9(showPath, f)).isDirectory();
|
|
@@ -1946,7 +1995,7 @@ var findSeasonFolder2 = (showPath, season) => {
|
|
|
1946
1995
|
var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
1947
1996
|
const config = getConfig();
|
|
1948
1997
|
const sessionId = (/* @__PURE__ */ new Date()).toISOString();
|
|
1949
|
-
const entry =
|
|
1998
|
+
const entry = basename4(entryPath);
|
|
1950
1999
|
const movieFormat = config.format?.movie ?? DEFAULT_MOVIE_FORMAT;
|
|
1951
2000
|
const seasonFormat = config.format?.season ?? DEFAULT_SEASON_FORMAT;
|
|
1952
2001
|
const isDir = lstatSync5(entryPath).isDirectory();
|
|
@@ -1976,7 +2025,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
1976
2025
|
if (!nameMatch || !id) return;
|
|
1977
2026
|
const destName = `${nameMatch[0]} [${id}]`;
|
|
1978
2027
|
const destPath = resolve9(destRoot, destName);
|
|
1979
|
-
if (
|
|
2028
|
+
if (existsSync12(destPath)) {
|
|
1980
2029
|
spinner_default.warn(`already exists: ${destName}`);
|
|
1981
2030
|
return;
|
|
1982
2031
|
}
|
|
@@ -1987,19 +2036,19 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
1987
2036
|
}
|
|
1988
2037
|
if (detectedType === "book") {
|
|
1989
2038
|
const destPath = resolve9(destRoot, entry);
|
|
1990
|
-
if (
|
|
2039
|
+
if (existsSync12(destPath)) {
|
|
1991
2040
|
spinner_default.warn(`already exists: ${entry}`);
|
|
1992
2041
|
return;
|
|
1993
2042
|
}
|
|
1994
2043
|
if (isDir || isBookDir) {
|
|
1995
2044
|
moveItem(entryPath, destPath);
|
|
1996
2045
|
} else {
|
|
1997
|
-
|
|
2046
|
+
mkdirSync5(destRoot, { recursive: true });
|
|
1998
2047
|
if (sameDev2(entryPath, destRoot)) {
|
|
1999
|
-
|
|
2048
|
+
renameSync6(entryPath, destPath);
|
|
2000
2049
|
} else {
|
|
2001
2050
|
cpSync2(entryPath, destPath);
|
|
2002
|
-
|
|
2051
|
+
rmSync4(entryPath);
|
|
2003
2052
|
}
|
|
2004
2053
|
}
|
|
2005
2054
|
recordImport(sessionId, entryPath, destPath, "move", void 0, "book");
|
|
@@ -2043,7 +2092,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2043
2092
|
const destVideoName2 = `${episodeName}.${videoExt2}`;
|
|
2044
2093
|
const destVideoPath = resolve9(seasonPath, destVideoName2);
|
|
2045
2094
|
const videoSourcePath2 = isDir ? resolve9(entryPath, videoFile2) : entryPath;
|
|
2046
|
-
if (
|
|
2095
|
+
if (existsSync12(destVideoPath)) {
|
|
2047
2096
|
spinner_default.warn(`already exists: ${episodeName}`);
|
|
2048
2097
|
return;
|
|
2049
2098
|
}
|
|
@@ -2052,7 +2101,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2052
2101
|
const subtitleExt2 = subtitle2?.match(/([^.]+$)/)?.[0];
|
|
2053
2102
|
const subtitleSourcePath2 = subtitle2 ? resolve9(entryPath, subtitle2) : null;
|
|
2054
2103
|
const destSubtitleName2 = subtitle2 && subtitleExt2 ? `${episodeName}.${subtitleExt2}` : null;
|
|
2055
|
-
|
|
2104
|
+
mkdirSync5(seasonPath, { recursive: true });
|
|
2056
2105
|
let mode = "move";
|
|
2057
2106
|
if (useHardlink) {
|
|
2058
2107
|
try {
|
|
@@ -2067,13 +2116,13 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2067
2116
|
if (subtitleSourcePath2 && destSubtitleName2) cpSync2(subtitleSourcePath2, resolve9(seasonPath, destSubtitleName2));
|
|
2068
2117
|
} else {
|
|
2069
2118
|
if (sameDev2(videoSourcePath2, seasonPath)) {
|
|
2070
|
-
|
|
2119
|
+
renameSync6(videoSourcePath2, destVideoPath);
|
|
2071
2120
|
} else {
|
|
2072
2121
|
cpSync2(videoSourcePath2, destVideoPath);
|
|
2073
|
-
|
|
2122
|
+
rmSync4(videoSourcePath2);
|
|
2074
2123
|
}
|
|
2075
|
-
if (subtitleSourcePath2 && destSubtitleName2)
|
|
2076
|
-
if (isDir)
|
|
2124
|
+
if (subtitleSourcePath2 && destSubtitleName2) renameSync6(subtitleSourcePath2, resolve9(seasonPath, destSubtitleName2));
|
|
2125
|
+
if (isDir) rmSync4(entryPath, { recursive: true, force: true });
|
|
2077
2126
|
}
|
|
2078
2127
|
recordImport(sessionId, entryPath, seasonPath, mode, void 0, "tv");
|
|
2079
2128
|
spinner_default.succeed(`imported ${Color11.green.encoder(`${showFolderName} / ${seasonFolderName} / ${episodeName}`)}`);
|
|
@@ -2082,7 +2131,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2082
2131
|
const edition = detectEdition(entry);
|
|
2083
2132
|
const folderName = formatMovieName(movieFormat, parsed.title, parsed.year, edition);
|
|
2084
2133
|
const destFolder = resolve9(destRoot, folderName);
|
|
2085
|
-
if (
|
|
2134
|
+
if (existsSync12(destFolder)) {
|
|
2086
2135
|
spinner_default.warn(`already exists: ${folderName}`);
|
|
2087
2136
|
return;
|
|
2088
2137
|
}
|
|
@@ -2100,7 +2149,7 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2100
2149
|
const subtitleSourcePath = subtitle ? resolve9(entryPath, subtitle) : null;
|
|
2101
2150
|
const destSubtitleName = subtitle && subtitleExt ? `${folderName}.${subtitleExt}` : null;
|
|
2102
2151
|
if (useHardlink) {
|
|
2103
|
-
|
|
2152
|
+
mkdirSync5(destFolder, { recursive: true });
|
|
2104
2153
|
const destVideoPath = resolve9(destFolder, destVideoName);
|
|
2105
2154
|
let mode;
|
|
2106
2155
|
try {
|
|
@@ -2117,18 +2166,18 @@ var processItem = async (entryPath, useHardlink, language, auto) => {
|
|
|
2117
2166
|
} else {
|
|
2118
2167
|
if (isDir) {
|
|
2119
2168
|
const keep = new Set([videoFile, subtitle].filter(Boolean));
|
|
2120
|
-
for (const f of dirFiles.filter((f2) => !keep.has(f2)))
|
|
2121
|
-
|
|
2122
|
-
if (subtitleSourcePath && destSubtitleName)
|
|
2169
|
+
for (const f of dirFiles.filter((f2) => !keep.has(f2))) rmSync4(resolve9(entryPath, f), { recursive: true, force: true });
|
|
2170
|
+
renameSync6(videoSourcePath, resolve9(entryPath, destVideoName));
|
|
2171
|
+
if (subtitleSourcePath && destSubtitleName) renameSync6(subtitleSourcePath, resolve9(entryPath, destSubtitleName));
|
|
2123
2172
|
moveItem(entryPath, destFolder);
|
|
2124
2173
|
} else {
|
|
2125
|
-
|
|
2174
|
+
mkdirSync5(destFolder, { recursive: true });
|
|
2126
2175
|
const destVideoPath = resolve9(destFolder, destVideoName);
|
|
2127
2176
|
if (sameDev2(videoSourcePath, destRoot)) {
|
|
2128
|
-
|
|
2177
|
+
renameSync6(videoSourcePath, destVideoPath);
|
|
2129
2178
|
} else {
|
|
2130
2179
|
cpSync2(videoSourcePath, destVideoPath);
|
|
2131
|
-
|
|
2180
|
+
rmSync4(videoSourcePath);
|
|
2132
2181
|
}
|
|
2133
2182
|
}
|
|
2134
2183
|
recordImport(sessionId, entryPath, destFolder, "move", void 0, "movie");
|
package/package.json
CHANGED