mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-31 02:17:01 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			105 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			105 lines
		
	
	
		
			4.4 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
| "use strict";
 | |
| /* IMPORT */
 | |
| const fs = require("fs");
 | |
| const path = require("path");
 | |
| const promise_concurrency_limiter_1 = require("./promise-concurrency-limiter");
 | |
| /* HELPERS */
 | |
| const limiter = new promise_concurrency_limiter_1.default({ concurrency: 500 });
 | |
| /* TINY READDIR */
 | |
| const readdir = (rootPath, options) => {
 | |
|     var _a, _b, _c, _d;
 | |
|     const followSymlinks = (_a = options === null || options === void 0 ? void 0 : options.followSymlinks) !== null && _a !== void 0 ? _a : false, maxDepth = (_b = options === null || options === void 0 ? void 0 : options.depth) !== null && _b !== void 0 ? _b : Infinity, isIgnored = (_c = options === null || options === void 0 ? void 0 : options.ignore) !== null && _c !== void 0 ? _c : (() => false), signal = (_d = options === null || options === void 0 ? void 0 : options.signal) !== null && _d !== void 0 ? _d : { aborted: false }, directories = [], files = [], symlinks = [], map = {}, resultEmpty = { directories: [], files: [], symlinks: [], map: {} }, result = { directories, files, symlinks, map };
 | |
|     const handleDirectory = (dirmap, subPath, depth) => {
 | |
|         dirmap.directories.push(subPath);
 | |
|         directories.push(subPath);
 | |
|         if (depth >= maxDepth)
 | |
|             return;
 | |
| 
 | |
|         // if depth > 1 and the limiter is full, then we cannot queue this function or the current promise will never return
 | |
|         if (depth > 1 && limiter.count >= limiter.concurrency) return populateResultFromPath(subPath, depth + 1)
 | |
| 
 | |
|         return limiter.add(() => populateResultFromPath(subPath, depth + 1));
 | |
|     };
 | |
|     const handleFile = (dirmap, subPath) => {
 | |
|         dirmap.files.push(subPath);
 | |
|         files.push(subPath);
 | |
|     };
 | |
|     const handleSymlink = (dirmap, subPath, depth) => {
 | |
|         dirmap.symlinks.push(subPath);
 | |
|         symlinks.push(subPath);
 | |
|         if (!followSymlinks)
 | |
|             return;
 | |
|         if (depth >= maxDepth)
 | |
|             return;
 | |
|         return limiter.add(() => populateResultFromSymlink(subPath, depth + 1));
 | |
|     };
 | |
|     const handleStat = (dirmap, rootPath, stat, depth) => {
 | |
|         if (signal.aborted)
 | |
|             return;
 | |
|         if (isIgnored(rootPath))
 | |
|             return;
 | |
|         if (stat.isDirectory()) {
 | |
|             return handleDirectory(dirmap, rootPath, depth);
 | |
|         }
 | |
|         else if (stat.isFile()) {
 | |
|             return handleFile(dirmap, rootPath);
 | |
|         }
 | |
|         else if (stat.isSymbolicLink()) {
 | |
|             return handleSymlink(dirmap, rootPath, depth);
 | |
|         }
 | |
|     };
 | |
|     const handleDirent = (dirmap, rootPath, dirent, depth) => {
 | |
|         if (signal.aborted)
 | |
|             return;
 | |
|         const subPath = `${rootPath}${path.sep}${dirent.name}`;
 | |
|         if (isIgnored(subPath))
 | |
|             return;
 | |
|         if (dirent.isDirectory()) {
 | |
|             return handleDirectory(dirmap, subPath, depth);
 | |
|         }
 | |
|         else if (dirent.isFile()) {
 | |
|             return handleFile(dirmap, subPath);
 | |
|         }
 | |
|         else if (dirent.isSymbolicLink()) {
 | |
|             return handleSymlink(dirmap, subPath, depth);
 | |
|         }
 | |
|     };
 | |
|     const handleDirents = (dirmap, rootPath, dirents, depth) => {
 | |
|         return Promise.all(dirents.map((dirent) => {
 | |
|             return handleDirent(dirmap, rootPath, dirent, depth);
 | |
|         }));
 | |
|     };
 | |
|     const populateResultFromPath = async (rootPath, depth) => {
 | |
|         if (signal.aborted)
 | |
|             return;
 | |
|         if (depth > maxDepth)
 | |
|             return;
 | |
|         const dirents = await fs.promises.readdir(rootPath, { withFileTypes: true }).catch(() => []);
 | |
|         if (signal.aborted)
 | |
|             return;
 | |
|         const dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
 | |
|         if (!dirents.length)
 | |
|             return;
 | |
|         await handleDirents(dirmap, rootPath, dirents, depth);
 | |
|     };
 | |
|     const populateResultFromSymlink = async (rootPath, depth) => {
 | |
|         try {
 | |
|             const realPath = await fs.promises.realpath(rootPath), stat = await fs.promises.stat(realPath), dirmap = map[rootPath] = { directories: [], files: [], symlinks: [] };
 | |
|             await handleStat(dirmap, realPath, stat, depth);
 | |
|         }
 | |
|         catch (_a) { }
 | |
|     };
 | |
|     const getResult = async (rootPath, depth = 1) => {
 | |
|         rootPath = path.normalize(rootPath);
 | |
|         await populateResultFromPath(rootPath, depth);
 | |
|         if (signal.aborted)
 | |
|             return resultEmpty;
 | |
|         return result;
 | |
|     };
 | |
|     return getResult(rootPath);
 | |
| };
 | |
| /* EXPORT */
 | |
| module.exports = readdir;
 | |
| module.exports.default = readdir;
 | |
| Object.defineProperty(module.exports, "__esModule", { value: true });
 |