diff --git a/dnfs/index.html b/dnfs/index.html
index 44262df..3b55581 100644
--- a/dnfs/index.html
+++ b/dnfs/index.html
@@ -9,7 +9,7 @@
-
+
diff --git a/static/fsys.py b/static/fsys.py
index d3f52a0..5048bb3 100644
--- a/static/fsys.py
+++ b/static/fsys.py
@@ -60,6 +60,9 @@ SSL_ENABLED = file_config['ssl'].get('enabled', 'false').lower() == 'true'
SSL_CERT_FILE = file_config['ssl'].get('cert_file', 'cert.pem')
SSL_KEY_FILE = file_config['ssl'].get('key_file', 'key.pem')
+# 视图文件名:根路径与目录访问时固定返回此静态文件,由前端 JS 调用 /api/filelist 拉取数据
+VIEW_FILE = '__view.html'
+
# ==================== 视频文件支持 ====================
VIDEO_MIME_TYPES = {
'.mp4': 'video/mp4', '.webm': 'video/webm', '.ogg': 'video/ogg',
@@ -106,29 +109,30 @@ def get_file_list():
try:
if not FILESYSTEM_ENABLED:
return jsonify({'error': '文件系统未启用'}), 403
-
+
requested_path = request.args.get('path', '')
full_path = safe_path_join(HTML_ROOT_DIR, requested_path)
-
+
if full_path is None:
return jsonify({'error': '无效的路径'}), 403
-
+
if not os.path.exists(full_path) or not os.path.isdir(full_path):
return jsonify({'error': '目录不存在'}), 404
-
+
items = []
for item in os.listdir(full_path):
- if item == '__pycache__':
+ # 过滤系统项目:以双下划线开头的文件和文件夹(如 __pycache__、__view.html、__icons 等)
+ if item.startswith('__'):
continue
-
+
item_path = os.path.join(full_path, item)
item_stat = os.stat(item_path)
is_dir = os.path.isdir(item_path)
-
+
item_rel_path = os.path.join(requested_path, item) if requested_path else item
-
+
file_type = 'dir' if is_dir else ('video' if is_video_file(item) else ('audio' if is_audio_file(item) else 'file'))
-
+
items.append({
'name': item,
'type': file_type,
@@ -137,9 +141,9 @@ def get_file_list():
'size_formatted': format_file_size(item_stat.st_size) if not is_dir else '',
'modified': datetime.datetime.fromtimestamp(item_stat.st_mtime).strftime('%Y-%m-%d %H:%M:%S')
})
-
+
items.sort(key=lambda x: (x['type'] != 'dir', x['name'].lower()))
-
+
return jsonify({
'success': True,
'path': requested_path or '/',
@@ -155,33 +159,33 @@ def stream_video(file_path):
try:
if not FILESYSTEM_ENABLED:
return jsonify({'error': '文件系统未启用'}), 403
-
+
full_path = safe_path_join(HTML_ROOT_DIR, file_path)
if full_path is None or not os.path.exists(full_path) or not os.path.isfile(full_path):
return jsonify({'error': '文件不存在'}), 404
-
+
if not is_video_file(full_path) and not is_audio_file(full_path):
return jsonify({'error': '不支持的文件类型'}), 400
-
+
file_size = os.path.getsize(full_path)
mime_type = get_media_mime_type(full_path)
-
+
range_header = request.headers.get('Range', None)
-
+
if range_header:
byte_range = range_header.replace('bytes=', '').split('-')
start = int(byte_range[0]) if byte_range[0] else 0
end = int(byte_range[1]) if len(byte_range) > 1 and byte_range[1] else file_size - 1
-
+
if start >= file_size:
return jsonify({'error': '请求范围超出文件大小'}), 416
-
+
length = end - start + 1
-
+
with open(full_path, 'rb') as f:
f.seek(start)
data = f.read(length)
-
+
response = Response(data, 206, mimetype=mime_type, direct_passthrough=True)
response.headers.add('Content-Range', f'bytes {start}-{end}/{file_size}')
response.headers.add('Accept-Ranges', 'bytes')
@@ -194,342 +198,38 @@ def stream_video(file_path):
logger.error(f"Video streaming error: {str(e)}")
return jsonify({'error': str(e)}), 500
-# ==================== 极简版HTML页面(使用字符串拼接,避免花括号问题) ====================
-def get_html_template(path, breadcrumb_html):
- """生成HTML页面"""
- return f'''
-
-
-
-
-
文件浏览
-
-
-
-
-
-
-
根目录
- {breadcrumb_html}
-
-
-
-
-
-
-
- 📊 共 0 项
- 📁 0
- 📄 0
- 🎬 0
- 🎵 0
-
-
-
-
-
-
-'''
-
# ==================== 主路由 ====================
-@app.route('/', defaults={'path': ''})
+@app.route('/')
+def serve_view():
+ """根路径固定返回 __view.html 静态文件,由前端 JS 调用 /api/filelist 拉取文件系统信息"""
+ if not FILESYSTEM_ENABLED:
+ return "文件系统未启用", 403
+ view_path = os.path.join(HTML_ROOT_DIR, VIEW_FILE)
+ if not os.path.exists(view_path):
+ return f"视图文件 {VIEW_FILE} 不存在", 500
+ return send_file(view_path, mimetype='text/html')
+
@app.route('/
')
-def serve_file(path=''):
+def serve_file(path):
try:
if not FILESYSTEM_ENABLED:
return "文件系统未启用", 403
-
+
full_path = safe_path_join(HTML_ROOT_DIR, path)
if full_path is None:
return "无效的路径", 403
-
+
if not os.path.exists(full_path):
return "路径不存在", 404
-
+
# 文件处理
if os.path.isfile(full_path):
if request.args.get('download') == 'true':
return send_file(full_path, as_attachment=True, download_name=os.path.basename(full_path))
-
+
if is_video_file(full_path) or is_audio_file(full_path):
return send_file(full_path, mimetype=get_media_mime_type(full_path))
-
+
# 普通文件
with open(full_path, 'rb') as f:
content = f.read()
@@ -541,23 +241,13 @@ def serve_file(path=''):
'.pdf': 'application/pdf', '.svg': 'image/svg+xml', '.ico': 'image/x-icon'
}
return Response(content, mimetype=mime_map.get(ext, 'application/octet-stream'))
-
- # 目录处理 - 生成面包屑
- breadcrumb = ''
- if path:
- parts = path.split('/')
- current = ''
- for i, part in enumerate(parts):
- if i == len(parts) - 1:
- breadcrumb += f'›{part}'
- else:
- current += part + '/'
- breadcrumb += f'›{part}'
-
- # 使用函数生成HTML,避免字符串格式化问题
- html = get_html_template(path, breadcrumb)
- return Response(html, mimetype='text/html')
-
+
+ # 目录处理:返回 __view.html,由前端 JS 根据 URL 路径调用 /api/filelist 拉取文件列表
+ view_path = os.path.join(HTML_ROOT_DIR, VIEW_FILE)
+ if os.path.exists(view_path):
+ return send_file(view_path, mimetype='text/html')
+ return "目录无法浏览", 404
+
except Exception as e:
logger.error(f"Error: {str(e)}")
import traceback
@@ -575,7 +265,7 @@ def health_check():
if __name__ == '__main__':
host = file_config['server']['host']
port = int(file_config['server']['port'])
-
+
print("\n" + "="*50)
print("📁 文件托管服务器 (极简版)")
print("="*50)
@@ -589,3 +279,4 @@ if __name__ == '__main__':
app.run(host=host, port=port, ssl_context=(SSL_CERT_FILE, SSL_KEY_FILE), debug=False)
else:
app.run(host=host, port=port, debug=False)
+
diff --git a/static/public/__view.html b/static/public/__view.html
new file mode 100644
index 0000000..e4bed51
--- /dev/null
+++ b/static/public/__view.html
@@ -0,0 +1,485 @@
+
+
+
+
+
+ 文件浏览
+
+
+
+
+
+
+
+
+
+
+
+
+ 📊 共 0 项
+ 📁 0
+ 📄 0
+ 🎬 0
+ 🎵 0
+
+
+
+
+
+
+
+
+
+
+
diff --git a/static/public/css/qing.css b/static/public/css/qing.css
new file mode 100644
index 0000000..3874be6
--- /dev/null
+++ b/static/public/css/qing.css
@@ -0,0 +1,71 @@
+code {
+ color: red;
+ background-color: rgb(254, 235, 238);
+ padding: 5px;
+ border-radius: 5px;
+}
+pre > code {
+ display: block;
+ color: white;
+ background-color: rgb(96, 96, 96);
+ padding: 5px;
+ border-radius: 5px;
+}
+blockquote {
+ margin-right: 0px;
+ background-color: #cfcfcf;
+}
+
+/* by qing */
+body {
+ min-height: 100vh;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ background: #fffbf0;
+ font-family: system-ui, -apple-system, "Segoe UI", Roboto,sans-serif;
+ padding: 1rem;
+}
+
+.box {
+ width: 90%;
+}
+
+.card {
+ background-color: #eedeb0;
+ border: 1px solid #000000;
+ border-radius: 1.125rem;
+ padding: 1.5rem 1.25rem;
+ box-shadow: 0 6px 18px rgba(0, 0, 0, 0.04), 0 2px 4px rgba(0, 0, 0, 0.02);
+ /*max-width: 480px;*/
+ width: 90%;
+ color: #4d3e2b;
+ transition: box-shadow 0.2s, border-color 0.2s;
+ overflow-wrap: break-word;
+}
+
+.card:hover {
+ border-color: #c7b38a;
+ box-shadow: 0 10px 24px rgba(0,0,0,0.06), 0 2px 6px rgba(0,0,0,0.03);
+}
+
+/* 移动端微调 */
+@media (max-width: 480px) {
+ body {
+ padding: 0.8rem;
+ }
+
+ .card {
+ padding: 1.2rem, 1rem;
+ border-radius: 1rem;
+ border-width: 1px;
+ }
+}
+
+/* 极小屏 (宽度 < 360px) */
+@media (max-width: 360px) {
+ .card {
+ padding: 1rem 0.8rem;
+ border-radius: 0.9rem;
+ }
+}
diff --git a/static/public/dnfs.html b/static/public/dnfs.html
index c720319..09bfc29 100644
--- a/static/public/dnfs.html
+++ b/static/public/dnfs.html
@@ -5,66 +5,37 @@
DNFS · 树状笔记
-
+
-
-
- title
+
+
+
+ title
-
-
- 发布时间:
2026-1-1
+
+
+ 发布时间:2026-1-1
+
+
+ 浏览:999
+ 点赞:999
+ 分享:999
+
+
hello
+
+
+
+
节点操作
+
+
+
+
+
+
+
+
-
- 浏览:999
- 点赞:999
- 分享:999
-
-
-
-
hello
-
-
-
其他推荐
-
-
-
-
节点操作
-
-
-
-
-
-
-
-
-