From f6d44b7ee51fefca46a179f30bc8c1ccc5a09bcf Mon Sep 17 00:00:00 2001 From: myl7 Date: Tue, 23 Nov 2021 02:13:11 +0800 Subject: [PATCH] add folder download utils --- components/FileListing.tsx | 16 +++++++++++- utils/tools.ts | 52 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+), 1 deletion(-) diff --git a/components/FileListing.tsx b/components/FileListing.tsx index 59c10a7..9a31230 100644 --- a/components/FileListing.tsx +++ b/components/FileListing.tsx @@ -12,7 +12,7 @@ import dynamic from 'next/dynamic' import { getExtension, getFileIcon, hasKey } from '../utils/getFileIcon' import { extensions, preview } from '../utils/getPreviewType' -import { getBaseUrl, downloadMultipleFiles, useProtectedSWRInfinite } from '../utils/tools' +import { getBaseUrl, treeList, downloadMultipleFiles, useProtectedSWRInfinite } from '../utils/tools' import { VideoPreview } from './previews/VideoPreview' import { AudioPreview } from './previews/AudioPreview' @@ -285,6 +285,13 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) = } } + // Folder recursive download + const handleFolderDownload = (path: string) => async () => { + for await (const { meta: c, path: p } of treeList(path)) { + console.log(p, c) + } + } + return (
@@ -400,6 +407,13 @@ const FileListing: FunctionComponent<{ query?: ParsedUrlQuery }> = ({ query }) = > + + +
) : (
diff --git a/utils/tools.ts b/utils/tools.ts index b97de21..a2fbfbc 100644 --- a/utils/tools.ts +++ b/utils/tools.ts @@ -156,3 +156,55 @@ export const downloadMultipleFiles = async (files: { name: string; url: string } window.URL.revokeObjectURL(bUrl) el.remove() } + +// One-shot recursive tree-like listing for the folder. +// Due to react hook limit, we cannot reuse SWR utils for recursive listing. +export async function* treeList(path: string) { + const hashedToken = getStoredToken(path) + const root = new PathNode(path) + const loader = async (path: string) => { + const data: any = await fetcher(`/api?path=${path}`, hashedToken ?? undefined) + if (data && data.folder) { + console.log(data.folder) + const children = data.folder.value.map(c => { + const p = `${path === '/' ? '' : path}/${encodeURIComponent(c.name)}` + return c.folder ? new PathNode(p) : new PathNode(p, false, c) + }) + return { children } + } else { + throw new Error('Path is not folder') + } + } + for await (const { meta: c, path: p } of root.dfs(loader)) { + if (c) { + yield { meta: c, path: p } + } + } +} + +// Traverse helper +class PathNode { + private _path: string + private _meta: any + private _isFolder: boolean + + constructor(path: string, isFolder?: boolean, meta?: any) { + this._path = path + this._meta = meta + this._isFolder = isFolder ?? true + } + + async* dfs(loader: (path: string) => Promise<{ meta?: any, children: PathNode[] }>) { + const ancestors = [this as PathNode] + while (ancestors.length > 0) { + const next = ancestors.pop()! + if (next._isFolder) { + const { meta, children } = await loader(next._path) + ancestors.push(...children) + yield { path: next._path, meta: meta } + } else { + yield { path: next._path, meta: next._meta } + } + } + } +}