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 }
+ }
+ }
+ }
+}