From 25b72bad5dd867cde6fac4a57e54cfb4bb781bb6 Mon Sep 17 00:00:00 2001 From: wangchuanli Date: Fri, 21 Aug 2026 16:45:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(run):=20=E5=A2=9E=E5=BC=BA=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E5=BA=93=E5=88=9D=E5=A7=8B=E5=8C=96=E4=B8=8E=E5=AE=89?= =?UTF-8?q?=E5=85=A8=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 从环境变量读取密钥,未设置时随机生成 - 自动初始化数据库并显式使用 UTF-8 读取 schema - 移除默认管理员账号,更新页面署名与链接 - 新增 .gitignore、LICENSE 和 README --- .gitignore | 30 +++++++++++ LICENSE | 21 ++++++++ README.md | 102 +++++++++++++++++++++++++++++++++++++ run.py | 22 ++++++-- schema.sql | 5 +- templates/base/base.html | 6 +-- templates/base/footer.html | 13 ++--- 7 files changed, 180 insertions(+), 19 deletions(-) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..6b133c9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,30 @@ +# 数据库文件(含本地数据,不提交) +*.db +*.sqlite +*.sqlite3 + +# Python +__pycache__/ +*.py[cod] +*.egg-info/ +.Python +venv/ +.venv/ +env/ + +# 环境变量 / 密钥 +.env +.env.* + +# 运行时 / 日志 +*.log +.pyc + +# 操作系统 +.DS_Store +Thumbs.db + +# 编辑器 +.idea/ +.vscode/ +*.swp diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..e6db1e3 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 wali-Navi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..8df0bd2 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# 瓦力导航 · wali-Navi + +一个基于 Flask 的轻量级网址导航站,支持用户自定义收藏、管理员维护公共导航库、访问统计等功能。数据使用 SQLite 存储,开箱即用,可一键部署到 Docker。 + +## 功能特性 + +- 🔖 **公共导航库**:管理员可维护分类导航(搜索类 / 快捷方式类) +- 👤 **用户系统**:支持注册、登录、退出;普通用户可自定义个人收藏 +- 🎨 **自定义收藏**:用户可增删改个人搜索与快捷导航,支持图标、颜色、标签、分组 +- 📊 **访问统计**:记录每日访问量与在线人数,提供数据分析页面 +- 🔍 **多引擎搜索**:可配置多个搜索引擎 +- 🗺️ **自动 Sitemap**:自动生成 `sitemap.xml` 便于 SEO +- 🐳 **Docker 支持**:提供 `Dockerfile` 与 `docker-compose.yml` 一键部署 + +## 技术栈 + +- 后端:Python 3.9 + Flask 2.2 +- 缓存:Flask-Caching(SimpleCache) +- 服务器:gevent WSGI +- 前端:Fomantic-UI(Semantic UI)、jQuery +- 数据库:SQLite + +## 目录结构 + +``` +navi/ +├── run.py # 应用主入口 +├── collect.py # 导航数据采集脚本(参考) +├── schema.sql # 数据库表结构 +├── site.txt # 初始导航数据(CSV 格式) +├── requirements.txt # Python 依赖 +├── Dockerfile # 基于 python:3.9-slim 的镜像 +├── Dockerfile-ubuntu # 基于 Ubuntu 的镜像(备选) +├── docker-compose.yml # 编排文件 +├── static/ # 静态资源(CSS/JS/图片) +└── templates/ # Jinja2 模板 +``` + +## 快速开始 + +### 本地运行 + +1. 安装依赖: + + ```bash + pip install -r requirements.txt + ``` + +2. 配置环境变量(可选): + + | 变量名 | 说明 | 默认值 | + | --- | --- | --- | + | `NAVI_SECRET_KEY` | Flask 会话签名密钥,**生产环境务必设置** | 未设置时随机生成(重启失效) | + | `NAVI_SITE_URL` | 站点域名,用于生成 sitemap | 空(相对路径) | + + ```bash + export NAVI_SECRET_KEY="your-strong-secret-key" + export NAVI_SITE_URL="https://your-domain.com" + ``` + +3. 启动应用: + + ```bash + python run.py + ``` + + 首次运行会自动按 `schema.sql` 创建数据库与表结构(生成空的 `navi.db`)。 + +4. 访问 `http://localhost:18100`。 + +> 默认未内置管理员账号。如需创建管理员,可在数据库生成后执行: +> ```sql +> insert into user (username, password, status, type) values ('admin', 'your-strong-password', 1, 1); +> ``` +> 其中 `type=1` 表示管理员。 + +### Docker 部署 + +```bash +docker compose up -d --build +``` + +容器映射端口 `18100`,数据库 `navi.db` 通过卷挂载持久化。 + +### 初始化导航数据 + +`site.txt` 为 CSV 格式的初始导航数据,可参考 `collect.py` 中的逻辑将其导入 `library` 表。 + +## 配置说明 + +- 应用默认监听 `0.0.0.0:18100`,可在 `run.py` 末尾的 `app.run(...)` 修改。 +- 缓存默认超时 300 秒,访问统计缓存 30 秒,可在 `run.py` 中调整。 + +## 安全建议 + +- **务必设置 `NAVI_SECRET_KEY` 环境变量**,否则会话可被伪造。 +- 生产环境请关闭 Flask 的 `debug` 模式,并使用 gevent 等生产级 WSGI 服务器(代码中已预留 `WSGIServer` 用法)。 +- 默认管理员密码请替换为强密码。 + +## 开源协议 + +本项目基于 [MIT License](./LICENSE) 开源。 diff --git a/run.py b/run.py index f22009b..f0ddd5a 100644 --- a/run.py +++ b/run.py @@ -1,11 +1,14 @@ import datetime,time +import os import sqlite3 from gevent.pywsgi import WSGIServer from flask import Flask, abort, render_template, g, escape, request, make_response, session, redirect, url_for from flask_caching import Cache app = Flask(__name__) -app.secret_key = b'f98d5992f84753d9004ef6b86f8dc603e105d6f201b3a7ac0e0d6d674e3b71a3' +# 从环境变量读取密钥,未设置时生成临时随机密钥(重启后失效,生产环境请务必设置) +import os +app.secret_key = os.environ.get('NAVI_SECRET_KEY') or os.urandom(24) # ===========db DATABASE = './navi.db' cache = Cache(config={"DEBUG": True,'CACHE_TYPE': 'SimpleCache',"CACHE_DEFAULT_TIMEOUT": 300}) @@ -29,12 +32,22 @@ def close_connection(exception): def init_db(): with app.app_context(): db = get_db() - with app.open_resource('./schema.sql', mode='r') as f: + # 显式以 utf-8 读取,避免 Windows(GBK) 下因中文注释解码失败 + with app.open_resource('./schema.sql', mode='r', encoding='utf-8') as f: db.cursor().executescript(f.read()) db.commit() -# init_db() +def ensure_db(): + """确保数据库文件及表结构存在,首次运行自动按 schema.sql 初始化。""" + if not os.path.exists(DATABASE): + print("数据库不存在,正在初始化:%s" % DATABASE) + init_db() + + +# 启动时检查并初始化数据库 +ensure_db() +# init_db() # 如需重置数据库结构可手动调用 def query_db(query, args=(), one=False): cur = get_db().execute(query, args) @@ -385,10 +398,11 @@ def sitemap(): pages = [] ten_days_ago = (datetime.datetime.now() - datetime.timedelta(days=7)).date().isoformat() # static pages + site_url = os.environ.get('NAVI_SITE_URL', '').rstrip('/') for rule in app.url_map.iter_rules(): if "GET" in rule.methods and len(rule.arguments) == 0: pages.append( - ["https://nav.iwali.top" + str(rule.rule), ten_days_ago] + [site_url + str(rule.rule), ten_days_ago] ) sitemap_xml = render_template('sitemap_template.xml', pages=pages) response = make_response(sitemap_xml) diff --git a/schema.sql b/schema.sql index ce3e1b9..ca551f5 100644 --- a/schema.sql +++ b/schema.sql @@ -8,9 +8,8 @@ CREATE TABLE user type INTEGER not null default 0 ); -insert into user (username, password,status,type) -values ('admin', 'admin', 1, 1), - ('wangcl', 'wangcl', 1, 0); +-- 默认管理员账号请自行通过初始化脚本创建,例如: +-- insert into user (username, password, status, type) values ('admin', '请修改为强密码', 1, 1); DROP TABLE IF EXISTS search; CREATE TABLE search diff --git a/templates/base/base.html b/templates/base/base.html index 574159d..a496b07 100644 --- a/templates/base/base.html +++ b/templates/base/base.html @@ -10,12 +10,12 @@ 瓦力导航 · wali-Navi | A Navigation Website for wali - + - - + + diff --git a/templates/base/footer.html b/templates/base/footer.html index 16a719d..429a3b8 100644 --- a/templates/base/footer.html +++ b/templates/base/footer.html @@ -2,27 +2,22 @@
-

站群

+

友情链接

About

瓦力导航 · wali-Navi