diff options
| author | shu <nvcsadjkojf@outlook.com> | 2026-07-26 18:33:43 +0800 |
|---|---|---|
| committer | shu <nvcsadjkojf@outlook.com> | 2026-07-26 18:33:43 +0800 |
| commit | c1414f940c1fca93df0c266a3e90c9ff1d7e88c7 (patch) | |
| tree | 4d613a365905d12699d71b3bfb2f68d2a7089c1c /tiddlers/files-list-api.tid | |
Initial TiddlyWiki setup
Diffstat (limited to 'tiddlers/files-list-api.tid')
| -rw-r--r-- | tiddlers/files-list-api.tid | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/tiddlers/files-list-api.tid b/tiddlers/files-list-api.tid new file mode 100644 index 0000000..063fddb --- /dev/null +++ b/tiddlers/files-list-api.tid @@ -0,0 +1,132 @@ +title: $:/plugins/local/files-api/get-files.js +type: application/javascript +module-type: route + +/*\ +title: $:/plugins/local/files-api/get-files.js +type: application/javascript +module-type: route + +GET /api/files +\*/ +"use strict"; + +var fs = require("fs"), + path = require("path"); + +exports.methods = ["GET"]; +exports.path = /^\/api\/files\/?$/; + +exports.info = { + priority: 100 +}; + +function encodeFilePath(filename) { + return filename + .split(path.sep) + .map(encodeURIComponent) + .join("/"); +} + +async function scanDirectory(rootDirectory,directory,prefix) { + var entries, + files = []; + + try { + entries = await fs.promises.readdir(directory,{ + withFileTypes: true + }); + } catch(error) { + if(error.code === "ENOENT") { + return []; + } + throw error; + } + + for(var index = 0; index < entries.length; index++) { + var entry = entries[index]; + + // 不公开隐藏文件。 + if(entry.name.charAt(0) === ".") { + continue; + } + + var absolutePath = path.join(directory,entry.name); + + // 忽略符号链接,避免扫描到 files/ 目录之外。 + if(entry.isDirectory()) { + var childFiles = await scanDirectory( + rootDirectory, + absolutePath, + path.join(prefix,entry.name) + ); + files.push.apply(files,childFiles); + continue; + } + + if(!entry.isFile()) { + continue; + } + + var relativePath = path.join(prefix,entry.name), + extension = path.extname(entry.name).toLowerCase(), + extensionInfo = $tw.config.fileExtensionInfo[extension], + stats; + + try { + stats = await fs.promises.stat(absolutePath); + } catch(error) { + // 文件可能在扫描过程中被删除。 + continue; + } + + files.push({ + name: entry.name, + path: relativePath.split(path.sep).join("/"), + url: (prefix === "" ? "" : "") + + encodeFilePath(relativePath), + type: extensionInfo ? + extensionInfo.type : + "application/octet-stream", + size: stats.size, + modified: stats.mtime.toISOString() + }); + } + + return files; +} + +exports.handler = function(request,response,state) { + var rootDirectory = path.resolve(state.boot.wikiPath,"files"), + pathPrefix = state.pathPrefix || ""; + + scanDirectory(rootDirectory,rootDirectory,"") + .then(function(files) { + files.sort(function(left,right) { + return left.path.localeCompare(right.path); + }); + + files.forEach(function(file) { + file.url = pathPrefix + "/files/" + file.url; + }); + + state.sendResponse( + 200, + {"Content-Type": "application/json; charset=utf-8"}, + JSON.stringify(files), + "utf8" + ); + }) + .catch(function(error) { + console.error("Unable to list files directory:",error); + + state.sendResponse( + 500, + {"Content-Type": "application/json; charset=utf-8"}, + JSON.stringify({ + error: "Unable to list files directory" + }), + "utf8" + ); + }); +};
\ No newline at end of file |
