hfsapi 0.1.0__py3-none-any.whl
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.
- hfsapi/__init__.py +21 -0
- hfsapi/client.py +324 -0
- hfsapi/models.py +39 -0
- hfsapi-0.1.0.dist-info/METADATA +53 -0
- hfsapi-0.1.0.dist-info/RECORD +7 -0
- hfsapi-0.1.0.dist-info/WHEEL +5 -0
- hfsapi-0.1.0.dist-info/top_level.txt +1 -0
hfsapi/__init__.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
"""HFS (HTTP File Server) Python API 客户端 - https://github.com/rejetto/hfs"""
|
|
2
|
+
|
|
3
|
+
from hfsapi.client import HFSClient
|
|
4
|
+
from hfsapi.models import (
|
|
5
|
+
DirEntry,
|
|
6
|
+
FileListResponse,
|
|
7
|
+
entry_created,
|
|
8
|
+
entry_modified,
|
|
9
|
+
entry_permissions,
|
|
10
|
+
entry_size,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"HFSClient",
|
|
15
|
+
"DirEntry",
|
|
16
|
+
"FileListResponse",
|
|
17
|
+
"entry_size",
|
|
18
|
+
"entry_created",
|
|
19
|
+
"entry_modified",
|
|
20
|
+
"entry_permissions",
|
|
21
|
+
]
|
hfsapi/client.py
ADDED
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HFS (HTTP File Server) Python API 客户端。
|
|
3
|
+
|
|
4
|
+
基于 https://github.com/rejetto/hfs 的 OpenAPI 与前端行为实现,
|
|
5
|
+
支持登录、文件列表、上传、配置及权限相关操作。
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import io
|
|
11
|
+
from typing import Any, BinaryIO
|
|
12
|
+
from urllib.parse import urlencode
|
|
13
|
+
|
|
14
|
+
import httpx
|
|
15
|
+
|
|
16
|
+
from hfsapi.models import DirEntry, FileListResponse
|
|
17
|
+
|
|
18
|
+
# POST 请求需携带的防 CSRF 头(HFS OpenAPI 要求)
|
|
19
|
+
HFS_ANTI_CSRF_HEADER = "x-hfs-anti-csrf"
|
|
20
|
+
HFS_ANTI_CSRF_VALUE = "1"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class HFSClient:
|
|
24
|
+
"""
|
|
25
|
+
HFS 服务器 API 客户端。
|
|
26
|
+
|
|
27
|
+
认证方式:使用 Basic HTTP 认证或首次请求带 ?login=用户名:密码 建立会话。
|
|
28
|
+
测试示例: base_url="http://127.0.0.1:8280", username="abct", password="abc123"
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
def __init__(
|
|
32
|
+
self,
|
|
33
|
+
base_url: str,
|
|
34
|
+
username: str | None = None,
|
|
35
|
+
password: str | None = None,
|
|
36
|
+
*,
|
|
37
|
+
timeout: float = 30.0,
|
|
38
|
+
verify: bool = True,
|
|
39
|
+
):
|
|
40
|
+
"""
|
|
41
|
+
:param base_url: 服务器根地址,如 http://127.0.0.1:8280(不要带末尾 /data/)
|
|
42
|
+
:param username: 登录用户名,如 abct
|
|
43
|
+
:param password: 登录密码,如 abc123
|
|
44
|
+
:param timeout: 请求超时秒数
|
|
45
|
+
:param verify: 是否验证 HTTPS 证书
|
|
46
|
+
"""
|
|
47
|
+
self.base_url = base_url.rstrip("/")
|
|
48
|
+
self.username = username
|
|
49
|
+
self.password = password
|
|
50
|
+
self.timeout = timeout
|
|
51
|
+
self.verify = verify
|
|
52
|
+
self._api_base = f"{self.base_url}/~/api"
|
|
53
|
+
self._client: httpx.Client | None = None
|
|
54
|
+
|
|
55
|
+
def _get_client(self) -> httpx.Client:
|
|
56
|
+
if self._client is None or self._client.is_closed:
|
|
57
|
+
auth = None
|
|
58
|
+
if self.username is not None and self.password is not None:
|
|
59
|
+
auth = (self.username, self.password)
|
|
60
|
+
self._client = httpx.Client(
|
|
61
|
+
base_url=self.base_url,
|
|
62
|
+
auth=auth,
|
|
63
|
+
timeout=self.timeout,
|
|
64
|
+
verify=self.verify,
|
|
65
|
+
follow_redirects=True,
|
|
66
|
+
)
|
|
67
|
+
return self._client
|
|
68
|
+
|
|
69
|
+
def _post_headers(self) -> dict[str, str]:
|
|
70
|
+
return {HFS_ANTI_CSRF_HEADER: HFS_ANTI_CSRF_VALUE}
|
|
71
|
+
|
|
72
|
+
def close(self) -> None:
|
|
73
|
+
"""关闭底层 HTTP 客户端。"""
|
|
74
|
+
if self._client and not self._client.is_closed:
|
|
75
|
+
self._client.close()
|
|
76
|
+
self._client = None
|
|
77
|
+
|
|
78
|
+
def __enter__(self) -> HFSClient:
|
|
79
|
+
return self
|
|
80
|
+
|
|
81
|
+
def __exit__(self, *args: Any) -> None:
|
|
82
|
+
self.close()
|
|
83
|
+
|
|
84
|
+
# ------------------------- 登录与会话 -------------------------
|
|
85
|
+
|
|
86
|
+
def login(self) -> bool:
|
|
87
|
+
"""
|
|
88
|
+
使用 URL 参数方式建立登录会话(可选)。
|
|
89
|
+
若已使用 Basic 认证构造客户端,则无需单独调用。
|
|
90
|
+
返回是否请求成功(不保证服务端一定接受凭证)。
|
|
91
|
+
"""
|
|
92
|
+
if self.username is None or self.password is None:
|
|
93
|
+
return False
|
|
94
|
+
url = f"{self.base_url}/?login={self.username}:{self.password}"
|
|
95
|
+
try:
|
|
96
|
+
r = self._get_client().get(url)
|
|
97
|
+
return r.is_success
|
|
98
|
+
except Exception:
|
|
99
|
+
return False
|
|
100
|
+
|
|
101
|
+
# ------------------------- 文件列表(对应图片中的「谁可以访问列表」等) -------------------------
|
|
102
|
+
|
|
103
|
+
def get_file_list(
|
|
104
|
+
self,
|
|
105
|
+
uri: str = "/",
|
|
106
|
+
*,
|
|
107
|
+
offset: int | None = None,
|
|
108
|
+
limit: int | None = None,
|
|
109
|
+
search: str | None = None,
|
|
110
|
+
request_c_and_m: bool = False,
|
|
111
|
+
) -> FileListResponse:
|
|
112
|
+
"""
|
|
113
|
+
获取指定目录下的文件/文件夹列表(含权限与元数据)。
|
|
114
|
+
|
|
115
|
+
对应前端「谁可以访问列表」:有权限时才能拿到 list;列表中每项包含:
|
|
116
|
+
- 名称、创建/修改时间、大小
|
|
117
|
+
- 权限缩写 p(r/R/l/L/d 等,仅在与父级不同时返回)
|
|
118
|
+
|
|
119
|
+
:param uri: 目录路径,如 "/" 或 "/data"
|
|
120
|
+
:param offset: 跳过条数
|
|
121
|
+
:param limit: 最多返回条数
|
|
122
|
+
:param search: 搜索关键词(含子目录)
|
|
123
|
+
:param request_c_and_m: 是否同时请求 c(创建)和 m(修改)时间
|
|
124
|
+
:return: 含 can_archive, can_upload, can_delete, can_comment, list 等字段
|
|
125
|
+
"""
|
|
126
|
+
params: dict[str, Any] = {"uri": uri}
|
|
127
|
+
if offset is not None:
|
|
128
|
+
params["offset"] = offset
|
|
129
|
+
if limit is not None:
|
|
130
|
+
params["limit"] = limit
|
|
131
|
+
if search:
|
|
132
|
+
params["search"] = search
|
|
133
|
+
if request_c_and_m:
|
|
134
|
+
params["c"] = "1"
|
|
135
|
+
r = self._get_client().get(f"{self._api_base}/get_file_list", params=params)
|
|
136
|
+
r.raise_for_status()
|
|
137
|
+
return r.json()
|
|
138
|
+
|
|
139
|
+
def list_entries(self, uri: str = "/", **kwargs: Any) -> list[DirEntry]:
|
|
140
|
+
"""便捷方法:只返回 get_file_list 的 list 数组。"""
|
|
141
|
+
data = self.get_file_list(uri, **kwargs)
|
|
142
|
+
return data.get("list", [])
|
|
143
|
+
|
|
144
|
+
# ------------------------- 下载(对应「谁可以下载」) -------------------------
|
|
145
|
+
|
|
146
|
+
def download_file(
|
|
147
|
+
self,
|
|
148
|
+
path: str,
|
|
149
|
+
save_to: str | None = None,
|
|
150
|
+
) -> bytes:
|
|
151
|
+
"""
|
|
152
|
+
下载文件。GET 指定路径,返回内容;若提供 save_to 则写入该路径。
|
|
153
|
+
|
|
154
|
+
:param path: 远程路径,如 "/data/Welcome.md" 或 "share/foo.txt"
|
|
155
|
+
:param save_to: 本地保存路径,若提供则写入文件
|
|
156
|
+
:return: 文件内容(bytes)
|
|
157
|
+
"""
|
|
158
|
+
path = path.strip("/")
|
|
159
|
+
# 使用相对路径,避免带 base_url 的 client 将完整 URL 再拼一次
|
|
160
|
+
url = f"/{path}" if path else "/"
|
|
161
|
+
r = self._get_client().get(url)
|
|
162
|
+
r.raise_for_status()
|
|
163
|
+
content = r.content
|
|
164
|
+
if save_to:
|
|
165
|
+
from pathlib import Path
|
|
166
|
+
|
|
167
|
+
Path(save_to).parent.mkdir(parents=True, exist_ok=True)
|
|
168
|
+
Path(save_to).write_bytes(content)
|
|
169
|
+
return content
|
|
170
|
+
|
|
171
|
+
# ------------------------- 上传(对应「谁可以上传」) -------------------------
|
|
172
|
+
|
|
173
|
+
def upload_file(
|
|
174
|
+
self,
|
|
175
|
+
folder: str,
|
|
176
|
+
file_content: BinaryIO | bytes,
|
|
177
|
+
filename: str | None = None,
|
|
178
|
+
*,
|
|
179
|
+
use_put: bool = False,
|
|
180
|
+
put_params: dict[str, str] | None = None,
|
|
181
|
+
use_session_for_put: bool = False,
|
|
182
|
+
) -> httpx.Response:
|
|
183
|
+
"""
|
|
184
|
+
上传文件到指定目录。
|
|
185
|
+
|
|
186
|
+
:param folder: 目录路径,如 "" 或 "share" 或 "share/sub"
|
|
187
|
+
:param file_content: 文件内容(文件对象或 bytes)
|
|
188
|
+
:param filename: 使用 PUT 时的文件名;POST 时由服务端从 multipart 解析
|
|
189
|
+
:param use_put: True 时用 PUT /{folder}/{filename},否则用 POST /{folder} multipart
|
|
190
|
+
:param put_params: PUT 时附加的 query 参数(与前端一致时可传 resume=0! 等)
|
|
191
|
+
:param use_session_for_put: True 时用仅 session(无 Basic)发 PUT,与浏览器一致,需先 login()
|
|
192
|
+
:return: 响应对象,可检查 .status_code 与 .json()
|
|
193
|
+
"""
|
|
194
|
+
folder = folder.strip("/")
|
|
195
|
+
if use_put:
|
|
196
|
+
if not filename:
|
|
197
|
+
raise ValueError("use_put=True 时必须提供 filename")
|
|
198
|
+
# 使用相对路径,避免带 base_url 的 client 将 URL 重复拼接(与 download_file 一致)
|
|
199
|
+
path = f"{folder}/{filename}".replace("//", "/") if folder else filename
|
|
200
|
+
url = f"/{path}" if path else "/"
|
|
201
|
+
if isinstance(file_content, bytes):
|
|
202
|
+
body = file_content
|
|
203
|
+
else:
|
|
204
|
+
body = file_content.read()
|
|
205
|
+
if put_params:
|
|
206
|
+
url = f"{url}?{urlencode(put_params)}"
|
|
207
|
+
# 与 HFS 前端一致:Referer 为当前目录 URL
|
|
208
|
+
referer = f"{self.base_url}/{folder}/".replace("//", "/") if folder else f"{self.base_url}/"
|
|
209
|
+
headers = {**self._post_headers(), "Referer": referer}
|
|
210
|
+
if use_session_for_put and self.username and self.password:
|
|
211
|
+
session_client = httpx.Client(
|
|
212
|
+
base_url=self.base_url,
|
|
213
|
+
timeout=self.timeout,
|
|
214
|
+
verify=self.verify,
|
|
215
|
+
follow_redirects=True,
|
|
216
|
+
)
|
|
217
|
+
try:
|
|
218
|
+
session_client.get(f"/?login={self.username}:{self.password}")
|
|
219
|
+
if folder:
|
|
220
|
+
session_client.get(f"/{folder}/")
|
|
221
|
+
r = session_client.put(url, content=body, headers=headers)
|
|
222
|
+
# HFS roots:若 host 映射到 root(如 /data),需发 PUT /filename 相对 root
|
|
223
|
+
if r.status_code == 404 and folder:
|
|
224
|
+
url_rel = f"/{filename}?{urlencode(put_params)}" if put_params else f"/{filename}"
|
|
225
|
+
r = session_client.put(url_rel, content=body, headers=headers)
|
|
226
|
+
return r
|
|
227
|
+
finally:
|
|
228
|
+
session_client.close()
|
|
229
|
+
return self._get_client().put(url, content=body, headers=headers)
|
|
230
|
+
# POST multipart:HFS 文档写的是 curl -F upload=@FILE FOLDER/,字段名用 upload
|
|
231
|
+
url = f"{self.base_url}/{folder}".replace("//", "/") if folder else self.base_url
|
|
232
|
+
if isinstance(file_content, bytes):
|
|
233
|
+
file_content = io.BytesIO(file_content)
|
|
234
|
+
files = {"upload": (filename or "file", file_content, "application/octet-stream")}
|
|
235
|
+
return self._get_client().post(
|
|
236
|
+
url,
|
|
237
|
+
files=files,
|
|
238
|
+
headers=self._post_headers(),
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
# ------------------------- 删除(对应「谁可以删除」) -------------------------
|
|
242
|
+
|
|
243
|
+
def delete_file(self, folder: str, filename: str) -> httpx.Response:
|
|
244
|
+
"""
|
|
245
|
+
删除指定目录下的文件。
|
|
246
|
+
|
|
247
|
+
HFS 3:对文件路径发 DELETE 请求(path 即要删除的文件);需当前用户有 can_delete 权限。
|
|
248
|
+
|
|
249
|
+
:param folder: 目录路径,如 "share" 或 "share/sub"
|
|
250
|
+
:param filename: 要删除的文件名(仅文件名,不含路径)
|
|
251
|
+
:return: 响应对象,可检查 .status_code
|
|
252
|
+
"""
|
|
253
|
+
folder = folder.strip("/")
|
|
254
|
+
path = f"{folder}/{filename}".replace("//", "/") if folder else filename
|
|
255
|
+
url = f"/{path}" if path else "/"
|
|
256
|
+
return self._get_client().delete(url)
|
|
257
|
+
|
|
258
|
+
# ------------------------- 配置(权限、VFS、Serve as web-page 等) -------------------------
|
|
259
|
+
|
|
260
|
+
def get_config(
|
|
261
|
+
self,
|
|
262
|
+
only: list[str] | None = None,
|
|
263
|
+
omit: list[str] | None = None,
|
|
264
|
+
) -> dict[str, Any]:
|
|
265
|
+
"""
|
|
266
|
+
获取服务器配置(含 VFS、权限等)。
|
|
267
|
+
|
|
268
|
+
:param only: 只返回这些键
|
|
269
|
+
:param omit: 返回除这些键外的所有键
|
|
270
|
+
"""
|
|
271
|
+
params: dict[str, Any] = {}
|
|
272
|
+
if only is not None:
|
|
273
|
+
params["only"] = only
|
|
274
|
+
if omit is not None:
|
|
275
|
+
params["omit"] = omit
|
|
276
|
+
r = self._get_client().get(f"{self._api_base}/get_config", params=params)
|
|
277
|
+
r.raise_for_status()
|
|
278
|
+
return r.json()
|
|
279
|
+
|
|
280
|
+
def set_config(self, values: dict[str, Any]) -> httpx.Response:
|
|
281
|
+
"""
|
|
282
|
+
设置配置项。可用于修改 VFS 节点权限(can_read, can_see, can_upload 等)
|
|
283
|
+
以及「如果找到 index.html 则作为网页提供」等选项(对应 default 等)。
|
|
284
|
+
|
|
285
|
+
与界面权限对应关系:
|
|
286
|
+
- can_read: 谁可以下载
|
|
287
|
+
- can_archive: 谁可以压缩
|
|
288
|
+
- can_list: 谁可以访问列表
|
|
289
|
+
- can_delete: 谁可以删除
|
|
290
|
+
- can_upload: 谁可以上传
|
|
291
|
+
- can_see: 谁可以查看
|
|
292
|
+
- default: 如 "index.html" 表示该文件夹「作为网页提供」
|
|
293
|
+
|
|
294
|
+
:param values: 配置键值,参见 HFS config.md
|
|
295
|
+
"""
|
|
296
|
+
return self._get_client().post(
|
|
297
|
+
f"{self._api_base}/set_config",
|
|
298
|
+
json={"values": values},
|
|
299
|
+
headers=self._post_headers(),
|
|
300
|
+
)
|
|
301
|
+
|
|
302
|
+
def get_vfs(self) -> Any:
|
|
303
|
+
"""获取当前 VFS 配置(文件/文件夹树及权限)。"""
|
|
304
|
+
return self.get_config(only=["vfs"]).get("vfs", [])
|
|
305
|
+
|
|
306
|
+
# ------------------------- 账户(可选,管理员接口) -------------------------
|
|
307
|
+
|
|
308
|
+
def get_accounts(self) -> list[dict[str, Any]]:
|
|
309
|
+
"""获取账户列表(需管理员权限)。"""
|
|
310
|
+
r = self._get_client().get(f"{self._api_base}/get_accounts")
|
|
311
|
+
r.raise_for_status()
|
|
312
|
+
return r.json().get("list", [])
|
|
313
|
+
|
|
314
|
+
def get_usernames(self) -> list[str]:
|
|
315
|
+
"""获取用户名列表。"""
|
|
316
|
+
r = self._get_client().get(f"{self._api_base}/get_usernames")
|
|
317
|
+
r.raise_for_status()
|
|
318
|
+
return r.json().get("list", [])
|
|
319
|
+
|
|
320
|
+
def get_account(self, username: str) -> dict[str, Any]:
|
|
321
|
+
"""获取单个账户信息。"""
|
|
322
|
+
r = self._get_client().get(f"{self._api_base}/get_account", params={"username": username})
|
|
323
|
+
r.raise_for_status()
|
|
324
|
+
return r.json()
|
hfsapi/models.py
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""
|
|
2
|
+
HFS API 数据模型(与 OpenAPI / 前端一致)。
|
|
3
|
+
|
|
4
|
+
与界面「谁可以下载/压缩/访问列表/删除/上传/查看」对应:
|
|
5
|
+
- 列表项中的 p:权限缩写,仅在与父级不同时返回。
|
|
6
|
+
- r: 不可下载 R: 仅其他凭证可下载
|
|
7
|
+
- l: 不可列目录 L: 仅其他凭证可列目录
|
|
8
|
+
- d: 可删除
|
|
9
|
+
- 修改这些权限需通过 set_config 修改 VFS 节点上的 can_read / can_archive / can_list / can_delete / can_upload / can_see。
|
|
10
|
+
"""
|
|
11
|
+
|
|
12
|
+
from typing import Any
|
|
13
|
+
|
|
14
|
+
# DirEntry:get_file_list 返回的 list 中每一项
|
|
15
|
+
# n=名称, c=创建时间, m=修改时间, s=大小(字节), p=权限缩写, comment=注释
|
|
16
|
+
DirEntry = dict[str, Any]
|
|
17
|
+
|
|
18
|
+
# get_file_list 响应:can_archive, can_upload, can_delete, can_comment, list
|
|
19
|
+
FileListResponse = dict[str, Any]
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def entry_size(entry: DirEntry) -> int:
|
|
23
|
+
"""条目大小(字节),文件夹可为 0 或未提供。"""
|
|
24
|
+
return int(entry.get("s") or 0)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def entry_created(entry: DirEntry) -> str | None:
|
|
28
|
+
"""条目创建时间(ISO 字符串)。"""
|
|
29
|
+
return entry.get("c")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def entry_modified(entry: DirEntry) -> str | None:
|
|
33
|
+
"""条目修改时间(ISO 字符串)。"""
|
|
34
|
+
return entry.get("m")
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def entry_permissions(entry: DirEntry) -> str:
|
|
38
|
+
"""权限字符串,如 'rLd';仅在与父级不同时存在。"""
|
|
39
|
+
return entry.get("p") or ""
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: hfsapi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: HFS (HTTP File Server) Python API 客户端
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: httpx>=0.27.0
|
|
8
|
+
Provides-Extra: dev
|
|
9
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
10
|
+
|
|
11
|
+
# hfsapi
|
|
12
|
+
|
|
13
|
+
[HFS (HTTP File Server)](https://github.com/rejetto/hfs) 的 Python API 客户端,支持登录、文件列表、上传、配置与权限相关操作。
|
|
14
|
+
|
|
15
|
+
## 安装
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv sync
|
|
19
|
+
# 或
|
|
20
|
+
pip install -e .
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## 快速开始
|
|
24
|
+
|
|
25
|
+
```python
|
|
26
|
+
from hfsapi import HFSClient, entry_size, entry_created, entry_modified
|
|
27
|
+
|
|
28
|
+
with HFSClient("http://127.0.0.1:8280", username="abct", password="abc123") as client:
|
|
29
|
+
data = client.get_file_list(uri="/data")
|
|
30
|
+
for e in data.get("list", []):
|
|
31
|
+
print(e["n"], entry_size(e), entry_created(e), entry_modified(e))
|
|
32
|
+
|
|
33
|
+
# 上传
|
|
34
|
+
client.upload_file("data", b"content", filename="hello.txt", use_put=True)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## 核心 API
|
|
38
|
+
|
|
39
|
+
| 方法 / 函数 | 说明 |
|
|
40
|
+
|-------------|------|
|
|
41
|
+
| **HFSClient**(base_url, username, password, timeout) | 客户端;建议用 `with` 或显式 `close()`。 |
|
|
42
|
+
| **login()** | 使用 URL 参数建立会话(与 Basic 二选一或配合使用)。 |
|
|
43
|
+
| **get_file_list**(uri, offset, limit, search, request_c_and_m) | 获取目录列表及当前用户在该目录的权限、条目元数据。 |
|
|
44
|
+
| **list_entries**(uri, ...) | 仅返回 `get_file_list` 的 `list` 数组。 |
|
|
45
|
+
| **upload_file**(folder, file_content, filename, use_put, put_params, use_session_for_put) | 上传文件到指定目录。 |
|
|
46
|
+
| **delete_file**(folder, filename) | 删除指定目录下的文件。 |
|
|
47
|
+
| **get_config**(only, omit) / **set_config**(values) | 读取/写入 HFS 配置;可改 VFS 与权限等。 |
|
|
48
|
+
| **get_vfs()** | 获取当前 VFS 树(含权限结构)。 |
|
|
49
|
+
| **entry_size**(e) / **entry_created**(e) / **entry_modified**(e) / **entry_permissions**(e) | 列表项元数据与权限缩写解析。 |
|
|
50
|
+
|
|
51
|
+
列表响应中:`n` 名称、`s` 大小、`c`/`m` 创建/修改时间;`can_archive`、`can_upload`、`can_delete` 等表示当前用户在该目录的权限。
|
|
52
|
+
|
|
53
|
+
更多说明(权限对应、测试、发布、上传方式与 roots 等)见 **[HELP.md](HELP.md)**。
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
hfsapi/__init__.py,sha256=hTZfQrPh9TzCAcXt9BBUNntzL2JPauKnadUVhnDkEns,422
|
|
2
|
+
hfsapi/client.py,sha256=rpgVGnI35azOY0r4s9hqWdrLFrTWEkrGRuhzD3MCApI,12799
|
|
3
|
+
hfsapi/models.py,sha256=DFGng0mHc0UyUtEwpq5XQX8zL8sTE5qZMVBE3PQi7dM,1353
|
|
4
|
+
hfsapi-0.1.0.dist-info/METADATA,sha256=Bd3g0lbIEjEr-2eIJ98-OK9WIC5jSrAt4bv0fcsDLAE,2206
|
|
5
|
+
hfsapi-0.1.0.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
6
|
+
hfsapi-0.1.0.dist-info/top_level.txt,sha256=W7sHdemBjJ6XhEileCvntDqiAa9kNqV8Lt0drPKDMtk,7
|
|
7
|
+
hfsapi-0.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
hfsapi
|