reelsort 0.2.1 → 0.2.2
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 +176 -17
- package/dist/index.js +175 -16
- package/dist/index.mjs +175 -16
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1441,10 +1441,99 @@ var findVideo = (dir) => (0, import_fs13.readdirSync)(dir).find((f) => {
|
|
|
1441
1441
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1442
1442
|
return ext && videoExtensions_default.includes(ext);
|
|
1443
1443
|
}) ?? null;
|
|
1444
|
-
var containsBook = (dir) => (0, import_fs13.readdirSync)(dir).some((f) => {
|
|
1444
|
+
var containsBook = (dir, depth = 2) => (0, import_fs13.readdirSync)(dir).some((f) => {
|
|
1445
1445
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1446
|
-
|
|
1446
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1447
|
+
if (depth > 1) {
|
|
1448
|
+
try {
|
|
1449
|
+
const sub = (0, import_path14.resolve)(dir, f);
|
|
1450
|
+
if ((0, import_fs13.lstatSync)(sub).isDirectory()) return containsBook(sub, depth - 1);
|
|
1451
|
+
} catch {
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
return false;
|
|
1447
1455
|
});
|
|
1456
|
+
var isTvEpisodeName = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1457
|
+
var isSeasonDirName = (name) => !isTvEpisodeName(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1458
|
+
var gatherEntries = (source) => {
|
|
1459
|
+
const result = [];
|
|
1460
|
+
for (const name of (0, import_fs13.readdirSync)(source)) {
|
|
1461
|
+
const fullPath = (0, import_path14.resolve)(source, name);
|
|
1462
|
+
let isDir;
|
|
1463
|
+
try {
|
|
1464
|
+
isDir = (0, import_fs13.lstatSync)(fullPath).isDirectory();
|
|
1465
|
+
} catch {
|
|
1466
|
+
continue;
|
|
1467
|
+
}
|
|
1468
|
+
const ext = name.match(/([^.]+$)/)?.[0];
|
|
1469
|
+
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1470
|
+
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1471
|
+
if (!isDir && !isVideo && !isBook) continue;
|
|
1472
|
+
if (!isDir) {
|
|
1473
|
+
result.push({ entry: name, entryPath: fullPath, isDir: false });
|
|
1474
|
+
continue;
|
|
1475
|
+
}
|
|
1476
|
+
if (/(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name) || isTvEpisodeName(name)) {
|
|
1477
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1478
|
+
continue;
|
|
1479
|
+
}
|
|
1480
|
+
let children;
|
|
1481
|
+
try {
|
|
1482
|
+
children = (0, import_fs13.readdirSync)(fullPath);
|
|
1483
|
+
} catch {
|
|
1484
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1485
|
+
continue;
|
|
1486
|
+
}
|
|
1487
|
+
if (children.some((c) => isTvEpisodeName(c))) {
|
|
1488
|
+
for (const child of children) {
|
|
1489
|
+
const childPath = (0, import_path14.resolve)(fullPath, child);
|
|
1490
|
+
let childIsDir;
|
|
1491
|
+
try {
|
|
1492
|
+
childIsDir = (0, import_fs13.lstatSync)(childPath).isDirectory();
|
|
1493
|
+
} catch {
|
|
1494
|
+
continue;
|
|
1495
|
+
}
|
|
1496
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1497
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1498
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1499
|
+
}
|
|
1500
|
+
continue;
|
|
1501
|
+
}
|
|
1502
|
+
const seasonDirs = children.filter((c) => {
|
|
1503
|
+
try {
|
|
1504
|
+
return isSeasonDirName(c) && (0, import_fs13.lstatSync)((0, import_path14.resolve)(fullPath, c)).isDirectory();
|
|
1505
|
+
} catch {
|
|
1506
|
+
return false;
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
if (seasonDirs.length > 0) {
|
|
1510
|
+
for (const seasonDir of seasonDirs) {
|
|
1511
|
+
const seasonPath = (0, import_path14.resolve)(fullPath, seasonDir);
|
|
1512
|
+
let seasonChildren;
|
|
1513
|
+
try {
|
|
1514
|
+
seasonChildren = (0, import_fs13.readdirSync)(seasonPath);
|
|
1515
|
+
} catch {
|
|
1516
|
+
continue;
|
|
1517
|
+
}
|
|
1518
|
+
for (const child of seasonChildren) {
|
|
1519
|
+
const childPath = (0, import_path14.resolve)(seasonPath, child);
|
|
1520
|
+
let childIsDir;
|
|
1521
|
+
try {
|
|
1522
|
+
childIsDir = (0, import_fs13.lstatSync)(childPath).isDirectory();
|
|
1523
|
+
} catch {
|
|
1524
|
+
continue;
|
|
1525
|
+
}
|
|
1526
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1527
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1528
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1529
|
+
}
|
|
1530
|
+
}
|
|
1531
|
+
continue;
|
|
1532
|
+
}
|
|
1533
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1534
|
+
}
|
|
1535
|
+
return result;
|
|
1536
|
+
};
|
|
1448
1537
|
var findSeasonFolder = (showPath, season) => {
|
|
1449
1538
|
if (!(0, import_fs13.existsSync)(showPath)) return null;
|
|
1450
1539
|
const folders = (0, import_fs13.readdirSync)(showPath).filter((f) => {
|
|
@@ -1573,24 +1662,16 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1573
1662
|
continue;
|
|
1574
1663
|
}
|
|
1575
1664
|
spinner_default.text = `scanning ${import_termkit14.Color.white.encoder(source)}`;
|
|
1576
|
-
for (const entry of (
|
|
1577
|
-
const entryPath = (0, import_path14.resolve)(source, entry);
|
|
1578
|
-
const isDir = (0, import_fs13.lstatSync)(entryPath).isDirectory();
|
|
1665
|
+
for (const { entry, entryPath, isDir } of gatherEntries(source)) {
|
|
1579
1666
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
1580
|
-
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1581
1667
|
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1582
1668
|
const isBookDir = isDir && containsBook(entryPath);
|
|
1583
|
-
if (!isDir && !isVideo && !isBook) {
|
|
1584
|
-
if (verbose) spinner_default.info(`skipped ${entry}`);
|
|
1585
|
-
skipped++;
|
|
1586
|
-
continue;
|
|
1587
|
-
}
|
|
1588
1669
|
let detectedType;
|
|
1589
1670
|
if (type) {
|
|
1590
1671
|
detectedType = type;
|
|
1591
1672
|
} else if (isBook || isBookDir) {
|
|
1592
1673
|
detectedType = "book";
|
|
1593
|
-
} else if (isDir &&
|
|
1674
|
+
} else if (isDir && /^[A-Z]{4}\d{5}/i.test(entry)) {
|
|
1594
1675
|
detectedType = "ps3";
|
|
1595
1676
|
} else if (/S\d{2,3}E\d{2,3}/i.test(entry) || /\d+x\d{2,3}/i.test(entry)) {
|
|
1596
1677
|
detectedType = "tv";
|
|
@@ -1830,7 +1911,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1830
1911
|
}
|
|
1831
1912
|
}
|
|
1832
1913
|
}
|
|
1833
|
-
spinner_default.succeed(
|
|
1914
|
+
spinner_default.succeed(`${dryRun ? "would import" : "imported"} ${imported} items`);
|
|
1834
1915
|
if (skipped) spinner_default.info(`skipped ${skipped} items`);
|
|
1835
1916
|
spinner_default.stop();
|
|
1836
1917
|
};
|
|
@@ -1999,10 +2080,86 @@ var findVideo2 = (dir) => (0, import_fs17.readdirSync)(dir).find((f) => {
|
|
|
1999
2080
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
2000
2081
|
return ext && videoExtensions_default.includes(ext);
|
|
2001
2082
|
}) ?? null;
|
|
2002
|
-
var containsBook2 = (dir) => (0, import_fs17.readdirSync)(dir).some((f) => {
|
|
2083
|
+
var containsBook2 = (dir, depth = 2) => (0, import_fs17.readdirSync)(dir).some((f) => {
|
|
2003
2084
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
2004
|
-
|
|
2085
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
2086
|
+
if (depth > 1) {
|
|
2087
|
+
try {
|
|
2088
|
+
const sub = (0, import_path16.resolve)(dir, f);
|
|
2089
|
+
if ((0, import_fs17.lstatSync)(sub).isDirectory()) return containsBook2(sub, depth - 1);
|
|
2090
|
+
} catch {
|
|
2091
|
+
}
|
|
2092
|
+
}
|
|
2093
|
+
return false;
|
|
2005
2094
|
});
|
|
2095
|
+
var isTvEpisodeName2 = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
2096
|
+
var isSeasonDirName2 = (name) => !isTvEpisodeName2(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
2097
|
+
var expandWatchPath = (p) => {
|
|
2098
|
+
let isDir;
|
|
2099
|
+
try {
|
|
2100
|
+
isDir = (0, import_fs17.lstatSync)(p).isDirectory();
|
|
2101
|
+
} catch {
|
|
2102
|
+
return [p];
|
|
2103
|
+
}
|
|
2104
|
+
if (!isDir) return [p];
|
|
2105
|
+
const name = (0, import_path16.basename)(p);
|
|
2106
|
+
if (isTvEpisodeName2(name) || /(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name)) return [p];
|
|
2107
|
+
let children;
|
|
2108
|
+
try {
|
|
2109
|
+
children = (0, import_fs17.readdirSync)(p);
|
|
2110
|
+
} catch {
|
|
2111
|
+
return [p];
|
|
2112
|
+
}
|
|
2113
|
+
if (children.some((c) => isTvEpisodeName2(c))) {
|
|
2114
|
+
const entries = [];
|
|
2115
|
+
for (const child of children) {
|
|
2116
|
+
const cp = (0, import_path16.resolve)(p, child);
|
|
2117
|
+
let cd;
|
|
2118
|
+
try {
|
|
2119
|
+
cd = (0, import_fs17.lstatSync)(cp).isDirectory();
|
|
2120
|
+
} catch {
|
|
2121
|
+
continue;
|
|
2122
|
+
}
|
|
2123
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
2124
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
2125
|
+
entries.push(cp);
|
|
2126
|
+
}
|
|
2127
|
+
return entries.length > 0 ? entries : [p];
|
|
2128
|
+
}
|
|
2129
|
+
const seasonDirs = children.filter((c) => {
|
|
2130
|
+
try {
|
|
2131
|
+
return isSeasonDirName2(c) && (0, import_fs17.lstatSync)((0, import_path16.resolve)(p, c)).isDirectory();
|
|
2132
|
+
} catch {
|
|
2133
|
+
return false;
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
if (seasonDirs.length > 0) {
|
|
2137
|
+
const entries = [];
|
|
2138
|
+
for (const sd of seasonDirs) {
|
|
2139
|
+
const sp = (0, import_path16.resolve)(p, sd);
|
|
2140
|
+
let sc;
|
|
2141
|
+
try {
|
|
2142
|
+
sc = (0, import_fs17.readdirSync)(sp);
|
|
2143
|
+
} catch {
|
|
2144
|
+
continue;
|
|
2145
|
+
}
|
|
2146
|
+
for (const child of sc) {
|
|
2147
|
+
const cp = (0, import_path16.resolve)(sp, child);
|
|
2148
|
+
let cd;
|
|
2149
|
+
try {
|
|
2150
|
+
cd = (0, import_fs17.lstatSync)(cp).isDirectory();
|
|
2151
|
+
} catch {
|
|
2152
|
+
continue;
|
|
2153
|
+
}
|
|
2154
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
2155
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
2156
|
+
entries.push(cp);
|
|
2157
|
+
}
|
|
2158
|
+
}
|
|
2159
|
+
return entries.length > 0 ? entries : [p];
|
|
2160
|
+
}
|
|
2161
|
+
return [p];
|
|
2162
|
+
};
|
|
2006
2163
|
var findSeasonFolder2 = (showPath, season) => {
|
|
2007
2164
|
if (!(0, import_fs17.existsSync)(showPath)) return null;
|
|
2008
2165
|
const folders = (0, import_fs17.readdirSync)(showPath).filter((f) => {
|
|
@@ -2222,7 +2379,9 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
|
2222
2379
|
setTimeout(async () => {
|
|
2223
2380
|
pending.delete(path);
|
|
2224
2381
|
try {
|
|
2225
|
-
|
|
2382
|
+
for (const entry of expandWatchPath(path)) {
|
|
2383
|
+
await processItem(entry, hardlink, verbose, language, auto);
|
|
2384
|
+
}
|
|
2226
2385
|
} catch (err) {
|
|
2227
2386
|
spinner_default.fail(`error processing ${path}: ${err.message}`);
|
|
2228
2387
|
}
|
|
@@ -2245,7 +2404,7 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
|
2245
2404
|
var watch_default = watch;
|
|
2246
2405
|
|
|
2247
2406
|
// package.json
|
|
2248
|
-
var version = "0.2.
|
|
2407
|
+
var version = "0.2.2";
|
|
2249
2408
|
|
|
2250
2409
|
// src/program.ts
|
|
2251
2410
|
var toCamel = (s) => s.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
package/dist/index.js
CHANGED
|
@@ -1244,10 +1244,99 @@ var findVideo = (dir) => (0, import_fs10.readdirSync)(dir).find((f) => {
|
|
|
1244
1244
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1245
1245
|
return ext && videoExtensions_default.includes(ext);
|
|
1246
1246
|
}) ?? null;
|
|
1247
|
-
var containsBook = (dir) => (0, import_fs10.readdirSync)(dir).some((f) => {
|
|
1247
|
+
var containsBook = (dir, depth = 2) => (0, import_fs10.readdirSync)(dir).some((f) => {
|
|
1248
1248
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1249
|
-
|
|
1249
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1250
|
+
if (depth > 1) {
|
|
1251
|
+
try {
|
|
1252
|
+
const sub = (0, import_path11.resolve)(dir, f);
|
|
1253
|
+
if ((0, import_fs10.lstatSync)(sub).isDirectory()) return containsBook(sub, depth - 1);
|
|
1254
|
+
} catch {
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1257
|
+
return false;
|
|
1250
1258
|
});
|
|
1259
|
+
var isTvEpisodeName = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1260
|
+
var isSeasonDirName = (name) => !isTvEpisodeName(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1261
|
+
var gatherEntries = (source) => {
|
|
1262
|
+
const result = [];
|
|
1263
|
+
for (const name of (0, import_fs10.readdirSync)(source)) {
|
|
1264
|
+
const fullPath = (0, import_path11.resolve)(source, name);
|
|
1265
|
+
let isDir;
|
|
1266
|
+
try {
|
|
1267
|
+
isDir = (0, import_fs10.lstatSync)(fullPath).isDirectory();
|
|
1268
|
+
} catch {
|
|
1269
|
+
continue;
|
|
1270
|
+
}
|
|
1271
|
+
const ext = name.match(/([^.]+$)/)?.[0];
|
|
1272
|
+
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1273
|
+
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1274
|
+
if (!isDir && !isVideo && !isBook) continue;
|
|
1275
|
+
if (!isDir) {
|
|
1276
|
+
result.push({ entry: name, entryPath: fullPath, isDir: false });
|
|
1277
|
+
continue;
|
|
1278
|
+
}
|
|
1279
|
+
if (/(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name) || isTvEpisodeName(name)) {
|
|
1280
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1281
|
+
continue;
|
|
1282
|
+
}
|
|
1283
|
+
let children;
|
|
1284
|
+
try {
|
|
1285
|
+
children = (0, import_fs10.readdirSync)(fullPath);
|
|
1286
|
+
} catch {
|
|
1287
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1288
|
+
continue;
|
|
1289
|
+
}
|
|
1290
|
+
if (children.some((c) => isTvEpisodeName(c))) {
|
|
1291
|
+
for (const child of children) {
|
|
1292
|
+
const childPath = (0, import_path11.resolve)(fullPath, child);
|
|
1293
|
+
let childIsDir;
|
|
1294
|
+
try {
|
|
1295
|
+
childIsDir = (0, import_fs10.lstatSync)(childPath).isDirectory();
|
|
1296
|
+
} catch {
|
|
1297
|
+
continue;
|
|
1298
|
+
}
|
|
1299
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1300
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1301
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1302
|
+
}
|
|
1303
|
+
continue;
|
|
1304
|
+
}
|
|
1305
|
+
const seasonDirs = children.filter((c) => {
|
|
1306
|
+
try {
|
|
1307
|
+
return isSeasonDirName(c) && (0, import_fs10.lstatSync)((0, import_path11.resolve)(fullPath, c)).isDirectory();
|
|
1308
|
+
} catch {
|
|
1309
|
+
return false;
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
if (seasonDirs.length > 0) {
|
|
1313
|
+
for (const seasonDir of seasonDirs) {
|
|
1314
|
+
const seasonPath = (0, import_path11.resolve)(fullPath, seasonDir);
|
|
1315
|
+
let seasonChildren;
|
|
1316
|
+
try {
|
|
1317
|
+
seasonChildren = (0, import_fs10.readdirSync)(seasonPath);
|
|
1318
|
+
} catch {
|
|
1319
|
+
continue;
|
|
1320
|
+
}
|
|
1321
|
+
for (const child of seasonChildren) {
|
|
1322
|
+
const childPath = (0, import_path11.resolve)(seasonPath, child);
|
|
1323
|
+
let childIsDir;
|
|
1324
|
+
try {
|
|
1325
|
+
childIsDir = (0, import_fs10.lstatSync)(childPath).isDirectory();
|
|
1326
|
+
} catch {
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1330
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1331
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
continue;
|
|
1335
|
+
}
|
|
1336
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1337
|
+
}
|
|
1338
|
+
return result;
|
|
1339
|
+
};
|
|
1251
1340
|
var findSeasonFolder = (showPath, season) => {
|
|
1252
1341
|
if (!(0, import_fs10.existsSync)(showPath)) return null;
|
|
1253
1342
|
const folders = (0, import_fs10.readdirSync)(showPath).filter((f) => {
|
|
@@ -1376,24 +1465,16 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1376
1465
|
continue;
|
|
1377
1466
|
}
|
|
1378
1467
|
spinner_default.text = `scanning ${import_termkit10.Color.white.encoder(source)}`;
|
|
1379
|
-
for (const entry of (
|
|
1380
|
-
const entryPath = (0, import_path11.resolve)(source, entry);
|
|
1381
|
-
const isDir = (0, import_fs10.lstatSync)(entryPath).isDirectory();
|
|
1468
|
+
for (const { entry, entryPath, isDir } of gatherEntries(source)) {
|
|
1382
1469
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
1383
|
-
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1384
1470
|
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1385
1471
|
const isBookDir = isDir && containsBook(entryPath);
|
|
1386
|
-
if (!isDir && !isVideo && !isBook) {
|
|
1387
|
-
if (verbose) spinner_default.info(`skipped ${entry}`);
|
|
1388
|
-
skipped++;
|
|
1389
|
-
continue;
|
|
1390
|
-
}
|
|
1391
1472
|
let detectedType;
|
|
1392
1473
|
if (type) {
|
|
1393
1474
|
detectedType = type;
|
|
1394
1475
|
} else if (isBook || isBookDir) {
|
|
1395
1476
|
detectedType = "book";
|
|
1396
|
-
} else if (isDir &&
|
|
1477
|
+
} else if (isDir && /^[A-Z]{4}\d{5}/i.test(entry)) {
|
|
1397
1478
|
detectedType = "ps3";
|
|
1398
1479
|
} else if (/S\d{2,3}E\d{2,3}/i.test(entry) || /\d+x\d{2,3}/i.test(entry)) {
|
|
1399
1480
|
detectedType = "tv";
|
|
@@ -1633,7 +1714,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1633
1714
|
}
|
|
1634
1715
|
}
|
|
1635
1716
|
}
|
|
1636
|
-
spinner_default.succeed(
|
|
1717
|
+
spinner_default.succeed(`${dryRun ? "would import" : "imported"} ${imported} items`);
|
|
1637
1718
|
if (skipped) spinner_default.info(`skipped ${skipped} items`);
|
|
1638
1719
|
spinner_default.stop();
|
|
1639
1720
|
};
|
|
@@ -1688,10 +1769,86 @@ var findVideo2 = (dir) => (0, import_fs12.readdirSync)(dir).find((f) => {
|
|
|
1688
1769
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1689
1770
|
return ext && videoExtensions_default.includes(ext);
|
|
1690
1771
|
}) ?? null;
|
|
1691
|
-
var containsBook2 = (dir) => (0, import_fs12.readdirSync)(dir).some((f) => {
|
|
1772
|
+
var containsBook2 = (dir, depth = 2) => (0, import_fs12.readdirSync)(dir).some((f) => {
|
|
1692
1773
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1693
|
-
|
|
1774
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1775
|
+
if (depth > 1) {
|
|
1776
|
+
try {
|
|
1777
|
+
const sub = (0, import_path12.resolve)(dir, f);
|
|
1778
|
+
if ((0, import_fs12.lstatSync)(sub).isDirectory()) return containsBook2(sub, depth - 1);
|
|
1779
|
+
} catch {
|
|
1780
|
+
}
|
|
1781
|
+
}
|
|
1782
|
+
return false;
|
|
1694
1783
|
});
|
|
1784
|
+
var isTvEpisodeName2 = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1785
|
+
var isSeasonDirName2 = (name) => !isTvEpisodeName2(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1786
|
+
var expandWatchPath = (p) => {
|
|
1787
|
+
let isDir;
|
|
1788
|
+
try {
|
|
1789
|
+
isDir = (0, import_fs12.lstatSync)(p).isDirectory();
|
|
1790
|
+
} catch {
|
|
1791
|
+
return [p];
|
|
1792
|
+
}
|
|
1793
|
+
if (!isDir) return [p];
|
|
1794
|
+
const name = (0, import_path12.basename)(p);
|
|
1795
|
+
if (isTvEpisodeName2(name) || /(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name)) return [p];
|
|
1796
|
+
let children;
|
|
1797
|
+
try {
|
|
1798
|
+
children = (0, import_fs12.readdirSync)(p);
|
|
1799
|
+
} catch {
|
|
1800
|
+
return [p];
|
|
1801
|
+
}
|
|
1802
|
+
if (children.some((c) => isTvEpisodeName2(c))) {
|
|
1803
|
+
const entries = [];
|
|
1804
|
+
for (const child of children) {
|
|
1805
|
+
const cp = (0, import_path12.resolve)(p, child);
|
|
1806
|
+
let cd;
|
|
1807
|
+
try {
|
|
1808
|
+
cd = (0, import_fs12.lstatSync)(cp).isDirectory();
|
|
1809
|
+
} catch {
|
|
1810
|
+
continue;
|
|
1811
|
+
}
|
|
1812
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
1813
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
1814
|
+
entries.push(cp);
|
|
1815
|
+
}
|
|
1816
|
+
return entries.length > 0 ? entries : [p];
|
|
1817
|
+
}
|
|
1818
|
+
const seasonDirs = children.filter((c) => {
|
|
1819
|
+
try {
|
|
1820
|
+
return isSeasonDirName2(c) && (0, import_fs12.lstatSync)((0, import_path12.resolve)(p, c)).isDirectory();
|
|
1821
|
+
} catch {
|
|
1822
|
+
return false;
|
|
1823
|
+
}
|
|
1824
|
+
});
|
|
1825
|
+
if (seasonDirs.length > 0) {
|
|
1826
|
+
const entries = [];
|
|
1827
|
+
for (const sd of seasonDirs) {
|
|
1828
|
+
const sp = (0, import_path12.resolve)(p, sd);
|
|
1829
|
+
let sc;
|
|
1830
|
+
try {
|
|
1831
|
+
sc = (0, import_fs12.readdirSync)(sp);
|
|
1832
|
+
} catch {
|
|
1833
|
+
continue;
|
|
1834
|
+
}
|
|
1835
|
+
for (const child of sc) {
|
|
1836
|
+
const cp = (0, import_path12.resolve)(sp, child);
|
|
1837
|
+
let cd;
|
|
1838
|
+
try {
|
|
1839
|
+
cd = (0, import_fs12.lstatSync)(cp).isDirectory();
|
|
1840
|
+
} catch {
|
|
1841
|
+
continue;
|
|
1842
|
+
}
|
|
1843
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
1844
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
1845
|
+
entries.push(cp);
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
return entries.length > 0 ? entries : [p];
|
|
1849
|
+
}
|
|
1850
|
+
return [p];
|
|
1851
|
+
};
|
|
1695
1852
|
var findSeasonFolder2 = (showPath, season) => {
|
|
1696
1853
|
if (!(0, import_fs12.existsSync)(showPath)) return null;
|
|
1697
1854
|
const folders = (0, import_fs12.readdirSync)(showPath).filter((f) => {
|
|
@@ -1911,7 +2068,9 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
|
1911
2068
|
setTimeout(async () => {
|
|
1912
2069
|
pending.delete(path);
|
|
1913
2070
|
try {
|
|
1914
|
-
|
|
2071
|
+
for (const entry of expandWatchPath(path)) {
|
|
2072
|
+
await processItem(entry, hardlink, verbose, language, auto);
|
|
2073
|
+
}
|
|
1915
2074
|
} catch (err) {
|
|
1916
2075
|
spinner_default.fail(`error processing ${path}: ${err.message}`);
|
|
1917
2076
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -1168,10 +1168,99 @@ var findVideo = (dir) => readdirSync7(dir).find((f) => {
|
|
|
1168
1168
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1169
1169
|
return ext && videoExtensions_default.includes(ext);
|
|
1170
1170
|
}) ?? null;
|
|
1171
|
-
var containsBook = (dir) => readdirSync7(dir).some((f) => {
|
|
1171
|
+
var containsBook = (dir, depth = 2) => readdirSync7(dir).some((f) => {
|
|
1172
1172
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1173
|
-
|
|
1173
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1174
|
+
if (depth > 1) {
|
|
1175
|
+
try {
|
|
1176
|
+
const sub = resolve8(dir, f);
|
|
1177
|
+
if (lstatSync4(sub).isDirectory()) return containsBook(sub, depth - 1);
|
|
1178
|
+
} catch {
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
return false;
|
|
1174
1182
|
});
|
|
1183
|
+
var isTvEpisodeName = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1184
|
+
var isSeasonDirName = (name) => !isTvEpisodeName(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1185
|
+
var gatherEntries = (source) => {
|
|
1186
|
+
const result = [];
|
|
1187
|
+
for (const name of readdirSync7(source)) {
|
|
1188
|
+
const fullPath = resolve8(source, name);
|
|
1189
|
+
let isDir;
|
|
1190
|
+
try {
|
|
1191
|
+
isDir = lstatSync4(fullPath).isDirectory();
|
|
1192
|
+
} catch {
|
|
1193
|
+
continue;
|
|
1194
|
+
}
|
|
1195
|
+
const ext = name.match(/([^.]+$)/)?.[0];
|
|
1196
|
+
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1197
|
+
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1198
|
+
if (!isDir && !isVideo && !isBook) continue;
|
|
1199
|
+
if (!isDir) {
|
|
1200
|
+
result.push({ entry: name, entryPath: fullPath, isDir: false });
|
|
1201
|
+
continue;
|
|
1202
|
+
}
|
|
1203
|
+
if (/(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name) || isTvEpisodeName(name)) {
|
|
1204
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1205
|
+
continue;
|
|
1206
|
+
}
|
|
1207
|
+
let children;
|
|
1208
|
+
try {
|
|
1209
|
+
children = readdirSync7(fullPath);
|
|
1210
|
+
} catch {
|
|
1211
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1212
|
+
continue;
|
|
1213
|
+
}
|
|
1214
|
+
if (children.some((c) => isTvEpisodeName(c))) {
|
|
1215
|
+
for (const child of children) {
|
|
1216
|
+
const childPath = resolve8(fullPath, child);
|
|
1217
|
+
let childIsDir;
|
|
1218
|
+
try {
|
|
1219
|
+
childIsDir = lstatSync4(childPath).isDirectory();
|
|
1220
|
+
} catch {
|
|
1221
|
+
continue;
|
|
1222
|
+
}
|
|
1223
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1224
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1225
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1226
|
+
}
|
|
1227
|
+
continue;
|
|
1228
|
+
}
|
|
1229
|
+
const seasonDirs = children.filter((c) => {
|
|
1230
|
+
try {
|
|
1231
|
+
return isSeasonDirName(c) && lstatSync4(resolve8(fullPath, c)).isDirectory();
|
|
1232
|
+
} catch {
|
|
1233
|
+
return false;
|
|
1234
|
+
}
|
|
1235
|
+
});
|
|
1236
|
+
if (seasonDirs.length > 0) {
|
|
1237
|
+
for (const seasonDir of seasonDirs) {
|
|
1238
|
+
const seasonPath = resolve8(fullPath, seasonDir);
|
|
1239
|
+
let seasonChildren;
|
|
1240
|
+
try {
|
|
1241
|
+
seasonChildren = readdirSync7(seasonPath);
|
|
1242
|
+
} catch {
|
|
1243
|
+
continue;
|
|
1244
|
+
}
|
|
1245
|
+
for (const child of seasonChildren) {
|
|
1246
|
+
const childPath = resolve8(seasonPath, child);
|
|
1247
|
+
let childIsDir;
|
|
1248
|
+
try {
|
|
1249
|
+
childIsDir = lstatSync4(childPath).isDirectory();
|
|
1250
|
+
} catch {
|
|
1251
|
+
continue;
|
|
1252
|
+
}
|
|
1253
|
+
const childExt = child.match(/([^.]+$)/)?.[0];
|
|
1254
|
+
if (!childIsDir && !(childExt && videoExtensions_default.includes(childExt))) continue;
|
|
1255
|
+
result.push({ entry: child, entryPath: childPath, isDir: childIsDir });
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
continue;
|
|
1259
|
+
}
|
|
1260
|
+
result.push({ entry: name, entryPath: fullPath, isDir: true });
|
|
1261
|
+
}
|
|
1262
|
+
return result;
|
|
1263
|
+
};
|
|
1175
1264
|
var findSeasonFolder = (showPath, season) => {
|
|
1176
1265
|
if (!existsSync9(showPath)) return null;
|
|
1177
1266
|
const folders = readdirSync7(showPath).filter((f) => {
|
|
@@ -1300,24 +1389,16 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1300
1389
|
continue;
|
|
1301
1390
|
}
|
|
1302
1391
|
spinner_default.text = `scanning ${Color9.white.encoder(source)}`;
|
|
1303
|
-
for (const entry of
|
|
1304
|
-
const entryPath = resolve8(source, entry);
|
|
1305
|
-
const isDir = lstatSync4(entryPath).isDirectory();
|
|
1392
|
+
for (const { entry, entryPath, isDir } of gatherEntries(source)) {
|
|
1306
1393
|
const ext = entry.match(/([^.]+$)/)?.[0];
|
|
1307
|
-
const isVideo = !isDir && ext && videoExtensions_default.includes(ext);
|
|
1308
1394
|
const isBook = !isDir && ext && bookExtensions_default.includes(ext);
|
|
1309
1395
|
const isBookDir = isDir && containsBook(entryPath);
|
|
1310
|
-
if (!isDir && !isVideo && !isBook) {
|
|
1311
|
-
if (verbose) spinner_default.info(`skipped ${entry}`);
|
|
1312
|
-
skipped++;
|
|
1313
|
-
continue;
|
|
1314
|
-
}
|
|
1315
1396
|
let detectedType;
|
|
1316
1397
|
if (type) {
|
|
1317
1398
|
detectedType = type;
|
|
1318
1399
|
} else if (isBook || isBookDir) {
|
|
1319
1400
|
detectedType = "book";
|
|
1320
|
-
} else if (isDir &&
|
|
1401
|
+
} else if (isDir && /^[A-Z]{4}\d{5}/i.test(entry)) {
|
|
1321
1402
|
detectedType = "ps3";
|
|
1322
1403
|
} else if (/S\d{2,3}E\d{2,3}/i.test(entry) || /\d+x\d{2,3}/i.test(entry)) {
|
|
1323
1404
|
detectedType = "tv";
|
|
@@ -1557,7 +1638,7 @@ var scan = async ({ type, hardlink: useHardlink, dryRun, verbose, auto, force, i
|
|
|
1557
1638
|
}
|
|
1558
1639
|
}
|
|
1559
1640
|
}
|
|
1560
|
-
spinner_default.succeed(
|
|
1641
|
+
spinner_default.succeed(`${dryRun ? "would import" : "imported"} ${imported} items`);
|
|
1561
1642
|
if (skipped) spinner_default.info(`skipped ${skipped} items`);
|
|
1562
1643
|
spinner_default.stop();
|
|
1563
1644
|
};
|
|
@@ -1612,10 +1693,86 @@ var findVideo2 = (dir) => readdirSync8(dir).find((f) => {
|
|
|
1612
1693
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1613
1694
|
return ext && videoExtensions_default.includes(ext);
|
|
1614
1695
|
}) ?? null;
|
|
1615
|
-
var containsBook2 = (dir) => readdirSync8(dir).some((f) => {
|
|
1696
|
+
var containsBook2 = (dir, depth = 2) => readdirSync8(dir).some((f) => {
|
|
1616
1697
|
const ext = f.match(/([^.]+$)/)?.[0];
|
|
1617
|
-
|
|
1698
|
+
if (ext && bookExtensions_default.includes(ext)) return true;
|
|
1699
|
+
if (depth > 1) {
|
|
1700
|
+
try {
|
|
1701
|
+
const sub = resolve9(dir, f);
|
|
1702
|
+
if (lstatSync5(sub).isDirectory()) return containsBook2(sub, depth - 1);
|
|
1703
|
+
} catch {
|
|
1704
|
+
}
|
|
1705
|
+
}
|
|
1706
|
+
return false;
|
|
1618
1707
|
});
|
|
1708
|
+
var isTvEpisodeName2 = (name) => /S\d{2,3}E\d{2,3}/i.test(name) || /\d+x\d{2,3}/i.test(name);
|
|
1709
|
+
var isSeasonDirName2 = (name) => !isTvEpisodeName2(name) && /(?:^|[.\s_-])(?:season|s)\s*0*\d+(?:[.\s_-]|$)/i.test(name);
|
|
1710
|
+
var expandWatchPath = (p) => {
|
|
1711
|
+
let isDir;
|
|
1712
|
+
try {
|
|
1713
|
+
isDir = lstatSync5(p).isDirectory();
|
|
1714
|
+
} catch {
|
|
1715
|
+
return [p];
|
|
1716
|
+
}
|
|
1717
|
+
if (!isDir) return [p];
|
|
1718
|
+
const name = basename3(p);
|
|
1719
|
+
if (isTvEpisodeName2(name) || /(?<=\[).+?(?=\])/.test(name) || /^[A-Z]{4}\d{5}/i.test(name)) return [p];
|
|
1720
|
+
let children;
|
|
1721
|
+
try {
|
|
1722
|
+
children = readdirSync8(p);
|
|
1723
|
+
} catch {
|
|
1724
|
+
return [p];
|
|
1725
|
+
}
|
|
1726
|
+
if (children.some((c) => isTvEpisodeName2(c))) {
|
|
1727
|
+
const entries = [];
|
|
1728
|
+
for (const child of children) {
|
|
1729
|
+
const cp = resolve9(p, child);
|
|
1730
|
+
let cd;
|
|
1731
|
+
try {
|
|
1732
|
+
cd = lstatSync5(cp).isDirectory();
|
|
1733
|
+
} catch {
|
|
1734
|
+
continue;
|
|
1735
|
+
}
|
|
1736
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
1737
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
1738
|
+
entries.push(cp);
|
|
1739
|
+
}
|
|
1740
|
+
return entries.length > 0 ? entries : [p];
|
|
1741
|
+
}
|
|
1742
|
+
const seasonDirs = children.filter((c) => {
|
|
1743
|
+
try {
|
|
1744
|
+
return isSeasonDirName2(c) && lstatSync5(resolve9(p, c)).isDirectory();
|
|
1745
|
+
} catch {
|
|
1746
|
+
return false;
|
|
1747
|
+
}
|
|
1748
|
+
});
|
|
1749
|
+
if (seasonDirs.length > 0) {
|
|
1750
|
+
const entries = [];
|
|
1751
|
+
for (const sd of seasonDirs) {
|
|
1752
|
+
const sp = resolve9(p, sd);
|
|
1753
|
+
let sc;
|
|
1754
|
+
try {
|
|
1755
|
+
sc = readdirSync8(sp);
|
|
1756
|
+
} catch {
|
|
1757
|
+
continue;
|
|
1758
|
+
}
|
|
1759
|
+
for (const child of sc) {
|
|
1760
|
+
const cp = resolve9(sp, child);
|
|
1761
|
+
let cd;
|
|
1762
|
+
try {
|
|
1763
|
+
cd = lstatSync5(cp).isDirectory();
|
|
1764
|
+
} catch {
|
|
1765
|
+
continue;
|
|
1766
|
+
}
|
|
1767
|
+
const ext = child.match(/([^.]+$)/)?.[0];
|
|
1768
|
+
if (!cd && !(ext && videoExtensions_default.includes(ext))) continue;
|
|
1769
|
+
entries.push(cp);
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
return entries.length > 0 ? entries : [p];
|
|
1773
|
+
}
|
|
1774
|
+
return [p];
|
|
1775
|
+
};
|
|
1619
1776
|
var findSeasonFolder2 = (showPath, season) => {
|
|
1620
1777
|
if (!existsSync10(showPath)) return null;
|
|
1621
1778
|
const folders = readdirSync8(showPath).filter((f) => {
|
|
@@ -1835,7 +1992,9 @@ var watch = async ({ hardlink = false, verbose = false, auto = false }) => {
|
|
|
1835
1992
|
setTimeout(async () => {
|
|
1836
1993
|
pending.delete(path);
|
|
1837
1994
|
try {
|
|
1838
|
-
|
|
1995
|
+
for (const entry of expandWatchPath(path)) {
|
|
1996
|
+
await processItem(entry, hardlink, verbose, language, auto);
|
|
1997
|
+
}
|
|
1839
1998
|
} catch (err) {
|
|
1840
1999
|
spinner_default.fail(`error processing ${path}: ${err.message}`);
|
|
1841
2000
|
}
|
package/package.json
CHANGED